Actually launching services should work now:
* ServiceSocketMap now maps directly to service_address objects which now have gotten a pointer to their owner. * now uses listen(), and accept() for SOCK_STREAM sockets * fMinSocket could be wrong. * use FD_CLOEXEC on all sockets, and the communication pipe. * removed unused service::type and service::protocol. * if no family is specified, we now default to AF_INET. * uses fork()/exec() to actually spawn the servers to not clobber the net_server's input/output streams. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19663 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
4684dfec2d
commit
c30e35eb9b
@ -17,12 +17,14 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
struct service_address {
|
struct service_address {
|
||||||
|
struct service *owner;
|
||||||
int socket;
|
int socket;
|
||||||
int family;
|
int family;
|
||||||
int type;
|
int type;
|
||||||
@ -35,8 +37,6 @@ typedef vector<service_address> AddressList;
|
|||||||
struct service {
|
struct service {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string launch;
|
std::string launch;
|
||||||
int type;
|
|
||||||
int protocol;
|
|
||||||
uid_t user;
|
uid_t user;
|
||||||
gid_t group;
|
gid_t group;
|
||||||
AddressList addresses;
|
AddressList addresses;
|
||||||
@ -109,9 +109,7 @@ bool
|
|||||||
service::operator==(const struct service& other)
|
service::operator==(const struct service& other)
|
||||||
{
|
{
|
||||||
if (name != other.name
|
if (name != other.name
|
||||||
|| launch != other.launch
|
|| launch != other.launch)
|
||||||
|| type != other.type
|
|
||||||
|| protocol != other.protocol)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: compare addresses!
|
// TODO: compare addresses!
|
||||||
@ -137,15 +135,18 @@ Services::Services(const BMessage& services)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fListener = spawn_thread(_Listener, "services listener", B_NORMAL_PRIORITY, this);
|
fcntl(fReadPipe, F_SETFD, FD_CLOEXEC);
|
||||||
if (fListener >= B_OK)
|
fcntl(fWritePipe, F_SETFD, FD_CLOEXEC);
|
||||||
resume_thread(fListener);
|
|
||||||
|
|
||||||
FD_ZERO(&fSet);
|
FD_ZERO(&fSet);
|
||||||
FD_SET(fReadPipe, &fSet);
|
FD_SET(fReadPipe, &fSet);
|
||||||
|
|
||||||
_UpdateMaxSocket(fWritePipe);
|
fMinSocket = fWritePipe + 1;
|
||||||
fMinSocket = fMaxSocket;
|
fMaxSocket = fWritePipe + 1;
|
||||||
|
|
||||||
|
fListener = spawn_thread(_Listener, "services listener", B_NORMAL_PRIORITY, this);
|
||||||
|
if (fListener >= B_OK)
|
||||||
|
resume_thread(fListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -184,10 +185,12 @@ Services::_NotifyListener(bool quit)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Services::_UpdateMaxSocket(int socket)
|
Services::_UpdateMinMaxSocket(int socket)
|
||||||
{
|
{
|
||||||
if (socket >= fMaxSocket)
|
if (socket >= fMaxSocket)
|
||||||
fMaxSocket = socket + 1;
|
fMaxSocket = socket + 1;
|
||||||
|
if (socket < fMinSocket)
|
||||||
|
fMinSocket = socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -202,19 +205,17 @@ Services::_StartService(struct service& service)
|
|||||||
service_address& address = *iterator;
|
service_address& address = *iterator;
|
||||||
|
|
||||||
address.socket = socket(address.family, address.type, address.protocol);
|
address.socket = socket(address.family, address.type, address.protocol);
|
||||||
if (address.socket < 0) {
|
if (address.socket < 0
|
||||||
|
|| bind(address.socket, &address.address, address.address.sa_len) < 0
|
||||||
|
|| fcntl(address.socket, F_SETFD, FD_CLOEXEC) < 0) {
|
||||||
failed = true;
|
failed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(address.socket, &address.address, address.address.sa_len) < 0) {
|
if (address.type == SOCK_STREAM && listen(address.socket, 50) < 0) {
|
||||||
failed = true;
|
failed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fSocketMap[address.socket] = &service;
|
|
||||||
_UpdateMaxSocket(address.socket);
|
|
||||||
FD_SET(address.socket, &fSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
@ -222,15 +223,17 @@ Services::_StartService(struct service& service)
|
|||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add service to maps
|
// add service to maps and activate it
|
||||||
|
|
||||||
fNameMap[service.name] = &service;
|
fNameMap[service.name] = &service;
|
||||||
|
|
||||||
iterator = service.addresses.begin();
|
iterator = service.addresses.begin();
|
||||||
for (; iterator != service.addresses.end(); iterator++) {
|
for (; iterator != service.addresses.end(); iterator++) {
|
||||||
const service_address& address = *iterator;
|
service_address& address = *iterator;
|
||||||
|
|
||||||
fSocketMap[address.socket] = &service;
|
fSocketMap[address.socket] = &address;
|
||||||
|
_UpdateMinMaxSocket(address.socket);
|
||||||
|
FD_SET(address.socket, &fSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
_NotifyListener();
|
_NotifyListener();
|
||||||
@ -286,14 +289,17 @@ Services::_ToService(const BMessage& message, struct service*& service)
|
|||||||
|
|
||||||
// TODO: user/group is currently ignored!
|
// TODO: user/group is currently ignored!
|
||||||
|
|
||||||
// default family/port/protocol/type for all addresses
|
// Default family/port/protocol/type for all addresses
|
||||||
|
|
||||||
|
// we default to inet/tcp/port-from-service-name if nothing is specified
|
||||||
const char* string;
|
const char* string;
|
||||||
int32 serviceFamilyIndex;
|
int32 serviceFamilyIndex;
|
||||||
int32 serviceFamily = -1;
|
int32 serviceFamily = -1;
|
||||||
if (message.FindString("family", &string) == B_OK) {
|
if (message.FindString("family", &string) != B_OK)
|
||||||
|
string = "inet";
|
||||||
|
|
||||||
if (get_family_index(string, serviceFamilyIndex))
|
if (get_family_index(string, serviceFamilyIndex))
|
||||||
serviceFamily = family_at_index(serviceFamilyIndex);
|
serviceFamily = family_at_index(serviceFamilyIndex);
|
||||||
}
|
|
||||||
|
|
||||||
int32 serviceProtocol;
|
int32 serviceProtocol;
|
||||||
if (message.FindString("protocol", &string) == B_OK)
|
if (message.FindString("protocol", &string) == B_OK)
|
||||||
@ -359,6 +365,7 @@ Services::_ToService(const BMessage& message, struct service*& service)
|
|||||||
set_port(familyIndex, serviceAddress.address, port);
|
set_port(familyIndex, serviceAddress.address, port);
|
||||||
serviceAddress.socket = -1;
|
serviceAddress.socket = -1;
|
||||||
|
|
||||||
|
serviceAddress.owner = service;
|
||||||
service->addresses.push_back(serviceAddress);
|
service->addresses.push_back(serviceAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,6 +386,7 @@ Services::_ToService(const BMessage& message, struct service*& service)
|
|||||||
set_port(serviceFamilyIndex, serviceAddress.address, servicePort);
|
set_port(serviceFamilyIndex, serviceAddress.address, servicePort);
|
||||||
serviceAddress.socket = -1;
|
serviceAddress.socket = -1;
|
||||||
|
|
||||||
|
serviceAddress.owner = service;
|
||||||
service->addresses.push_back(serviceAddress);
|
service->addresses.push_back(serviceAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,6 +427,43 @@ Services::_Update(const BMessage& services)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Services::_LaunchService(struct service& service, int socket)
|
||||||
|
{
|
||||||
|
printf("LAUNCH: %s\n", service.launch.c_str());
|
||||||
|
|
||||||
|
if (fcntl(socket, F_SETFD, 0) < 0) {
|
||||||
|
// could not clear FD_CLOEXEC on socket
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t child = fork();
|
||||||
|
if (child == 0) {
|
||||||
|
// We're the child, replace standard input/output
|
||||||
|
dup2(socket, STDIN_FILENO);
|
||||||
|
dup2(socket, STDOUT_FILENO);
|
||||||
|
dup2(socket, STDERR_FILENO);
|
||||||
|
close(socket);
|
||||||
|
|
||||||
|
// build argument array
|
||||||
|
|
||||||
|
const char** args = (const char**)malloc(2 * sizeof(void *));
|
||||||
|
if (args == NULL)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
args[0] = service.launch.c_str();
|
||||||
|
args[1] = NULL;
|
||||||
|
if (execv(service.launch.c_str(), (char* const*)args) < 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
// we'll never trespass here
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make sure child started successfully...
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Services::_Listener()
|
Services::_Listener()
|
||||||
{
|
{
|
||||||
@ -449,10 +494,28 @@ printf("select returned!\n");
|
|||||||
if (iterator == fSocketMap.end())
|
if (iterator == fSocketMap.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
struct service_address& address = *iterator->second;
|
||||||
|
int socket;
|
||||||
|
|
||||||
|
if (address.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);
|
||||||
|
|
||||||
|
value = 0;
|
||||||
|
ioctl(i, FIONBIO, &value);
|
||||||
|
|
||||||
|
if (socket < 0)
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
socket = address.socket;
|
||||||
|
|
||||||
// launch this service's handler
|
// launch this service's handler
|
||||||
|
|
||||||
struct service* service = iterator->second;
|
_LaunchService(*address.owner, socket);
|
||||||
printf("LAUNCH: %s\n", service->launch.c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
|
|
||||||
struct service;
|
struct service;
|
||||||
|
struct service_address;
|
||||||
typedef std::map<std::string, service*> ServiceNameMap;
|
typedef std::map<std::string, service*> ServiceNameMap;
|
||||||
typedef std::map<int, service*> ServiceSocketMap;
|
typedef std::map<int, service_address*> ServiceSocketMap;
|
||||||
|
|
||||||
|
|
||||||
class Services : public BHandler {
|
class Services : public BHandler {
|
||||||
@ -33,12 +34,13 @@ class Services : public BHandler {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void _NotifyListener(bool quit = false);
|
void _NotifyListener(bool quit = false);
|
||||||
void _UpdateMaxSocket(int socket);
|
void _UpdateMinMaxSocket(int socket);
|
||||||
status_t _StartService(struct service& service);
|
status_t _StartService(struct service& service);
|
||||||
status_t _StopService(struct service& service);
|
status_t _StopService(struct service& service);
|
||||||
status_t _ToService(const BMessage& message, struct service*& service);
|
status_t _ToService(const BMessage& message, struct service*& service);
|
||||||
void _Update(const BMessage& services);
|
void _Update(const BMessage& services);
|
||||||
int32 _CompareServices(struct service& a, struct service& b);
|
int32 _CompareServices(struct service& a, struct service& b);
|
||||||
|
status_t _LaunchService(struct service& service, int socket);
|
||||||
status_t _Listener();
|
status_t _Listener();
|
||||||
static status_t _Listener(void* self);
|
static status_t _Listener(void* self);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user