1/*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions, and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions, and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32#include "AddOnHost.h"
33#include "AddOnHostProtocol.h"
34
35#include <Application.h>
36#include <Debug.h>
37#include <Entry.h>
38#include <MediaNode.h>
39#include <MediaRoster.h>
40#include <Messenger.h>
41#include <Path.h>
42#include <Roster.h>
43
44#include <OS.h>
45
46#include <cstdlib>
47#include <cstring>
48
49__USE_CORTEX_NAMESPACE
50
51// -------------------------------------------------------- //
52// constants
53// -------------------------------------------------------- //
54
55BMessenger AddOnHost::s_messenger;
56
57// -------------------------------------------------------- //
58// *** static interface
59// -------------------------------------------------------- //
60
61/*static*/
62status_t AddOnHost::FindInstance(
63	BMessenger*								outMessenger) {
64
65	status_t err;
66
67	// no current app? launch one
68	if(!s_messenger.IsValid()) {
69		s_messenger = BMessenger(
70			addon_host::g_appSignature,
71			-1,
72			&err);
73
74		if(err < B_OK)
75			return err;
76		if(!s_messenger.IsValid())
77			return B_ERROR;
78	}
79
80	*outMessenger = s_messenger;
81	return B_OK;
82}
83
84/*static*/
85status_t AddOnHost::Kill(
86	bigtime_t									timeout) {
87
88	if(!s_messenger.IsValid())
89		return B_NOT_ALLOWED;
90
91	status_t err = kill_team(s_messenger.Team());
92	return err;
93}
94
95/*static*/
96status_t AddOnHost::Launch(
97	BMessenger*								outMessenger) {
98
99	if(s_messenger.IsValid())
100		return B_NOT_ALLOWED;
101
102	status_t err;
103
104	// find it
105	entry_ref appRef;
106	err = be_roster->FindApp(addon_host::g_appSignature, &appRef);
107	if(err < B_OK)
108		return err;
109
110	// start it
111	team_id team;
112	const char* arg = "--addon-host";
113	err = be_roster->Launch(
114		&appRef,
115		1,
116		&arg,
117		&team);
118	if(err < B_OK)
119		return err;
120
121	// fetch messenger to the new app and return it
122	s_messenger = BMessenger(
123		addon_host::g_appSignature,
124		team,
125		&err);
126
127	if(err < B_OK)
128		return err;
129	if(!s_messenger.IsValid())
130		return B_ERROR;
131
132	if(outMessenger)
133		*outMessenger = s_messenger;
134
135	return B_OK;
136}
137
138/*static*/
139status_t AddOnHost::InstantiateDormantNode(
140	const dormant_node_info&	info,
141	media_node*								outNode,
142	bigtime_t									timeout) {
143
144	status_t err;
145
146	if(!s_messenger.IsValid()) {
147		err = Launch(0);
148
149		if(err < B_OK) {
150			// give up
151			PRINT((
152				"!!! AddOnHost::InstantiateDormantNode(): Launch() failed:\n"
153				"    %s\n",
154				strerror(err)));
155			return err;
156		}
157	}
158
159	// do it
160	ASSERT(s_messenger.IsValid());
161	BMessage request(addon_host::M_INSTANTIATE);
162	request.AddData("info", B_RAW_TYPE, &info, sizeof(dormant_node_info));
163
164	BMessage reply(B_NO_REPLY);
165	err = s_messenger.SendMessage(
166		&request,
167		&reply,
168		timeout,
169		timeout);
170
171//	PRINT((
172//		"### SendMessage() returned '%s'\n", strerror(err)));
173
174	if(err < B_OK) {
175		PRINT((
176			"!!! AddOnHost::InstantiateDormantNode(): SendMessage() failed:\n"
177			"    %s\n",
178			strerror(err)));
179		return err;
180	}
181
182	if(reply.what == B_NO_REPLY) {
183		PRINT((
184			"!!! AddOnHost::InstantiateDormantNode(): no reply.\n"));
185		return B_ERROR;
186	}
187
188	if(reply.what == addon_host::M_INSTANTIATE_COMPLETE) {
189		media_node_id nodeID;
190
191		// fetch node ID
192		err = reply.FindInt32("node_id", &nodeID);
193		if(err < B_OK) {
194			PRINT((
195				"!!! AddOnHost::InstantiateDormantNode(): 'node_id' missing from reply.\n"));
196			return B_ERROR;
197		}
198
199		// fetch node
200		err = BMediaRoster::Roster()->GetNodeFor(nodeID, outNode);
201		if(err < B_OK) {
202			PRINT((
203				"!!! AddOnHost::InstantiateDormantNode(): node missing!\n"));
204			return B_ERROR;
205		}
206
207//		// now solely owned by the add-on host team
208//		BMediaRoster::Roster()->ReleaseNode(*outNode);
209
210		return B_OK;
211	}
212
213	// failed:
214	return (reply.FindInt32("error", &err) == B_OK) ? err : B_ERROR;
215}
216
217/*static*/
218status_t AddOnHost::ReleaseInternalNode(
219	const live_node_info&			info,
220	bigtime_t									timeout) {
221
222	status_t err;
223
224	if(!s_messenger.IsValid()) {
225		err = Launch(0);
226
227		if(err < B_OK) {
228			// give up
229			PRINT((
230				"!!! AddOnHost::ReleaseInternalNode(): Launch() failed:\n"
231				"    %s\n",
232				strerror(err)));
233			return err;
234		}
235	}
236
237	// do it
238	ASSERT(s_messenger.IsValid());
239	BMessage request(addon_host::M_RELEASE);
240	request.AddData("info", B_RAW_TYPE, &info, sizeof(live_node_info));
241
242	BMessage reply(B_NO_REPLY);
243	err = s_messenger.SendMessage(
244		&request,
245		&reply,
246		timeout,
247		timeout);
248
249
250	if(err < B_OK) {
251		PRINT((
252			"!!! AddOnHost::ReleaseInternalNode(): SendMessage() failed:\n"
253			"    %s\n",
254			strerror(err)));
255		return err;
256	}
257
258	if(reply.what == B_NO_REPLY) {
259		PRINT((
260			"!!! AddOnHost::InstantiateDormantNode(): no reply.\n"));
261		return B_ERROR;
262	}
263
264	if(reply.what == addon_host::M_RELEASE_COMPLETE) {
265		return B_OK;
266	}
267
268	// failed:
269	return (reply.FindInt32("error", &err) == B_OK) ? err : B_ERROR;
270}
271
272