#include <AppDefs.h>
#include <List.h>
#include <String.h>
#include <stdio.h>
#include <string.h>
#include <ServerProtocol.h>
#include "AppServer.h"
#include "ServerApp.h"
#ifdef DEBUG_SERVERAPP
# include <stdio.h>
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
#ifdef DEBUG_SERVERAPP_FONT
# include <stdio.h>
# define FTRACE(x) printf x
#else
# define FTRACE(x) ;
#endif
ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort,
team_id clientTeamID, int32 handlerID, const char* signature)
:
fClientAppPort(sendport),
fMessagePort(rcvport),
fClientLooperPort(clientLooperPort),
fSignature(signature),
fMonitorThreadID(-1),
fClientTeamID(clientTeamID),
fLink(fClientAppPort, fMessagePort),
fLockSem(create_sem(1, "ServerApp sem")),
fCursorHidden(false),
fIsActive(false),
fQuitting(false)
{
if (fSignature == "")
fSignature = "application/x-vnd.NULL-application-signature";
Run();
STRACE(("ServerApp %s:\n", fSignature.String()));
STRACE(("\tBApp port: %ld\n", fClientAppPort));
STRACE(("\tReceiver port: %ld\n", fMessagePort));
}
ServerApp::~ServerApp(void)
{
STRACE(("*ServerApp %s:~ServerApp()\n",fSignature.String()));
fQuitting = true;
delete_sem(fLockSem);
STRACE(("#ServerApp %s:~ServerApp()\n", fSignature.String()));
delete_port(fMessagePort);
status_t dummyStatus;
wait_for_thread(fMonitorThreadID, &dummyStatus);
STRACE(("ServerApp %s::~ServerApp(): Exiting\n", fSignature.String()));
}
bool
ServerApp::Run(void)
{
fMonitorThreadID = spawn_thread(MonitorApp, fSignature.String(), B_NORMAL_PRIORITY, this);
if (fMonitorThreadID < B_OK)
return false;
return resume_thread(fMonitorThreadID) == B_OK;
}
bool
ServerApp::PingTarget(void)
{
team_info tinfo;
if (get_team_info(fClientTeamID, &tinfo) == B_BAD_TEAM_ID) {
BPrivate::LinkSender link(gAppServerPort);
link.StartMessage(AS_DELETE_APP);
link.Attach(&fMonitorThreadID, sizeof(thread_id));
link.Flush();
return false;
}
return true;
}
void
ServerApp::PostMessage(int32 code)
{
BPrivate::LinkSender link(fMessagePort);
link.StartMessage(code);
link.Flush();
}
void
ServerApp::SendMessageToClient(const BMessage *msg) const
{
ssize_t size = msg->FlattenedSize();
char *buffer = new char[size];
if (msg->Flatten(buffer, size) == B_OK)
write_port(fClientLooperPort, msg->what, buffer, size);
else
printf("PANIC: ServerApp: '%s': can't flatten message in 'SendMessageToClient()'\n", fSignature.String());
delete [] buffer;
}
void
ServerApp::Activate(bool value)
{
fIsActive = value;
}
int32
ServerApp::MonitorApp(void *data)
{
ServerApp *app = (ServerApp *)data;
BPrivate::LinkReceiver &reader = app->fLink.Receiver();
int32 code;
status_t err = B_OK;
while (!app->fQuitting) {
STRACE(("info: ServerApp::MonitorApp listening on port %ld.\n", app->fMessagePort));
err = reader.GetNextMessage(code, B_INFINITE_TIMEOUT);
if (err < B_OK) {
STRACE(("ServerApp::MonitorApp(): GetNextMessage returned %s\n", strerror(err)));
BPrivate::LinkSender link(gAppServerPort);
link.StartMessage(AS_DELETE_APP);
link.Attach(&app->fMonitorThreadID, sizeof(thread_id));
link.Flush();
break;
}
switch (code) {
case AS_QUIT_APP:
{
STRACE(("ServerApp %s:Server shutdown notification received\n",
app->fSignature.String()));
break;
}
case B_QUIT_REQUESTED:
{
STRACE(("ServerApp %s: B_QUIT_REQUESTED\n",app->fSignature.String()));
BPrivate::LinkSender sender(gAppServerPort);
sender.StartMessage(AS_DELETE_APP);
sender.Attach(&app->fMonitorThreadID, sizeof(thread_id));
sender.Flush();
break;
}
default:
STRACE(("ServerApp %s: Got a Message to dispatch\n", app->fSignature.String()));
app->DispatchMessage(code, reader);
break;
}
}
return 0;
}
void
ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
{
switch (code) {
case AS_CURRENT_WORKSPACE:
{
STRACE(("ServerApp %s: get current workspace\n", fSignature.String()));
fLink.StartMessage(B_OK);
fLink.Attach<int32>(0);
fLink.Flush();
break;
}
case AS_ACTIVATE_WORKSPACE:
{
STRACE(("ServerApp %s: activate workspace\n", fSignature.String()));
int32 index;
link.Read<int32>(&index);
break;
}
case AS_QUERY_CURSOR_HIDDEN:
{
STRACE(("ServerApp %s: Received IsCursorHidden request\n", fSignature.String()));
fLink.StartMessage(fCursorHidden ? B_OK : B_ERROR);
fLink.Flush();
break;
}
default:
printf("ServerApp %s received unhandled message code offset %lx\n",
fSignature.String(), code);
if (link.NeedsReply()) {
fLink.StartMessage(B_ERROR);
fLink.Flush();
} else
puts("message doesn't need a reply!");
break;
}
}
team_id
ServerApp::ClientTeamID() const
{
return fClientTeamID;
}
thread_id
ServerApp::MonitorThreadID() const
{
return fMonitorThreadID;
}