Skip to content

Commit

Permalink
launch_daemon: Divided MessageReceived() into several methods.
Browse files Browse the repository at this point in the history
* Was getting huge.
  • Loading branch information
axeld committed Jul 22, 2015
1 parent d54bb19 commit f2afa73
Showing 1 changed file with 174 additions and 133 deletions.
307 changes: 174 additions & 133 deletions src/servers/launch/LaunchDaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ class LaunchDaemon : public BServer, public Finder, public ConditionContext {
virtual void MessageReceived(BMessage* message);

private:
void _HandleGetLaunchData(BMessage* message);
void _HandleLaunchTarget(BMessage* message);
void _HandleLaunchSession(BMessage* message);
void _HandleRegisterSessionDaemon(BMessage* message);

uid_t _GetUserID(BMessage* message);

void _ReadPaths(const BStringList& paths);
Expand Down Expand Up @@ -281,149 +286,20 @@ LaunchDaemon::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_GET_LAUNCH_DATA:
{
uid_t user = _GetUserID(message);
if (user < 0)
return;

BMessage reply((uint32)B_OK);
Job* job = FindJob(get_leaf(message->GetString("name")));
if (job == NULL) {
Session* session = FindSession(user);
if (session != NULL) {
// Forward request to user launch_daemon
if (session->Daemon().SendMessage(message) == B_OK)
break;
}
reply.what = B_NAME_NOT_FOUND;
} else if (!job->IsLaunched() && !job->CheckCondition(*this)) {
// The job exists, but cannot be started yet, as its
// conditions are not met; don't make it available yet
// TODO: we may not want to initialize jobs with conditions
// that aren't met yet
reply.what = B_NO_INIT;
} else {
// If the job has not been launched yet, we'll pass on our
// team here. The rationale behind this is that this team
// will temporarily own the synchronous reply ports.
reply.AddInt32("team", job->Team() < 0
? current_team() : job->Team());

PortMap::const_iterator iterator = job->Ports().begin();
for (; iterator != job->Ports().end(); iterator++) {
BString name;
if (iterator->second.HasString("name"))
name << iterator->second.GetString("name") << "_";
name << "port";

reply.AddInt32(name.String(),
iterator->second.GetInt32("port", -1));
}

_TriggerJob(job);
}
message->SendReply(&reply);
_HandleGetLaunchData(message);
break;
}

case B_LAUNCH_TARGET:
{
uid_t user = _GetUserID(message);
if (user < 0)
break;

const char* name = message->GetString("target");
const char* baseName = message->GetString("base target");

Target* target = FindTarget(name);
if (target == NULL && baseName != NULL) {
Target* baseTarget = FindTarget(baseName);
if (baseTarget != NULL) {
target = new Target(name);

// Copy all jobs with the base target into the new target
for (JobMap::iterator iterator = fJobs.begin();
iterator != fJobs.end();) {
Job* job = iterator->second;
iterator++;

if (job->Target() == baseTarget) {
Job* copy = new Job(*job);
copy->SetTarget(target);

fJobs.insert(std::make_pair(copy->Name(), copy));
}
}
}
}
if (target == NULL) {
Session* session = FindSession(user);
if (session != NULL) {
// Forward request to user launch_daemon
if (session->Daemon().SendMessage(message) == B_OK)
break;
}

BMessage reply(B_NAME_NOT_FOUND);
message->SendReply(&reply);
break;
}

BMessage data;
if (message->FindMessage("data", &data) == B_OK)
target->AddData(data.GetString("name"), data);

_LaunchJobs(target);
_HandleLaunchTarget(message);
break;
}

case B_LAUNCH_SESSION:
{
uid_t user = _GetUserID(message);
if (user < 0)
break;

status_t status = B_OK;
const char* login = message->GetString("login");
if (login == NULL)
status = B_BAD_VALUE;
if (status == B_OK && user != 0) {
// Only the root user can start sessions
// TODO: we'd actually need to know the uid of the sender
status = B_PERMISSION_DENIED;
}
if (status == B_OK)
status = _StartSession(login);

BMessage reply((uint32)status);
message->SendReply(&reply);
_HandleLaunchSession(message);
break;
}

case B_REGISTER_SESSION_DAEMON:
{
uid_t user = _GetUserID(message);
if (user < 0)
break;

status_t status = B_OK;

BMessenger target;
if (message->FindMessenger("daemon", &target) != B_OK)
status = B_BAD_VALUE;

if (status == B_OK) {
Session* session = new (std::nothrow) Session(user, target);
if (session != NULL)
fSessions.insert(std::make_pair(user, session));
else
status = B_NO_MEMORY;
}

BMessage reply((uint32)status);
message->SendReply(&reply);
_HandleRegisterSessionDaemon(message);
break;
}

case kMsgEventTriggered:
{
Expand Down Expand Up @@ -454,6 +330,171 @@ LaunchDaemon::MessageReceived(BMessage* message)
}


void
LaunchDaemon::_HandleGetLaunchData(BMessage* message)
{
uid_t user = _GetUserID(message);
if (user < 0)
return;

BMessage reply((uint32)B_OK);
bool triggerJob = true;

Job* job = FindJob(get_leaf(message->GetString("name")));
if (job == NULL) {
Session* session = FindSession(user);
if (session != NULL) {
// Forward request to user launch_daemon
if (session->Daemon().SendMessage(message) == B_OK)
return;
}
reply.what = B_NAME_NOT_FOUND;
} else if (!job->IsLaunched()) {
if (!job->CheckCondition(*this)) {
// The job exists, but cannot be started yet, as its
// conditions are not met; don't make it available yet
// TODO: we may not want to initialize jobs with conditions
// that aren't met yet
reply.what = B_NO_INIT;
} else if (job->Event() != NULL) {
if (!Events::TriggerDemand(job->Event())) {
// The job is not triggered by demand; we cannot start it now
reply.what = B_NO_INIT;
} else {
// The job has already been triggered, don't trigger it
// again
triggerJob = false;
}
}
}

if (reply.what == B_OK) {
// If the job has not been launched yet, we'll pass on our
// team here. The rationale behind this is that this team
// will temporarily own the synchronous reply ports.
reply.AddInt32("team", job->Team() < 0
? current_team() : job->Team());

PortMap::const_iterator iterator = job->Ports().begin();
for (; iterator != job->Ports().end(); iterator++) {
BString name;
if (iterator->second.HasString("name"))
name << iterator->second.GetString("name") << "_";
name << "port";

reply.AddInt32(name.String(),
iterator->second.GetInt32("port", -1));
}

if (triggerJob)
_TriggerJob(job);
}
message->SendReply(&reply);
}


void
LaunchDaemon::_HandleLaunchTarget(BMessage* message)
{
uid_t user = _GetUserID(message);
if (user < 0)
return;

const char* name = message->GetString("target");
const char* baseName = message->GetString("base target");

Target* target = FindTarget(name);
if (target == NULL && baseName != NULL) {
Target* baseTarget = FindTarget(baseName);
if (baseTarget != NULL) {
target = new Target(name);

// Copy all jobs with the base target into the new target
for (JobMap::iterator iterator = fJobs.begin();
iterator != fJobs.end();) {
Job* job = iterator->second;
iterator++;

if (job->Target() == baseTarget) {
Job* copy = new Job(*job);
copy->SetTarget(target);

fJobs.insert(std::make_pair(copy->Name(), copy));
}
}
}
}
if (target == NULL) {
Session* session = FindSession(user);
if (session != NULL) {
// Forward request to user launch_daemon
if (session->Daemon().SendMessage(message) == B_OK)
return;
}

BMessage reply(B_NAME_NOT_FOUND);
message->SendReply(&reply);
return;
}

BMessage data;
if (message->FindMessage("data", &data) == B_OK)
target->AddData(data.GetString("name"), data);

_LaunchJobs(target);
}


void
LaunchDaemon::_HandleLaunchSession(BMessage* message)
{
uid_t user = _GetUserID(message);
if (user < 0)
return;

status_t status = B_OK;
const char* login = message->GetString("login");
if (login == NULL)
status = B_BAD_VALUE;
if (status == B_OK && user != 0) {
// Only the root user can start sessions
// TODO: we'd actually need to know the uid of the sender
status = B_PERMISSION_DENIED;
}
if (status == B_OK)
status = _StartSession(login);

BMessage reply((uint32)status);
message->SendReply(&reply);
}


void
LaunchDaemon::_HandleRegisterSessionDaemon(BMessage* message)
{
uid_t user = _GetUserID(message);
if (user < 0)
return;

status_t status = B_OK;

BMessenger target;
if (message->FindMessenger("daemon", &target) != B_OK)
status = B_BAD_VALUE;

if (status == B_OK) {
Session* session = new (std::nothrow) Session(user, target);
if (session != NULL)
fSessions.insert(std::make_pair(user, session));
else
status = B_NO_MEMORY;
}

BMessage reply((uint32)status);
message->SendReply(&reply);
}


uid_t
LaunchDaemon::_GetUserID(BMessage* message)
{
Expand Down

0 comments on commit f2afa73

Please sign in to comment.