net_server: initial replicant version.

* Still picture-less and thus ugly.
 * It provides updated information on what the net_server is doing in terms of interface configuration.
 * It is also able to show simplistic address information for configured interfaces.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20523 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-04-03 05:38:45 +00:00
parent ed07b9c7e3
commit 37c50abfaf
7 changed files with 479 additions and 13 deletions
+7 -3
View File
@@ -40,6 +40,11 @@ AutoconfigLooper::~AutoconfigLooper()
void
AutoconfigLooper::_ReadyToRun()
{
BMessage interface(kMsgConfigureInterface);
interface.AddString("device", fDevice.String());
interface.AddInt32("net:status", kStatusPreparing);
fTarget.SendMessage(&interface);
// start with DHCP
DHCPClient* client = new DHCPClient(fTarget, fDevice.String());
@@ -57,8 +62,7 @@ AutoconfigLooper::_ReadyToRun()
// TODO: have a look at zeroconf
// TODO: this could also be done add-on based
BMessage interface;
interface.AddString("device", fDevice.String());
interface.ReplaceInt32("net:status", kStatusLinkNoConfig);
uint8 mac[6];
uint8 last = 56;
@@ -80,7 +84,7 @@ AutoconfigLooper::_ReadyToRun()
address.AddString("gateway", "192.168.0.254");
interface.AddMessage("address", &address);
fTarget.SendMessage(kMsgConfigureInterface, &interface);
fTarget.SendMessage(&interface);
}
+1
View File
@@ -474,6 +474,7 @@ DHCPClient::_Negotiate(dhcp_state state)
fConfiguration.MakeEmpty();
fConfiguration.AddString("device", fDevice.String());
fConfiguration.AddInt32("net:status", kStatusConnected);
BMessage address;
address.AddString("family", "inet");
+1
View File
@@ -14,6 +14,7 @@ Server net_server :
AutoconfigLooper.cpp
DHCPClient.cpp
Services.cpp
StatusReplicant.cpp
: be libnetwork.so $(TARGET_LIBSTDC++)
# for PPP
+129 -10
View File
@@ -11,12 +11,15 @@
#include "NetServer.h"
#include "Services.h"
#include "Settings.h"
#include "StatusReplicant.h"
#include <Alert.h>
#include <Deskbar.h>
#include <Directory.h>
#include <Entry.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <Roster.h>
#include <Server.h>
#include <TextView.h>
@@ -36,7 +39,12 @@
#include <unistd.h>
const char *kSignature = "application/x-vnd.haiku-net_server";
static const char *kDeskbarSignature = "application/x-vnd.Be-TSKB";
typedef std::map<std::string, BLooper*> LooperMap;
typedef std::map<std::string, int> StatusMap;
class NetServer : public BServer {
@@ -61,10 +69,15 @@ class NetServer : public BServer {
void _ConfigureInterfaces(int socket, BMessage* _missingDevice = NULL);
void _BringUpInterfaces();
void _StartServices();
status_t _AddStatusReplicant(bool force);
void _UpdateDeviceStatus(const char *device, int status);
void _UpdateReplicantStatus();
Settings fSettings;
LooperMap fDeviceMap;
StatusMap fStatusMap;
BMessenger fServices;
BMessenger fStatusMessenger;
};
@@ -236,7 +249,7 @@ get_mac_address(const char* device, uint8* address)
NetServer::NetServer(status_t& error)
: BServer("application/x-vnd.haiku-net_server", false, &error)
: BServer(kSignature, false, &error)
{
}
@@ -266,6 +279,13 @@ NetServer::ReadyToRun()
fSettings.StartMonitoring(this);
_BringUpInterfaces();
_StartServices();
// we have to wait for Deskbar to show up before
// adding the status replicant
be_roster->StartWatching(BMessenger(this), B_REQUEST_LAUNCHED);
// but possibly the Deskbar is already running
// so add immediatly
_AddStatusReplicant(true);
}
@@ -305,18 +325,49 @@ NetServer::MessageReceived(BMessage* message)
break;
}
// we need a socket to talk to the networking stack
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0)
break;
status_t status = B_OK;
if (message->GetInfo("address", NULL) != B_NAME_NOT_FOUND) {
// we need a socket to talk to the networking stack
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0)
break;
status_t status = _ConfigureInterface(socket, *message, true);
status = _ConfigureInterface(socket, *message, true);
BMessage reply(B_REPLY);
reply.AddInt32("status", status);
message->SendReply(&reply);
BMessage reply(B_REPLY);
reply.AddInt32("status", status);
message->SendReply(&reply);
close(socket);
close(socket);
}
if (status == B_OK) {
const char *device;
int32 net_status;
if (message->FindInt32("net:status", &net_status) == B_OK &&
message->FindString("device", &device) == B_OK) {
_UpdateDeviceStatus(device, net_status);
}
}
break;
}
case B_SOME_APP_LAUNCHED:
{
// check if Deskbar was launched
const char *signature;
if (message->FindString("be:signature", &signature) == B_OK) {
if (strcmp(signature, kDeskbarSignature) == 0)
_AddStatusReplicant(true);
}
break;
}
case kRegisterStatusReplicant:
{
message->FindMessenger("messenger", &fStatusMessenger);
_UpdateReplicantStatus();
break;
}
@@ -732,6 +783,13 @@ NetServer::_QuitLooperForDevice(const char* device)
iterator->second->Quit();
fDeviceMap.erase(iterator);
StatusMap::iterator it = fStatusMap.find(device);
if (it != fStatusMap.end()) {
fStatusMap.erase(it);
_UpdateReplicantStatus();
}
return true;
}
@@ -877,6 +935,67 @@ NetServer::_StartServices()
}
status_t
NetServer::_AddStatusReplicant(bool force)
{
BDeskbar deskbar;
status_t status;
if (deskbar.HasItem(kStatusReplicant)) {
if (force) {
status = deskbar.RemoveItem(kStatusReplicant);
if (status != B_OK)
return status;
} else {
return B_OK;
}
}
StatusReplicant *replicant = new StatusReplicant();
status = deskbar.AddItem(replicant);
delete replicant;
return status;
}
void
NetServer::_UpdateDeviceStatus(const char *device, int status)
{
StatusMap::iterator it = fStatusMap.find(device);
if (it != fStatusMap.end() && it->second == status)
return;
fStatusMap[device] = status;
_UpdateReplicantStatus();
}
void
NetServer::_UpdateReplicantStatus()
{
if (!fStatusMessenger.IsValid())
return;
int prevaling = kStatusUnknown;
BMessage message(kStatusUpdate);
for (StatusMap::iterator it = fStatusMap.begin();
it != fStatusMap.end(); ++it) {
if (it->second > prevaling)
prevaling = it->second;
message.AddString("intf:name", it->first.c_str());
message.AddInt32("intf:status", it->second);
}
message.AddInt32("net:status", prevaling);
fStatusMessenger.SendMessage(&message);
}
// #pragma mark -
+11
View File
@@ -15,6 +15,17 @@
static const uint32 kMsgConfigureInterface = 'COif';
extern const char *kSignature;
enum {
kStatusUnknown = 0,
kStatusNoLink,
kStatusLinkNoConfig,
kStatusConnected,
kStatusPreparing,
kStatusCount
};
extern bool get_family_index(const char* name, int32& familyIndex);
extern int family_at_index(int32 index);
+278
View File
@@ -0,0 +1,278 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, hugosantos@gmail.com
*/
#include "NetServer.h"
#include "StatusReplicant.h"
#include <Alert.h>
#include <MenuItem.h>
#include <Message.h>
#include <Messenger.h>
#include <TextView.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/sockio.h>
const char *kStatusReplicant = "NetStatusView";
static const uint32 kShowConfiguration = 'shcf';
static const uint8 kStatusColors[kStatusCount][3] = {
{ 0, 0, 0 }, // Unknown
{ 255, 0, 0 }, // NoLink
{ 0, 0, 255 }, // LinkNoConfig
{ 0, 255, 0 }, // Connected
{ 255, 255, 0 }, // Preparing
};
struct information_entry {
const char *label;
int ioc;
};
static const information_entry kInformationEntries[] = {
{ "Address", SIOCGIFADDR },
{ "Broadcast", SIOCGIFBRDADDR },
{ "Netmask", SIOCGIFNETMASK },
{ NULL }
};
static const char *kStatusDescriptions[] = {
"Unknown",
"No Link",
"No stateful configuration",
"Ready",
"Configuring",
};
StatusReplicant::StatusReplicant()
: BView(BRect(0, 0, 15, 15), kStatusReplicant, B_FOLLOW_ALL, 0),
fPopup("", false, false)
{
}
StatusReplicant::StatusReplicant(BMessage *message)
: BView(message), fPopup("", false, false)
{
// TODO: Load status bitmaps from resources
for (int i = 0; i < kStatusCount; i++)
fBitmaps[i] = NULL;
}
StatusReplicant::~StatusReplicant()
{
}
StatusReplicant *
StatusReplicant::Instantiate(BMessage *data)
{
if (validate_instantiation(data, kStatusReplicant))
return new StatusReplicant(data);
return NULL;
}
status_t
StatusReplicant::Archive(BMessage *data, bool deep) const
{
BView::Archive(data, deep);
data->AddString("add_on", kSignature);
data->AddString("class", kStatusReplicant);
return B_OK;
}
void
StatusReplicant::AttachedToWindow()
{
BMessage message(kRegisterStatusReplicant);
message.AddMessenger("messenger", BMessenger(this));
if (BMessenger(kSignature).SendMessage(&message) != B_OK) {
// TODO: Remove myself from Deskbar
}
ChangeStatus(kStatusUnknown);
PrepareMenu(InterfaceStatusList());
}
void
StatusReplicant::MessageReceived(BMessage *message)
{
switch (message->what) {
case kStatusUpdate:
UpdateFromMessage(message);
break;
case kShowConfiguration:
ShowConfiguration(message);
break;
default:
BView::MessageReceived(message);
break;
}
}
void
StatusReplicant::MouseDown(BPoint point)
{
uint32 buttons;
BPoint where;
GetMouse(&where, &buttons, true);
where = ConvertToScreen(point);
fPopup.SetTargetForItems(this);
fPopup.Go(where, true, true);
}
void
StatusReplicant::UpdateFromMessage(BMessage *message)
{
int32 newStatus, intfStatus;
if (message->FindInt32("net:status", &newStatus) != B_OK
|| newStatus < 0 || newStatus >= kStatusCount)
return;
InterfaceStatusList status;
int index = 0;
while (message->FindInt32("intf:status", index, &intfStatus) == B_OK) {
if (intfStatus < 0 || intfStatus >= kStatusCount)
break;
const char *name;
if (message->FindString("intf:name", index, &name) != B_OK)
break;
status.push_back(InterfaceStatus(name, intfStatus));
index++;
}
ChangeStatus(newStatus);
PrepareMenu(status);
}
void
StatusReplicant::ShowConfiguration(BMessage *message)
{
const char *device;
if (message->FindString("intf:name", &device) != B_OK)
return;
int32 status;
if (message->FindInt32("intf:status", &status) != B_OK)
return;
if (status != kStatusConnected && status != kStatusLinkNoConfig)
return;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
return;
if (strlen(device) > IF_NAMESIZE)
return;
ifreq request;
memset(&request, 0, sizeof(request));
strcpy(request.ifr_name, device);
string text = device;
text += " information:\n";
size_t boldLength = text.size();
for (int i = 0; kInformationEntries[i].label; i++) {
if (ioctl(sock, kInformationEntries[i].ioc, &request,
sizeof(request)) < 0) {
close(sock);
return;
}
char address[32];
if (inet_ntop(AF_INET, &((sockaddr_in *)&request.ifr_addr)->sin_addr,
address, sizeof(address)) == NULL) {
close(sock);
return;
}
text += "\n";
text += kInformationEntries[i].label;
text += ": ";
text += address;
}
close(sock);
BAlert *info = new BAlert(device, text.c_str(), "Ok");
BTextView *view = info->TextView();
BFont font;
view->SetStylable(true);
view->GetFont(&font);
font.SetSize(12);
font.SetFace(B_BOLD_FACE);
view->SetFontAndColor(0, boldLength, &font);
info->Go(NULL);
}
void
StatusReplicant::PrepareMenu(const InterfaceStatusList &status)
{
while (fPopup.RemoveItem((int32)0));
if (status.empty()) {
fPopup.AddItem(new BMenuItem("No interfaces available.", NULL));
fPopup.ItemAt(0)->SetEnabled(false);
} else {
for (InterfaceStatusList::const_iterator i = status.begin();
i != status.end(); ++i) {
std::string label = i->first;
label += ": ";
label += kStatusDescriptions[i->second];
BMessage *message = new BMessage(kShowConfiguration);
message->AddString("intf:name", i->first.c_str());
message->AddInt32("intf:status", i->second);
BMenuItem *item = new BMenuItem(label.c_str(), message);
if (i->second != kStatusConnected &&
i->second != kStatusLinkNoConfig)
item->SetEnabled(false);
fPopup.AddItem(item);
}
}
}
void
StatusReplicant::ChangeStatus(int newStatus)
{
if (fBitmaps[newStatus]) {
SetViewColor(Parent()->ViewColor());
SetViewBitmap(fBitmaps[newStatus]);
} else {
ClearViewBitmap();
SetViewColor(kStatusColors[newStatus][0],
kStatusColors[newStatus][1],
kStatusColors[newStatus][2]);
}
Invalidate();
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, hugosantos@gmail.com
*/
#ifndef _STATUS_REPLICANT_H
#define _STATUS_REPLICANT_H
#include "NetServer.h"
#include <PopUpMenu.h>
#include <View.h>
#include <string>
#include <utility>
#include <vector>
static const uint32 kRegisterStatusReplicant = 'rnsr';
static const uint32 kStatusUpdate = 'stup';
extern const char *kStatusReplicant;
class StatusReplicant : public BView {
public:
StatusReplicant();
StatusReplicant(BMessage *);
virtual ~StatusReplicant();
static StatusReplicant *Instantiate(BMessage *);
status_t Archive(BMessage *, bool deep) const;
void AttachedToWindow();
void MessageReceived(BMessage *);
void MouseDown(BPoint point);
private:
typedef std::pair<std::string, int> InterfaceStatus;
typedef std::vector<InterfaceStatus> InterfaceStatusList;
void UpdateFromMessage(BMessage *);
void ShowConfiguration(BMessage *);
void PrepareMenu(const InterfaceStatusList &);
void ChangeStatus(int newStatus);
BPopUpMenu fPopup;
BBitmap *fBitmaps[kStatusCount];
};
#endif