xref: /haiku/src/apps/cortex/NodeManager/AddOnHost.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
55 BMessenger AddOnHost::s_messenger;
56 
57 // -------------------------------------------------------- //
58 // *** static interface
59 // -------------------------------------------------------- //
60 
61 /*static*/
62 status_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*/
85 status_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*/
96 status_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*/
139 status_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*/
218 status_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