1/*
2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files or portions
6 * thereof (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so, subject
10 * to the following conditions:
11 *
12 *  * Redistributions of source code must retain the above copyright notice,
13 *    this list of conditions and the following disclaimer.
14 *
15 *  * Redistributions in binary form must reproduce the above copyright notice
16 *    in the  binary, as well as this list of conditions and the following
17 *    disclaimer in the documentation and/or other materials provided with
18 *    the distribution.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 *
28 */
29
30
31#include "AppManager.h"
32
33#include <stdio.h>
34
35#include <Application.h>
36#include <Autolock.h>
37#include <OS.h>
38#include <Roster.h>
39
40#include <debug.h>
41#include <MediaMisc.h>
42
43#include "BufferManager.h"
44#include "media_server.h"
45#include "NodeManager.h"
46#include "NotificationManager.h"
47
48
49AppManager::AppManager()
50	:
51	BLocker("media app manager")
52{
53	fQuit = create_sem(0, "big brother waits");
54	fBigBrother = spawn_thread(_BigBrotherEntry, "big brother is watching you",
55		B_NORMAL_PRIORITY, this);
56	resume_thread(fBigBrother);
57}
58
59
60AppManager::~AppManager()
61{
62	delete_sem(fQuit);
63	wait_for_thread(fBigBrother, NULL);
64}
65
66
67bool
68AppManager::HasTeam(team_id team)
69{
70	BAutolock lock(this);
71	return fMap.find(team) != fMap.end();
72}
73
74
75status_t
76AppManager::RegisterTeam(team_id team, const BMessenger& messenger)
77{
78	BAutolock lock(this);
79
80	TRACE("AppManager::RegisterTeam %ld\n", team);
81	if (HasTeam(team)) {
82		ERROR("AppManager::RegisterTeam: team %ld already registered\n", team);
83		return B_ERROR;
84	}
85
86	try {
87		fMap.insert(std::make_pair(team, messenger));
88	} catch (std::bad_alloc& exception) {
89		return B_NO_MEMORY;
90	}
91
92	return B_OK;
93}
94
95
96status_t
97AppManager::UnregisterTeam(team_id team)
98{
99	TRACE("AppManager::UnregisterTeam %ld\n", team);
100
101	Lock();
102	bool isRemoved = fMap.erase(team) != 0;
103	Unlock();
104
105	_CleanupTeam(team);
106
107	return isRemoved ? B_OK : B_ERROR;
108}
109
110
111team_id
112AppManager::AddOnServerTeam()
113{
114	team_id id = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE);
115	if (id < 0) {
116		ERROR("media_server: Trouble, media_addon_server is dead!\n");
117		return -1;
118	}
119	return id;
120}
121
122
123status_t
124AppManager::SendMessage(team_id team, BMessage* message)
125{
126	BAutolock lock(this);
127
128	AppMap::iterator found = fMap.find(team);
129	if (found == fMap.end())
130		return B_NAME_NOT_FOUND;
131
132	return found->second.SendMessage(message);
133}
134
135
136void
137AppManager::Dump()
138{
139	BAutolock lock(this);
140
141	printf("\n");
142	printf("AppManager: list of applications follows:\n");
143
144	app_info info;
145	AppMap::iterator iterator = fMap.begin();
146	for (; iterator != fMap.end(); iterator++) {
147		app_info info;
148		be_roster->GetRunningAppInfo(iterator->first, &info);
149		printf(" team %ld \"%s\", messenger %svalid\n", iterator->first,
150			info.ref.name, iterator->second.IsValid() ? "" : "NOT ");
151	}
152
153	printf("AppManager: list end\n");
154}
155
156
157void
158AppManager::_CleanupTeam(team_id team)
159{
160	ASSERT(!IsLocked());
161
162	TRACE("AppManager: cleaning up team %ld\n", team);
163
164	gNodeManager->CleanupTeam(team);
165	gBufferManager->CleanupTeam(team);
166	gNotificationManager->CleanupTeam(team);
167}
168
169
170void
171AppManager::_TeamDied(team_id team)
172{
173	UnregisterTeam(team);
174}
175
176
177status_t
178AppManager::_BigBrotherEntry(void* self)
179{
180	static_cast<AppManager*>(self)->_BigBrother();
181	return 0;
182}
183
184
185/*!	The BigBrother thread send ping messages to the BMediaRoster of
186	all currently running teams. If the reply times out or is wrong,
187	the team cleanup function _TeamDied() will be called.
188*/
189void
190AppManager::_BigBrother()
191{
192	status_t status = B_TIMED_OUT;
193	BMessage ping('PING');
194	BMessage reply;
195
196	do {
197		if (!Lock())
198			break;
199
200		bool startOver = false;
201		AppMap::iterator iterator = fMap.begin();
202		for (; iterator != fMap.end(); iterator++) {
203			reply.what = 0;
204			status = iterator->second.SendMessage(&ping, &reply, 5000000,
205				2000000);
206			if (status != B_OK || reply.what != 'PONG') {
207				team_id team = iterator->first;
208				Unlock();
209
210				_TeamDied(team);
211				startOver = true;
212				break;
213			}
214		}
215
216		if (startOver)
217			continue;
218
219		Unlock();
220		status = acquire_sem_etc(fQuit, 1, B_RELATIVE_TIMEOUT, 2000000);
221	} while (status == B_TIMED_OUT || status == B_INTERRUPTED);
222}
223