* Added "stand_alone" setting to the services - this way you can use the

net_server to launch services that work like a daemon theirselves (like sshd).
  A service like this is also killed (via SIGTERM) when the netserver stops the
  service (with sshd, you have to pass the '-D' option to make this work).
* If a boolean is given without value, it now defaults to true.
* The "launch" argument now gets its arguments properly parsed, and added, too.
* Services::_Update() did accidently set fUpdate on the wrong service, causing
  services that were not changed to be stopped.
* More helpful output.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32319 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-08-13 16:22:09 +00:00
parent eab0984875
commit 5544f69de6
4 changed files with 89 additions and 27 deletions
+4
View File
@@ -80,6 +80,10 @@ struct address_family {
void (*set_port)(sockaddr* address, int32 port); void (*set_port)(sockaddr* address, int32 port);
}; };
const char* kNetServerSignature = "application/x-vnd.haiku-net_server";
// AF_INET family // AF_INET family
static bool inet_parse_address(const char* string, sockaddr* address); static bool inet_parse_address(const char* string, sockaddr* address);
static void inet_set_any_address(sockaddr* address); static void inet_set_any_address(sockaddr* address);
+2 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved. * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -14,7 +14,7 @@
#include <net/if.h> #include <net/if.h>
static const char* kNetServerSignature = "application/x-vnd.haiku-net_server"; extern const char* kNetServerSignature;
static const uint32 kMsgConfigureInterface = 'COif'; static const uint32 kMsgConfigureInterface = 'COif';
+77 -24
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -26,7 +26,7 @@
using namespace std; using namespace std;
struct service_address { struct service_address {
struct service *owner; struct service* owner;
int socket; int socket;
int family; int family;
int type; int type;
@@ -36,15 +36,18 @@ struct service_address {
bool operator==(const struct service_address& other) const; bool operator==(const struct service_address& other) const;
}; };
typedef vector<service_address> AddressList; typedef std::vector<service_address> AddressList;
typedef std::vector<std::string> StringList;
struct service { struct service {
std::string name; std::string name;
std::string launch; StringList arguments;
uid_t user; uid_t user;
gid_t group; gid_t group;
AddressList addresses; AddressList addresses;
uint32 update; uint32 update;
bool stand_alone;
pid_t process;
~service(); ~service();
bool operator!=(const struct service& other) const; bool operator!=(const struct service& other) const;
@@ -128,10 +131,18 @@ bool
service::operator==(const struct service& other) const service::operator==(const struct service& other) const
{ {
if (name != other.name if (name != other.name
|| launch != other.launch || arguments.size() != other.arguments.size()
|| addresses.size() != other.addresses.size()) || addresses.size() != other.addresses.size()
|| stand_alone != other.stand_alone)
return false; return false;
// compare arguments
for(int i = 0; i < arguments.size(); i++) {
if (arguments[i] != other.arguments[i])
return false;
}
// compare addresses // compare addresses
AddressList::const_iterator iterator = addresses.begin(); AddressList::const_iterator iterator = addresses.begin();
@@ -244,6 +255,16 @@ Services::_UpdateMinMaxSocket(int socket)
status_t status_t
Services::_StartService(struct service& service) Services::_StartService(struct service& service)
{ {
if (service.stand_alone && service.process == -1) {
status_t status = _LaunchService(service, -1);
if (status == B_OK) {
// add service
fNameMap[service.name] = &service;
service.update = fUpdate;
}
return status;
}
// create socket // create socket
bool failed = false; bool failed = false;
@@ -293,13 +314,16 @@ Services::_StartService(struct service& service)
status_t status_t
Services::_StopService(struct service& service) Services::_StopService(struct service& service)
{ {
printf("Stop service '%s'\n", service.name.c_str());
// remove service from maps // remove service from maps
{ {
ServiceNameMap::iterator iterator = fNameMap.find(service.name); ServiceNameMap::iterator iterator = fNameMap.find(service.name);
if (iterator != fNameMap.end()) if (iterator != fNameMap.end())
fNameMap.erase(iterator); fNameMap.erase(iterator);
} }
{
if (!service.stand_alone) {
AddressList::const_iterator iterator = service.addresses.begin(); AddressList::const_iterator iterator = service.addresses.begin();
for (; iterator != service.addresses.end(); iterator++) { for (; iterator != service.addresses.end(); iterator++) {
const service_address& address = *iterator; const service_address& address = *iterator;
@@ -314,6 +338,12 @@ Services::_StopService(struct service& service)
} }
} }
// Shutdown the running server, if any
if (service.process != -1) {
printf(" Sending SIGTERM to process %ld\n", service.process);
kill(-service.process, SIGTERM);
}
delete &service; delete &service;
return B_OK; return B_OK;
} }
@@ -324,9 +354,8 @@ Services::_ToService(const BMessage& message, struct service*& service)
{ {
// get mandatory fields // get mandatory fields
const char* name; const char* name;
const char* launch;
if (message.FindString("name", &name) != B_OK if (message.FindString("name", &name) != B_OK
|| message.FindString("launch", &launch) != B_OK) || !message.HasString("launch"))
return B_BAD_VALUE; return B_BAD_VALUE;
service = new (std::nothrow) ::service; service = new (std::nothrow) ::service;
@@ -334,7 +363,14 @@ Services::_ToService(const BMessage& message, struct service*& service)
return B_NO_MEMORY; return B_NO_MEMORY;
service->name = name; service->name = name;
service->launch = launch;
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->process = -1;
// TODO: user/group is currently ignored! // TODO: user/group is currently ignored!
@@ -355,7 +391,8 @@ Services::_ToService(const BMessage& message, struct service*& service)
serviceProtocol = parse_protocol(string); serviceProtocol = parse_protocol(string);
else { else {
string = "tcp"; string = "tcp";
// we set 'string' here for an eventual call to getservbyname() below // we set 'string' here for an eventual call to getservbyname()
// below
serviceProtocol = IPPROTO_TCP; serviceProtocol = IPPROTO_TCP;
} }
@@ -375,6 +412,10 @@ Services::_ToService(const BMessage& message, struct service*& service)
serviceType = type_for_protocol(serviceProtocol); serviceType = type_for_protocol(serviceProtocol);
} }
bool standAlone = false;
if (message.FindBool("stand_alone", &standAlone) == B_OK)
service->stand_alone = standAlone;
BMessage address; BMessage address;
int32 i = 0; int32 i = 0;
for (; message.FindMessage("address", i, &address) == B_OK; i++) { for (; message.FindMessage("address", i, &address) == B_OK; i++) {
@@ -464,15 +505,17 @@ Services::_Update(const BMessage& services)
ServiceNameMap::iterator iterator = fNameMap.find(name); ServiceNameMap::iterator iterator = fNameMap.find(name);
if (iterator == fNameMap.end()) { if (iterator == fNameMap.end()) {
// this service does not exist yet, start it // this service does not exist yet, start it
printf("New service %s\n", service->name.c_str());
_StartService(*service); _StartService(*service);
} else { } else {
// this service does already exist - check for any changes // this service does already exist - check for any changes
if (*service != *iterator->second) { if (*service != *iterator->second) {
printf("Restart service %s\n", service->name.c_str());
_StopService(*iterator->second); _StopService(*iterator->second);
_StartService(*service); _StartService(*service);
} else } else
service->update = fUpdate; iterator->second->update = fUpdate;
} }
} }
@@ -494,9 +537,9 @@ Services::_Update(const BMessage& services)
status_t status_t
Services::_LaunchService(struct service& service, int socket) Services::_LaunchService(struct service& service, int socket)
{ {
printf("LAUNCH: %s\n", service.launch.c_str()); printf("Launch service: %s\n", service.arguments[0].c_str());
if (fcntl(socket, F_SETFD, 0) < 0) { if (socket != -1 && fcntl(socket, F_SETFD, 0) < 0) {
// could not clear FD_CLOEXEC on socket // could not clear FD_CLOEXEC on socket
return errno; return errno;
} }
@@ -507,27 +550,37 @@ Services::_LaunchService(struct service& service, int socket)
// make sure we're in our own session, and don't accidently quit // make sure we're in our own session, and don't accidently quit
// the net_server // the net_server
// We're the child, replace standard input/output if (socket != -1) {
dup2(socket, STDIN_FILENO); // We're the child, replace standard input/output
dup2(socket, STDOUT_FILENO); dup2(socket, STDIN_FILENO);
dup2(socket, STDERR_FILENO); dup2(socket, STDOUT_FILENO);
close(socket); dup2(socket, STDERR_FILENO);
close(socket);
}
// build argument array // build argument array
const char** args = (const char**)malloc(2 * sizeof(void *)); const char** args = (const char**)malloc(
(service.arguments.size() + 1) * sizeof(char*));
if (args == NULL) if (args == NULL)
exit(1); exit(1);
args[0] = service.launch.c_str(); for (int i = 0; i < service.arguments.size(); i++) {
args[1] = NULL; args[i] = service.arguments[i].c_str();
if (execv(service.launch.c_str(), (char* const*)args) < 0) }
args[service.arguments.size()] = NULL;
if (execv(service.arguments[0].c_str(), (char* const*)args) < 0)
exit(1); exit(1);
// we'll never trespass here // we'll never trespass here
} else { } else {
// the server does not need the socket anymore // the server does not need the socket anymore
close(socket); if (socket != -1)
close(socket);
if (service.stand_alone)
service.process = child;
} }
// TODO: make sure child started successfully... // TODO: make sure child started successfully...
+6 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved. * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -75,6 +75,7 @@ const static settings_template kServiceTemplate[] = {
{B_STRING_TYPE, "type", NULL}, {B_STRING_TYPE, "type", NULL},
{B_STRING_TYPE, "protocol", NULL}, {B_STRING_TYPE, "protocol", NULL},
{B_INT32_TYPE, "port", NULL}, {B_INT32_TYPE, "port", NULL},
{B_BOOL_TYPE, "stand_alone", NULL},
{0, NULL, NULL} {0, NULL, NULL}
}; };
@@ -177,6 +178,10 @@ Settings::_AddParameter(const driver_parameter& parameter, const char* name,
break; break;
} }
} }
if (type == B_BOOL_TYPE && parameter.value_count == 0) {
// boolean parameters are always true
message.AddBool(name, true);
}
return B_OK; return B_OK;
} }