vfs: check userland buffers before reading them.
[haiku.git] / src / kits / media / Controllable.cpp
blob6c722245e53d34c1858642fe9a1d767f4cd75e14
1 /*
2 * Copyright 2009-2012, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT license.
4 */
6 /*
7 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files or portions
11 * thereof (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so, subject
15 * to the following conditions:
17 * * Redistributions of source code must retain the above copyright notice,
18 * this list of conditions and the following disclaimer.
20 * * Redistributions in binary form must reproduce the above copyright notice
21 * in the binary, as well as this list of conditions and the following
22 * disclaimer in the documentation and/or other materials provided with
23 * the distribution.
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 * THE SOFTWARE.
35 #include <Controllable.h>
37 #include <string.h>
39 #include <OS.h>
40 #include <ParameterWeb.h>
41 #include <Roster.h>
42 #include <TimeSource.h>
44 #include <debug.h>
45 #include <DataExchange.h>
46 #include <Notifications.h>
49 namespace BPrivate { namespace media {
51 /*! A helper class for the communication with the media server that
52 takes care of large buffers that need an area.
54 class ReceiveTransfer {
55 public:
56 ReceiveTransfer(const area_request_data& request, const void* smallBuffer)
58 if (request.area == -1 && smallBuffer != NULL) {
59 // small data transfer uses buffer in reply
60 fArea = -1;
61 fData = const_cast<void*>(smallBuffer);
62 // The caller is actually responsible to enforce the const;
63 // we don't touch the data.
64 } else {
65 // large data transfer, clone area
66 fArea = clone_area("get parameter data clone", &fData,
67 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request.area);
68 if (fArea < B_OK) {
69 ERROR("BControllabe: cloning area failed: %s\n",
70 strerror(fArea));
71 fData = NULL;
76 ~ReceiveTransfer()
78 if (fArea >= B_OK)
79 delete_area(fArea);
82 status_t InitCheck() const
84 return fData != NULL ? B_OK : fArea;
87 void* Data() const
89 return fData;
92 private:
93 area_id fArea;
94 void* fData;
97 } // namespace media
98 } // namespace BPrivate
100 using BPrivate::media::ReceiveTransfer;
103 // #pragma mark - protected
106 BControllable::~BControllable()
108 CALLED();
109 if (fSem > 0)
110 delete_sem(fSem);
112 delete fWeb;
116 // #pragma mark - public
119 BParameterWeb*
120 BControllable::Web()
122 CALLED();
123 return fWeb;
127 bool
128 BControllable::LockParameterWeb()
130 CALLED();
131 if (fSem <= 0)
132 return false;
134 if (atomic_add(&fBen, 1) > 0) {
135 status_t status;
136 do {
137 status = acquire_sem(fSem);
138 } while (status == B_INTERRUPTED);
140 return status == B_OK;
143 return true;
147 void
148 BControllable::UnlockParameterWeb()
150 CALLED();
151 if (fSem <= 0)
152 return;
154 if (atomic_add(&fBen, -1) > 1)
155 release_sem(fSem);
159 // #pragma mark - protected
162 BControllable::BControllable()
163 : BMediaNode("this one is never called"),
164 fWeb(NULL),
165 fSem(create_sem(0, "BControllable lock")),
166 fBen(0)
168 CALLED();
170 AddNodeKind(B_CONTROLLABLE);
174 status_t
175 BControllable::SetParameterWeb(BParameterWeb* web)
177 CALLED();
179 LockParameterWeb();
180 BParameterWeb* old = fWeb;
181 fWeb = web;
183 if (fWeb != NULL) {
184 // initialize BParameterWeb member variable
185 fWeb->fNode = Node();
188 UnlockParameterWeb();
190 if (old != web && web != NULL)
191 BPrivate::media::notifications::WebChanged(Node());
192 delete old;
193 return B_OK;
197 status_t
198 BControllable::HandleMessage(int32 message, const void* data, size_t size)
200 PRINT(4, "BControllable::HandleMessage %#lx, node %ld\n", message, ID());
202 switch (message) {
203 case CONTROLLABLE_GET_PARAMETER_DATA:
205 const controllable_get_parameter_data_request& request
206 = *static_cast<const controllable_get_parameter_data_request*>(
207 data);
208 controllable_get_parameter_data_reply reply;
210 ReceiveTransfer transfer(request, reply.raw_data);
211 if (transfer.InitCheck() != B_OK) {
212 request.SendReply(transfer.InitCheck(), &reply, sizeof(reply));
213 return B_OK;
216 reply.size = request.request_size;
217 status_t status = GetParameterValue(request.parameter_id,
218 &reply.last_change, transfer.Data(), &reply.size);
220 request.SendReply(status, &reply, sizeof(reply));
221 return B_OK;
224 case CONTROLLABLE_SET_PARAMETER_DATA:
226 const controllable_set_parameter_data_request& request
227 = *static_cast<const controllable_set_parameter_data_request*>(
228 data);
229 controllable_set_parameter_data_reply reply;
231 ReceiveTransfer transfer(request, request.raw_data);
232 if (transfer.InitCheck() != B_OK) {
233 request.SendReply(transfer.InitCheck(), &reply, sizeof(reply));
234 return B_OK;
237 // NOTE: This is not very fair, but the alternative
238 // would have been to mess with friends classes and
239 // member variables.
240 bigtime_t perfTime = 0;
241 if (request.when == -1)
242 perfTime = TimeSource()->Now();
243 else
244 perfTime = request.when;
246 SetParameterValue(request.parameter_id, perfTime,
247 transfer.Data(), request.size);
248 request.SendReply(B_OK, &reply, sizeof(reply));
249 return B_OK;
252 case CONTROLLABLE_GET_PARAMETER_WEB:
254 const controllable_get_parameter_web_request& request
255 = *static_cast<const controllable_get_parameter_web_request*>(
256 data);
257 controllable_get_parameter_web_reply reply;
259 status_t status = B_OK;
260 bool wasLocked = true;
261 if (!LockParameterWeb()) {
262 status = B_ERROR;
263 wasLocked = false;
266 if (status == B_OK && fWeb != NULL) {
267 if (fWeb->FlattenedSize() > request.max_size) {
268 // parameter web too large
269 reply.code = 0;
270 reply.size = -1;
271 status = B_OK;
272 } else {
273 ReceiveTransfer transfer(request, NULL);
274 status = transfer.InitCheck();
275 if (status == B_OK) {
276 reply.code = fWeb->TypeCode();
277 reply.size = fWeb->FlattenedSize();
278 status = fWeb->Flatten(transfer.Data(), reply.size);
279 if (status != B_OK) {
280 ERROR("BControllable::HandleMessage "
281 "CONTROLLABLE_GET_PARAMETER_WEB Flatten failed\n");
282 #if 0
283 } else {
284 printf("BControllable::HandleMessage CONTROLLABLE_GET_PARAMETER_WEB %ld bytes, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n",
285 reply.size, ((uint32*)buffer)[0], ((uint32*)buffer)[1], ((uint32*)buffer)[2], ((uint32*)buffer)[3]);
286 #endif
290 } else {
291 // no parameter web
292 reply.code = 0;
293 reply.size = 0;
295 if (wasLocked)
296 UnlockParameterWeb();
298 request.SendReply(status, &reply, sizeof(reply));
299 return B_OK;
302 case CONTROLLABLE_START_CONTROL_PANEL:
304 const controllable_start_control_panel_request* request
305 = static_cast<const controllable_start_control_panel_request*>(
306 data);
307 controllable_start_control_panel_reply reply;
308 BMessenger targetMessenger;
309 status_t status = StartControlPanel(&targetMessenger);
310 if (status != B_OK) {
311 ERROR("BControllable::HandleMessage "
312 "CONTROLLABLE_START_CONTROL_PANEL failed\n");
314 reply.result = status;
315 reply.team = targetMessenger.Team();
316 request->SendReply(status, &reply, sizeof(reply));
317 return B_OK;
320 default:
321 return B_ERROR;
324 return B_OK;
328 status_t
329 BControllable::BroadcastChangedParameter(int32 id)
331 CALLED();
332 return BPrivate::media::notifications::ParameterChanged(Node(), id);
336 status_t
337 BControllable::BroadcastNewParameterValue(bigtime_t when, int32 id,
338 void* newValue, size_t valueSize)
340 CALLED();
341 return BPrivate::media::notifications::NewParameterValue(Node(), id, when,
342 newValue, valueSize);
346 status_t
347 BControllable::StartControlPanel(BMessenger* _messenger)
349 CALLED();
351 int32 internalId;
352 BMediaAddOn* addon = AddOn(&internalId);
353 if (!addon) {
354 ERROR("BControllable::StartControlPanel not instantiated per AddOn\n");
355 return B_ERROR;
358 image_id imageID = addon->ImageID();
359 image_info info;
360 if (imageID <= 0 || get_image_info(imageID, &info) != B_OK) {
361 ERROR("BControllable::StartControlPanel Error accessing image\n");
362 return B_BAD_VALUE;
365 entry_ref ref;
366 if (get_ref_for_path(info.name, &ref) != B_OK) {
367 ERROR("BControllable::StartControlPanel Error getting ref\n");
368 return B_BAD_VALUE;
371 // The first argument is "node=id" with id meaning the media_node_id
372 char arg[32];
373 snprintf(arg, sizeof(arg), "node=%d", (int)ID());
375 team_id team;
376 if (be_roster->Launch(&ref, 1, (const char* const*)&arg, &team) != B_OK) {
377 ERROR("BControllable::StartControlPanel Error launching application\n");
378 return B_BAD_VALUE;
380 printf("BControllable::StartControlPanel done with id: %" B_PRId32 "\n",
381 team);
383 if (_messenger)
384 *_messenger = BMessenger(NULL, team);
386 return B_OK;
390 status_t
391 BControllable::ApplyParameterData(const void* value, size_t size)
393 UNIMPLEMENTED();
395 return B_ERROR;
399 status_t
400 BControllable::MakeParameterData(const int32* controls, int32 count,
401 void* buffer, size_t* ioSize)
403 UNIMPLEMENTED();
405 return B_ERROR;
409 // #pragma mark - private
412 status_t BControllable::_Reserved_Controllable_0(void *) { return B_ERROR; }
413 status_t BControllable::_Reserved_Controllable_1(void *) { return B_ERROR; }
414 status_t BControllable::_Reserved_Controllable_2(void *) { return B_ERROR; }
415 status_t BControllable::_Reserved_Controllable_3(void *) { return B_ERROR; }
416 status_t BControllable::_Reserved_Controllable_4(void *) { return B_ERROR; }
417 status_t BControllable::_Reserved_Controllable_5(void *) { return B_ERROR; }
418 status_t BControllable::_Reserved_Controllable_6(void *) { return B_ERROR; }
419 status_t BControllable::_Reserved_Controllable_7(void *) { return B_ERROR; }
420 status_t BControllable::_Reserved_Controllable_8(void *) { return B_ERROR; }
421 status_t BControllable::_Reserved_Controllable_9(void *) { return B_ERROR; }
422 status_t BControllable::_Reserved_Controllable_10(void *) { return B_ERROR; }
423 status_t BControllable::_Reserved_Controllable_11(void *) { return B_ERROR; }
424 status_t BControllable::_Reserved_Controllable_12(void *) { return B_ERROR; }
425 status_t BControllable::_Reserved_Controllable_13(void *) { return B_ERROR; }
426 status_t BControllable::_Reserved_Controllable_14(void *) { return B_ERROR; }
427 status_t BControllable::_Reserved_Controllable_15(void *) { return B_ERROR; }