vfs: check userland buffers before reading them.
[haiku.git] / src / kits / midi2 / MidiRoster.cpp
blob6ea024810392f26d2f4311352a99ac01afb5f1ac
1 /*
2 * Copyright 2006, Haiku.
4 * Copyright (c) 2002-2004 Matthijs Hollemans
5 * Distributed under the terms of the MIT License.
7 * Authors:
8 * Matthijs Hollemans
9 */
11 #include "debug.h"
12 #include <MidiConsumer.h>
13 #include <MidiRoster.h>
14 #include "MidiRosterLooper.h"
15 #include "protocol.h"
17 #include <pthread.h>
20 using namespace BPrivate;
22 // The midi_debug_level and midi_dispatcher_priority symbols
23 // were exported by Be's libmidi2, and even though they do not
24 // appear in the headers, some apps may still be using them.
25 // For backwards compatibility's sake, we export those symbols
26 // as well, even though we do not use them for anything.
28 // Not used. For backwards compatibility only.
29 int32 midi_debug_level = 0;
31 // Not used. For backwards compatibility only.
32 int32 midi_dispatcher_priority = B_REAL_TIME_PRIORITY;
34 //------------------------------------------------------------------------------
36 // The one and only BMidiRoster instance, which is created
37 // the first time the client app calls MidiRoster(). It is
38 // destroyed by the BMidiRosterKiller when the app quits.
39 static BMidiRoster* sRoster = NULL;
41 static pthread_once_t sInitOnce = PTHREAD_ONCE_INIT;
44 // Destroys the BMidiRoster instance when the app quits.
45 namespace BPrivate
47 static struct BMidiRosterKiller
49 ~BMidiRosterKiller()
51 delete sRoster;
54 static void CreateRoster() {
55 sRoster = new BMidiRoster();
58 midi_roster_killer;
62 BMidiEndpoint*
63 BMidiRoster::NextEndpoint(int32* id)
65 BMidiEndpoint* endp = NULL;
67 if (id != NULL) {
68 BMidiRosterLooper* looper = MidiRoster()->fLooper;
69 if (looper->Lock()) {
70 endp = looper->NextEndpoint(id);
71 if (endp != NULL) {
72 endp->Acquire();
74 looper->Unlock();
78 return endp;
82 BMidiProducer*
83 BMidiRoster::NextProducer(int32* id)
85 BMidiEndpoint* endp;
87 while ((endp = NextEndpoint(id)) != NULL) {
88 if (endp->IsProducer()) {
89 return (BMidiProducer*) endp;
91 endp->Release();
94 return NULL;
98 BMidiConsumer*
99 BMidiRoster::NextConsumer(int32* id)
101 BMidiEndpoint* endp;
103 while ((endp = NextEndpoint(id)) != NULL) {
104 if (endp->IsConsumer()) {
105 return (BMidiConsumer*) endp;
107 endp->Release();
110 return NULL;
114 BMidiEndpoint*
115 BMidiRoster::FindEndpoint(int32 id, bool localOnly)
117 BMidiEndpoint* endp = NULL;
119 BMidiRosterLooper* looper = MidiRoster()->fLooper;
120 if (looper->Lock()) {
121 endp = looper->FindEndpoint(id);
123 if ((endp != NULL) && endp->IsRemote()) {
124 if (localOnly || !endp->IsRegistered()) {
125 endp = NULL;
129 if (endp != NULL) {
130 endp->Acquire();
133 looper->Unlock();
136 return endp;
140 BMidiProducer*
141 BMidiRoster::FindProducer(int32 id, bool localOnly)
143 BMidiEndpoint* endp = FindEndpoint(id, localOnly);
145 if ((endp != NULL) && !endp->IsProducer()) {
146 endp->Release();
147 endp = NULL;
150 return (BMidiProducer*) endp;
154 BMidiConsumer*
155 BMidiRoster::FindConsumer(int32 id, bool localOnly)
157 BMidiEndpoint* endp = FindEndpoint(id, localOnly);
159 if ((endp != NULL) && !endp->IsConsumer()) {
160 endp->Release();
161 endp = NULL;
164 return (BMidiConsumer*) endp;
168 void
169 BMidiRoster::StartWatching(const BMessenger* msngr)
171 if (msngr == NULL) {
172 WARN("StartWatching does not accept a NULL messenger")
173 } else {
174 BMidiRosterLooper* looper = MidiRoster()->fLooper;
175 if (looper->Lock()) {
176 looper->StartWatching(msngr);
177 looper->Unlock();
183 void
184 BMidiRoster::StopWatching()
186 BMidiRosterLooper* looper = MidiRoster()->fLooper;
187 if (looper->Lock()) {
188 looper->StopWatching();
189 looper->Unlock();
194 status_t
195 BMidiRoster::Register(BMidiEndpoint* endp)
197 if (endp != NULL) {
198 return endp->Register();
201 return B_BAD_VALUE;
205 status_t
206 BMidiRoster::Unregister(BMidiEndpoint* endp)
208 if (endp != NULL) {
209 return endp->Unregister();
212 return B_BAD_VALUE;
216 BMidiRoster*
217 BMidiRoster::MidiRoster()
219 pthread_once(&sInitOnce, BPrivate::BMidiRosterKiller::CreateRoster);
221 return sRoster;
225 BMidiRoster::BMidiRoster()
227 TRACE(("BMidiRoster::BMidiRoster"))
229 fLooper = new BMidiRosterLooper();
231 if (!fLooper->Init(this))
232 return;
234 BMessage msg;
235 msg.what = MSG_REGISTER_APP;
236 msg.AddMessenger("midi:messenger", BMessenger(fLooper));
237 fServer = new BMessenger(MIDI_SERVER_SIGNATURE);
239 if (fServer->SendMessage(&msg, fLooper, TIMEOUT) != B_OK) {
240 WARN("Cannot send request to midi_server");
241 return;
244 // Although unlikely, we may receive the midi_server's
245 // "app registered" reply before we lock the semaphore.
246 // In that case, BMidiRosterLooper's MessageReceived()
247 // will bump the semaphore count, and our acquire_sem()
248 // can grab the semaphore safely (without blocking).
250 acquire_sem(fLooper->fInitLock);
254 BMidiRoster::~BMidiRoster()
256 TRACE(("BMidiRoster::~BMidiRoster"))
258 if (fLooper != NULL) {
259 fLooper->Lock();
260 fLooper->Quit();
262 delete fServer;
266 void BMidiRoster::_Reserved1() { }
267 void BMidiRoster::_Reserved2() { }
268 void BMidiRoster::_Reserved3() { }
269 void BMidiRoster::_Reserved4() { }
270 void BMidiRoster::_Reserved5() { }
271 void BMidiRoster::_Reserved6() { }
272 void BMidiRoster::_Reserved7() { }
273 void BMidiRoster::_Reserved8() { }
276 void
277 BMidiRoster::CreateLocal(BMidiEndpoint* endp)
279 ASSERT(endp != NULL)
281 // We are being called from the BMidiLocalConsumer or
282 // BMidiLocalProducer constructor, so there is no need
283 // to lock anything, because at this point there cannot
284 // be multiple threads accessing the endpoint's data.
286 BMessage msg;
287 msg.what = MSG_CREATE_ENDPOINT;
288 msg.AddBool("midi:consumer", endp->fIsConsumer);
289 msg.AddBool("midi:registered", endp->fIsRegistered);
290 msg.AddString("midi:name", endp->Name());
291 msg.AddMessage("midi:properties", endp->fProperties);
293 if (endp->IsConsumer()) {
294 BMidiConsumer* consumer = (BMidiConsumer*) endp;
295 msg.AddInt32("midi:port", consumer->fPort);
296 msg.AddInt64("midi:latency", consumer->fLatency);
299 BMessage reply;
300 if (SendRequest(&msg, &reply) == B_OK) {
301 status_t res;
302 if (reply.FindInt32("midi:result", &res) == B_OK) {
303 if (res == B_OK) {
304 int32 id;
305 if (reply.FindInt32("midi:id", &id) == B_OK) {
306 endp->fId = id;
308 if (fLooper->Lock()) {
309 fLooper->AddEndpoint(endp);
310 fLooper->Unlock();
317 // There are many things that can go wrong when creating
318 // a new endpoint, but BMidiEndpoint has no InitCheck()
319 // method to check for this. (You can, however, see if the
320 // endpoint's ID is 0 after the constructor returns, or
321 // call IsValid().) In any case, you should still Release()
322 // the endpoint to delete the object. (This is different
323 // from Be's implementation, which bumps the refcount only
324 // when creation succeeded. If you call Release(), you'll
325 // trip an assertion, so you can't delete these endpoints.)
329 void
330 BMidiRoster::DeleteLocal(BMidiEndpoint* endp)
332 ASSERT(endp != NULL)
334 BMessage msg;
335 msg.what = MSG_DELETE_ENDPOINT;
336 msg.AddInt32("midi:id", endp->ID());
338 // Note: this is always called from BMidiLocalConsumer's
339 // or BMidiLocalProducer's destructor, so we don't expect
340 // a reply from the server. If something went wrong, the
341 // object will be destroyed regardless.
343 fServer->SendMessage(&msg, (BHandler*) NULL, TIMEOUT);
345 // If the endpoint was successfully created, we must remove
346 // it from the list of endpoints. If creation failed, then
347 // we didn't put the endpoint on that list. If the endpoint
348 // was connected to anything, we must also disconnect it.
350 if (endp->ID() > 0) {
351 if (fLooper->Lock()) {
352 fLooper->RemoveEndpoint(endp);
353 fLooper->Unlock();
359 status_t
360 BMidiRoster::SendRequest(BMessage* msg, BMessage* reply)
362 ASSERT(msg != NULL)
363 ASSERT(reply != NULL)
365 status_t err = fServer->SendMessage(msg, reply, TIMEOUT, TIMEOUT);
367 if (err != B_OK) {
368 WARN("Cannot send request to midi_server");
371 #ifdef DEBUG
372 if (err == B_OK) {
373 printf("REPLY "); reply->PrintToStream();
375 #endif
377 return err;