Started writing the new networking server. Right now, it'll configure the

networking stack according to some settings file. Doesn't do anything beyond
that yet, though.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19082 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-10-19 10:45:11 +00:00
parent 3080cd989b
commit 919c897b98
5 changed files with 605 additions and 75 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ BEOS_SYSTEM_LIB = libbe.so $(HAIKU_LIBSTDC++) libmedia.so libtracker.so
libdevice.so libgame.so libscreensaver.so libroot.so $(X86_ONLY)libGL.so
libfluidsynth.so libqoca.so
;
BEOS_SYSTEM_SERVERS = registrar debug_server syslog_daemon media_server
BEOS_SYSTEM_SERVERS = registrar debug_server syslog_daemon media_server net_server
media_addon_server input_server app_server fake_app_server midi_server print_server
;
+1 -1
View File
@@ -7,7 +7,7 @@ SubInclude HAIKU_TOP src servers mail ;
SubInclude HAIKU_TOP src servers media ;
SubInclude HAIKU_TOP src servers media_addon ;
SubInclude HAIKU_TOP src servers midi ;
# SubInclude HAIKU_TOP src servers net ;
SubInclude HAIKU_TOP src servers net ;
SubInclude HAIKU_TOP src servers power ;
SubInclude HAIKU_TOP src servers print ;
SubInclude HAIKU_TOP src servers registrar ;
+8 -16
View File
@@ -1,29 +1,21 @@
SubDir HAIKU_TOP src servers net ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders net ;
# additonal headers for built-in add-ons:
UsePrivateHeaders net ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libppp headers ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net DialUpPreflet ] ;
#UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libppp headers ] ;
#UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ;
#UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net DialUpPreflet ] ;
Server net_server :
NetServer.cpp
# utils
SimpleMessageFilter.cpp
# built-in add-ons
PPPServer.cpp
;
LinkAgainst net_server :
be
libsocket.so
libbind.so
be
libnetwork.so
# for PPP
libppp.a
#libppp.a
;
+595 -44
View File
@@ -1,76 +1,627 @@
/*
* Copyright 2004-2005, Waldemar Kornewald <[email protected]>
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#include "NetServer.h"
#include <Application.h>
#include <Alert.h>
#include <Application.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <TextView.h>
#include <driver_settings.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const char *kSignature = NET_SERVER_SIGNATURE;
class NetServerApplication : public BApplication {
public:
NetServerApplication();
virtual void AboutRequested();
virtual void ReadyToRun();
// loads add-ons
virtual bool QuitRequested();
// unloads add-ons
struct settings_template {
uint32 type;
const char* name;
const settings_template* sub_template;
};
int main()
class Settings {
public:
Settings();
~Settings();
status_t GetNextInterface(uint32& cookie, BMessage& interface);
private:
status_t _Load();
status_t _GetPath(const char* name, BPath& path);
const settings_template* _FindSettingsTemplate(const settings_template* settingsTemplate,
const char* name);
status_t _ConvertFromDriverParameter(const driver_parameter& parameter,
const settings_template* settingsTemplate, BMessage& message);
status_t _ConvertFromDriverSettings(const driver_settings& settings,
const settings_template* settingsTemplate, BMessage& message);
status_t _ConvertFromDriverSettings(const char* path,
const settings_template* settingsTemplate, BMessage& message);
BMessage fInterfaces;
bool fUpdated;
};
class NetServer : public BApplication {
public:
NetServer();
virtual void AboutRequested();
virtual void ReadyToRun();
private:
bool _PrepareRequest(ifreq& request, const char* name);
status_t _ConfigureInterface(int socket, BMessage& interface);
void _BringUpInterfaces();
Settings fSettings;
};
struct address_family {
int family;
const char* name;
const char* identifiers[4];
bool (*parse_address)(const char* string, sockaddr* _address);
};
// AF_INET family
static bool inet_parse_address(const char* string, sockaddr* address);
static const address_family kFamilies[] = {
{
AF_INET,
"inet",
{"AF_INET", "inet", "ipv4", NULL},
inet_parse_address,
inet_print_address
},
{ -1, NULL, {NULL}, NULL, NULL }
};
const static settings_template kInterfaceAddressTemplate[] = {
{B_STRING_TYPE, "family", NULL},
{B_STRING_TYPE, "address", NULL},
{B_STRING_TYPE, "mask", NULL},
{B_STRING_TYPE, "peer", NULL},
{B_STRING_TYPE, "broadcast", NULL},
{0, NULL, NULL}
};
const static settings_template kInterfaceDeviceTemplate[] = {
{B_STRING_TYPE, "device", NULL},
{B_MESSAGE_TYPE, "address", kInterfaceAddressTemplate},
{B_INT32_TYPE, "flags", NULL},
{B_INT32_TYPE, "metric", NULL},
{B_INT32_TYPE, "mtu", NULL},
{0, NULL, NULL}
};
const static settings_template kInterfaceTemplate[] = {
{B_MESSAGE_TYPE, "interface", kInterfaceDeviceTemplate},
{0, NULL, NULL}
};
static bool
inet_parse_address(const char* string, sockaddr* _address)
{
new NetServerApplication();
be_app->Run();
delete be_app;
return 0;
in_addr inetAddress;
if (inet_aton(string, &inetAddress) != 1)
return false;
sockaddr_in& address = *(sockaddr_in *)_address;
address.sin_family = AF_INET;
address.sin_len = sizeof(struct sockaddr_in);
address.sin_port = 0;
address.sin_addr = inetAddress;
memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
return true;
}
NetServerApplication::NetServerApplication()
: BApplication(kSignature)
// #pragma mark -
static bool
get_family_index(const char* name, int32& familyIndex)
{
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
if (!strcmp(name, kFamilies[i].identifiers[j])) {
// found a match
familyIndex = i;
return true;
}
}
}
// defaults to AF_INET
familyIndex = 0;
return false;
}
static bool
parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
{
if (argument == NULL)
return false;
return kFamilies[familyIndex].parse_address(argument, &address);
}
// #pragma mark -
Settings::Settings()
:
fUpdated(false)
{
_Load();
}
Settings::~Settings()
{
// only save the settings if something has changed
if (!fUpdated)
return;
#if 0
BFile file;
if (_Open(&file, B_CREATE_FILE | B_WRITE_ONLY) != B_OK)
return;
#endif
}
status_t
Settings::_GetPath(const char* name, BPath& path)
{
if (find_directory(B_COMMON_SETTINGS_DIRECTORY, &path) != B_OK)
return B_ERROR;
path.Append("network");
path.Append(name);
return B_OK;
}
const settings_template*
Settings::_FindSettingsTemplate(const settings_template* settingsTemplate,
const char* name)
{
while (settingsTemplate->name != NULL) {
if (!strcmp(name, settingsTemplate->name))
return settingsTemplate;
settingsTemplate++;
}
return NULL;
}
status_t
Settings::_ConvertFromDriverParameter(const driver_parameter& parameter,
const settings_template* settingsTemplate, BMessage& message)
{
settingsTemplate = _FindSettingsTemplate(settingsTemplate, parameter.name);
if (settingsTemplate == NULL) {
fprintf(stderr, "unknown parameter %s\n", parameter.name);
return B_BAD_VALUE;
}
for (int32 i = 0; i < parameter.value_count; i++) {
switch (settingsTemplate->type) {
case B_STRING_TYPE:
message.AddString(parameter.name, parameter.values[i]);
break;
case B_INT32_TYPE:
message.AddInt32(parameter.name, atoi(parameter.values[i]));
break;
case B_BOOL_TYPE:
if (!strcasecmp(parameter.values[i], "true")
|| !strcasecmp(parameter.values[i], "on")
|| !strcasecmp(parameter.values[i], "enabled")
|| !strcasecmp(parameter.values[i], "1"))
message.AddBool(parameter.name, true);
else
message.AddBool(parameter.name, false);
break;
}
}
if (settingsTemplate->type == B_MESSAGE_TYPE && parameter.parameter_count > 0) {
status_t status = B_OK;
BMessage subMessage;
for (int32 j = 0; j < parameter.parameter_count; j++) {
status = _ConvertFromDriverParameter(parameter.parameters[j],
settingsTemplate->sub_template, subMessage);
if (status < B_OK)
break;
}
if (status == B_OK)
message.AddMessage(parameter.name, &subMessage);
}
return B_OK;
}
status_t
Settings::_ConvertFromDriverSettings(const driver_settings& settings,
const settings_template* settingsTemplate, BMessage& message)
{
for (int32 i = 0; i < settings.parameter_count; i++) {
status_t status = _ConvertFromDriverParameter(settings.parameters[i],
settingsTemplate, message);
if (status == B_BAD_VALUE) {
// ignore unknown entries
continue;
}
if (status < B_OK)
return status;
}
return B_OK;
}
status_t
Settings::_ConvertFromDriverSettings(const char* name,
const settings_template* settingsTemplate, BMessage& message)
{
BPath path;
status_t status = _GetPath("interfaces", path);
if (status < B_OK)
return status;
void* handle = load_driver_settings(path.Path());
if (handle == NULL)
return B_ENTRY_NOT_FOUND;
const driver_settings* settings = get_driver_settings(handle);
if (settings != NULL)
status = _ConvertFromDriverSettings(*settings, settingsTemplate, message);
unload_driver_settings(handle);
return status;
}
status_t
Settings::_Load()
{
return _ConvertFromDriverSettings("interfaces", kInterfaceTemplate, fInterfaces);
}
status_t
Settings::GetNextInterface(uint32& cookie, BMessage& interface)
{
status_t status = fInterfaces.FindMessage("interface", cookie, &interface);
if (status < B_OK)
return status;
cookie++;
return B_OK;
}
// #pragma mark -
NetServer::NetServer()
: BApplication("application/x-vnd.haiku-net_server")
{
}
void
NetServerApplication::AboutRequested()
NetServer::AboutRequested()
{
// the alert should not block because we might get _very_ important messages
(new BAlert("About...",
"OpenBeOS net_server\n\n"
"The net_server manages all userland tasks that "
"cannot be handled by the netstack.",
"Uhm...Cool?", NULL, NULL, B_WIDTH_AS_USUAL,
B_INFO_ALERT))->Go(NULL);
BAlert *alert = new BAlert("about", "Networking Server\n"
"\tCopyright " B_UTF8_COPYRIGHT "2006, Haiku.\n", "Ok");
BTextView *view = alert->TextView();
BFont font;
view->SetStylable(true);
view->GetFont(&font);
font.SetSize(18);
font.SetFace(B_BOLD_FACE);
view->SetFontAndColor(0, 17, &font);
alert->Go(NULL);
}
void
NetServerApplication::ReadyToRun()
NetServer::ReadyToRun()
{
// load integrated add-ons
// TODO: load add-on binaries
_BringUpInterfaces();
}
bool
NetServerApplication::QuitRequested()
NetServer::_PrepareRequest(ifreq& request, const char* name)
{
// unload integrated add-ons
// TODO: unload add-on binaries
if (strlen(name) > IF_NAMESIZE) {
fprintf(stderr, "%s: interface name \"%s\" is too long.\n", Name(), name);
return false;
}
strcpy(request.ifr_name, name);
return true;
}
status_t
NetServer::_ConfigureInterface(int socket, BMessage& interface)
{
const char *device;
if (interface.FindString("device", &device) != B_OK)
return B_BAD_VALUE;
ifreq request;
if (!_PrepareRequest(request, device))
return B_ERROR;
int32 flags;
if (interface.FindInt32("flags", &flags) < B_OK)
flags = IFF_UP;
int32 mtu;
if (interface.FindInt32("mtu", &mtu) < B_OK)
mtu = -1;
int32 metric;
if (interface.FindInt32("metric", &metric) < B_OK)
metric = -1;
BMessage addressMessage;
for (int32 index = 0; interface.FindMessage("address", index, &addressMessage) == B_OK;
index++) {
const char* family;
if (addressMessage.FindString("family", &family) < B_OK)
continue;
int32 familyIndex;
if (!get_family_index(family, familyIndex)) {
// we don't support this family
continue;
}
int familySocket = socket;
if (kFamilies[familyIndex].family != AF_INET)
socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0);
if (socket < 0) {
// the family is not available in this environment
continue;
}
uint32 interfaceIndex = 0;
if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
interfaceIndex = request.ifr_index;
if (interfaceIndex == 0) {
// we need to create the interface first
request.ifr_parameter.base_name[0] = '\0';
request.ifr_parameter.device[0] = '\0';
request.ifr_parameter.sub_type = 0;
// the default device is okay for us
if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
fprintf(stderr, "%s: Could not add interface: %s\n", Name(),
strerror(errno));
return errno;
}
}
// retrieve addresses
bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false;
struct sockaddr address, mask, peer, broadcast;
const char* string;
if (addressMessage.FindString("address", &string) == B_OK
&& parse_address(familyIndex, string, address)) {
hasAddress = true;
if (addressMessage.FindString("mask", &string) == B_OK
&& parse_address(familyIndex, string, mask))
hasMask = true;
}
if (addressMessage.FindString("peer", &string) == B_OK
&& parse_address(familyIndex, string, peer))
hasPeer = true;
if (addressMessage.FindString("broadcast", &string) == B_OK
&& parse_address(familyIndex, string, broadcast))
hasBroadcast = true;
// set addresses
if (hasAddress) {
memcpy(&request.ifr_addr, &address, address.sa_len);
if (ioctl(familySocket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting address failed: %s\n", Name(), strerror(errno));
continue;
}
}
if (ioctl(familySocket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Getting flags failed: %s\n", Name(), strerror(errno));
continue;
}
int32 currentFlags = request.ifr_flags;
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
sockaddr_in *netmask = (sockaddr_in *)&mask;
netmask->sin_len = sizeof(sockaddr_in);
netmask->sin_family = AF_INET;
// choose default netmask depending on the class of the address
in_addr_t net = ((sockaddr_in *)&address)->sin_addr.s_addr;
if (IN_CLASSA(net)
|| (ntohl(net) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
// class A, or loopback
netmask->sin_addr.s_addr = IN_CLASSA_NET;
} if (IN_CLASSB(net)) {
// class B
netmask->sin_addr.s_addr = IN_CLASSB_NET;
} else {
// class C and rest
netmask->sin_addr.s_addr = IN_CLASSC_NET;
}
hasMask = true;
}
if (hasMask) {
memcpy(&request.ifr_mask, &mask, mask.sa_len);
if (ioctl(familySocket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting subnet mask failed: %s\n", Name(), strerror(errno));
continue;
}
}
if (!hasBroadcast && hasAddress && (currentFlags & IFF_BROADCAST)
&& kFamilies[familyIndex].family == AF_INET
&& ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0
&& request.ifr_mask.sa_family == AF_UNSPEC) {
// generate standard broadcast address if it doesn't have one yet
sockaddr_in *broadcastAddr = (sockaddr_in *)&broadcast;
uint32 maskValue = ((sockaddr_in *)&mask)->sin_addr.s_addr;
uint32 broadcastValue = ((sockaddr_in *)&address)->sin_addr.s_addr;
broadcastValue = (broadcastValue & maskValue) | ~maskValue;
broadcastAddr->sin_len = sizeof(sockaddr_in);
broadcastAddr->sin_family = AF_INET;
broadcastAddr->sin_addr.s_addr = broadcastValue;
hasBroadcast = true;
}
if (hasBroadcast) {
memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
if (ioctl(familySocket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting broadcast address failed: %s\n", Name(), strerror(errno));
continue;
}
}
if (hasPeer) {
memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
if (ioctl(familySocket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting peer address failed: %s\n", Name(), strerror(errno));
continue;
}
}
// set flags
if (flags != 0) {
request.ifr_flags = currentFlags | flags;
if (ioctl(familySocket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0)
fprintf(stderr, "%s: Setting flags failed: %s\n", Name(), strerror(errno));
}
// set options
if (mtu != -1) {
request.ifr_mtu = mtu;
if (ioctl(familySocket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0)
fprintf(stderr, "%s: Setting MTU failed: %s\n", Name(), strerror(errno));
}
if (metric != -1) {
request.ifr_metric = metric;
if (ioctl(familySocket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0)
fprintf(stderr, "%s: Setting metric failed: %s\n", Name(), strerror(errno));
}
}
return B_OK;
}
void
NetServer::_BringUpInterfaces()
{
// we need a socket to talk to the networking stack
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0) {
fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n",
Name());
Quit();
return;
}
// First, we look into the settings, and try to bring everything up from there
BMessage interface;
uint32 cookie = 0;
while (fSettings.GetNextInterface(cookie, interface) == B_OK) {
const char *device;
if (interface.FindString("device", &device) != B_OK)
continue;
if (!strncmp(device, "/dev/net/", 9)) {
// it's a kernel device, check if it's present
BEntry entry(device);
if (!entry.Exists())
continue;
}
// try to bring the interface up
status_t status = _ConfigureInterface(socket, interface);
if (status < B_OK)
continue;
}
}
// #pragma mark -
int
main()
{
NetServer app;
app.Run();
return 0;
}
-13
View File
@@ -1,13 +0,0 @@
/*
* Copyright 2004, Waldemar Kornewald <[email protected]>
* Distributed under the terms of the MIT License.
*/
#ifndef _NET_SERVER__H
#define _NET_SERVER__H
#define NET_SERVER_SIGNATURE "application/x-obos.net_server"
#endif