1 /* 2 * Copyright 2001-2005, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Adrian Oanca <adioanca@cotty.iren.ro> 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Stefano Ceccherini (burton666@libero.it) 10 * Axel Dörfler, axeld@pinc-software.de 11 */ 12 13 14 #include <AppDefs.h> 15 #include <List.h> 16 #include <String.h> 17 #include <ColorSet.h> 18 #include <RGBColor.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <ScrollBar.h> 22 #include <Shape.h> 23 #include <ServerProtocol.h> 24 25 #include "AppServer.h" 26 #include "BitmapManager.h" 27 #include "BGet++.h" 28 29 #include "ServerApp.h" 30 #include "ServerCursor.h" 31 #include "ServerBitmap.h" 32 #include "ServerConfig.h" 33 #include "SystemPalette.h" 34 #include "Utils.h" 35 36 //#define DEBUG_SERVERAPP 37 38 #ifdef DEBUG_SERVERAPP 39 # include <stdio.h> 40 # define STRACE(x) printf x 41 #else 42 # define STRACE(x) ; 43 #endif 44 45 //#define DEBUG_SERVERAPP_FONT 46 47 #ifdef DEBUG_SERVERAPP_FONT 48 # include <stdio.h> 49 # define FTRACE(x) printf x 50 #else 51 # define FTRACE(x) ; 52 #endif 53 54 /*! 55 \brief Constructor 56 \param sendport port ID for the BApplication which will receive the ServerApp's messages 57 \param rcvport port by which the ServerApp will receive messages from its BApplication. 58 \param fSignature NULL-terminated string which contains the BApplication's 59 MIME fSignature. 60 */ 61 ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort, 62 team_id clientTeamID, int32 handlerID, const char* signature) 63 : 64 fClientAppPort(sendport), 65 fMessagePort(rcvport), 66 fClientLooperPort(clientLooperPort), 67 fSignature(signature), 68 fMonitorThreadID(-1), 69 fClientTeamID(clientTeamID), 70 fLink(fClientAppPort, fMessagePort), 71 fSWindowList(new BList()), 72 fBitmapList(new BList()), 73 fPictureList(new BList()), 74 fAppCursor(NULL), 75 fLockSem(create_sem(1, "ServerApp sem")), 76 fCursorHidden(false), 77 fIsActive(false), 78 //fHandlerToken(handlerID), 79 fSharedMem(new AreaPool), 80 fQuitting(false) 81 { 82 if (fSignature == "") 83 fSignature = "application/x-vnd.NULL-application-signature"; 84 85 Run(); 86 87 STRACE(("ServerApp %s:\n", fSignature.String())); 88 STRACE(("\tBApp port: %ld\n", fClientAppPort)); 89 STRACE(("\tReceiver port: %ld\n", fMessagePort)); 90 } 91 92 93 //! Does all necessary teardown for application 94 ServerApp::~ServerApp(void) 95 { 96 STRACE(("*ServerApp %s:~ServerApp()\n",fSignature.String())); 97 98 fQuitting = true; 99 100 for (int32 i = 0; i< fBitmapList->CountItems(); i++) { 101 delete static_cast<ServerBitmap *>(fBitmapList->ItemAt(i)); 102 } 103 delete fBitmapList; 104 105 delete fPictureList; 106 107 // This shouldn't be necessary -- all cursors owned by the app 108 // should be cleaned up by RemoveAppCursors 109 // if(fAppCursor) 110 // delete fAppCursor; 111 112 delete_sem(fLockSem); 113 114 STRACE(("#ServerApp %s:~ServerApp()\n", fSignature.String())); 115 116 // TODO: Is this the right place for this ? 117 // From what I've understood, this is the port created by 118 // the BApplication (?), but if I delete it in there, GetNextMessage() 119 // in the MonitorApp thread never returns. Cleanup. 120 delete_port(fMessagePort); 121 122 status_t dummyStatus; 123 wait_for_thread(fMonitorThreadID, &dummyStatus); 124 125 delete fSharedMem; 126 127 STRACE(("ServerApp %s::~ServerApp(): Exiting\n", fSignature.String())); 128 } 129 130 /*! 131 \brief Starts the ServerApp monitoring for messages 132 \return false if the application couldn't start, true if everything went OK. 133 */ 134 bool 135 ServerApp::Run(void) 136 { 137 // Unlike a BApplication, a ServerApp is *supposed* to return immediately 138 // when its Run() function is called. 139 fMonitorThreadID = spawn_thread(MonitorApp, fSignature.String(), B_NORMAL_PRIORITY, this); 140 if (fMonitorThreadID < B_OK) 141 return false; 142 143 return resume_thread(fMonitorThreadID) == B_OK; 144 } 145 146 /*! 147 \brief Pings the target app to make sure it's still working 148 \return true if target is still "alive" and false if "He's dead, Jim." 149 "But that's impossible..." 150 151 This function is called by the app_server thread to ensure that 152 the target app still exists. We do this not by sending a message 153 but by calling get_port_info. We don't want to send ping messages 154 just because the app might simply be hung. If this is the case, it 155 should be up to the user to kill it. If the app has been killed, its 156 ports will be invalid. Thus, if get_port_info returns an error, we 157 tell the app_server to delete the respective ServerApp. 158 */ 159 bool 160 ServerApp::PingTarget(void) 161 { 162 team_info tinfo; 163 if (get_team_info(fClientTeamID, &tinfo) == B_BAD_TEAM_ID) { 164 BPrivate::LinkSender link(gAppServerPort); 165 link.StartMessage(AS_DELETE_APP); 166 link.Attach(&fMonitorThreadID, sizeof(thread_id)); 167 link.Flush(); 168 return false; 169 } 170 return true; 171 } 172 173 /*! 174 \brief Send a message to the ServerApp with no attachments 175 \param code ID code of the message to post 176 */ 177 void 178 ServerApp::PostMessage(int32 code) 179 { 180 BPrivate::LinkSender link(fMessagePort); 181 link.StartMessage(code); 182 link.Flush(); 183 } 184 185 /*! 186 \brief Send a message to the ServerApp's BApplication 187 \param msg The message to send 188 */ 189 void 190 ServerApp::SendMessageToClient(const BMessage *msg) const 191 { 192 ssize_t size = msg->FlattenedSize(); 193 char *buffer = new char[size]; 194 195 if (msg->Flatten(buffer, size) == B_OK) 196 write_port(fClientLooperPort, msg->what, buffer, size); 197 else 198 printf("PANIC: ServerApp: '%s': can't flatten message in 'SendMessageToClient()'\n", fSignature.String()); 199 200 delete [] buffer; 201 } 202 203 /*! 204 \brief Sets the ServerApp's active status 205 \param value The new status of the ServerApp. 206 207 This changes an internal flag and also sets the current cursor to the one specified by 208 the application 209 */ 210 void 211 ServerApp::Activate(bool value) 212 { 213 fIsActive = value; 214 SetAppCursor(); 215 } 216 217 218 //! Sets the cursor to the application cursor, if any. 219 void 220 ServerApp::SetAppCursor(void) 221 { 222 } 223 224 225 /*! 226 \brief The thread function ServerApps use to monitor messages 227 \param data Pointer to the thread's ServerApp object 228 \return Throwaway value - always 0 229 */ 230 int32 231 ServerApp::MonitorApp(void *data) 232 { 233 // Message-dispatching loop for the ServerApp 234 235 ServerApp *app = (ServerApp *)data; 236 BPrivate::LinkReceiver &reader = app->fLink.Receiver(); 237 238 int32 code; 239 status_t err = B_OK; 240 241 while (!app->fQuitting) { 242 STRACE(("info: ServerApp::MonitorApp listening on port %ld.\n", app->fMessagePort)); 243 err = reader.GetNextMessage(code, B_INFINITE_TIMEOUT); 244 if (err < B_OK) { 245 STRACE(("ServerApp::MonitorApp(): GetNextMessage returned %s\n", strerror(err))); 246 247 // ToDo: this should kill the app, but it doesn't work 248 BPrivate::LinkSender link(gAppServerPort); 249 link.StartMessage(AS_DELETE_APP); 250 link.Attach(&app->fMonitorThreadID, sizeof(thread_id)); 251 link.Flush(); 252 break; 253 } 254 255 switch (code) { 256 case AS_QUIT_APP: 257 { 258 // This message is received only when the app_server is asked to shut down in 259 // test/debug mode. Of course, if we are testing while using AccelerantDriver, we do 260 // NOT want to shut down client applications. The server can be quit o in this fashion 261 // through the driver's interface, such as closing the ViewDriver's window. 262 263 STRACE(("ServerApp %s:Server shutdown notification received\n", 264 app->fSignature.String())); 265 266 // If we are using the real, accelerated version of the 267 // DisplayDriver, we do NOT want the user to be able shut down 268 // the server. The results would NOT be pretty 269 break; 270 } 271 272 case B_QUIT_REQUESTED: 273 { 274 STRACE(("ServerApp %s: B_QUIT_REQUESTED\n",app->fSignature.String())); 275 // Our BApplication sent us this message when it quit. 276 // We need to ask the app_server to delete ourself. 277 BPrivate::LinkSender sender(gAppServerPort); 278 sender.StartMessage(AS_DELETE_APP); 279 sender.Attach(&app->fMonitorThreadID, sizeof(thread_id)); 280 sender.Flush(); 281 break; 282 } 283 284 default: 285 STRACE(("ServerApp %s: Got a Message to dispatch\n", app->fSignature.String())); 286 app->DispatchMessage(code, reader); 287 break; 288 } 289 } 290 291 return 0; 292 } 293 294 295 /*! 296 \brief Handler function for BApplication API messages 297 \param code Identifier code for the message. Equivalent to BMessage::what 298 \param buffer Any attachments 299 300 Note that the buffer's exact format is determined by the particular message. 301 All attachments are placed in the buffer via a PortLink, so it will be a 302 matter of casting and incrementing an index variable to access them. 303 */ 304 void 305 ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link) 306 { 307 switch (code) { 308 case AS_ACQUIRE_SERVERMEM: 309 { 310 // This particular call is more than a bit of a pain in the neck. We are given a 311 // size of a chunk of memory needed. We need to (1) allocate it, (2) get the area for 312 // this particular chunk, (3) find the offset in the area for this chunk, and (4) 313 // tell the client about it. Good thing this particular call isn't used much 314 315 // Received from a ServerMemIO object requesting operating memory 316 // Attached Data: 317 // 1) size_t requested size 318 // 2) port_id reply_port 319 320 size_t memsize; 321 link.Read<size_t>(&memsize); 322 323 // TODO: I wonder if ACQUIRE_SERVERMEM should have a minimum size requirement? 324 325 void *sharedmem = fSharedMem->GetBuffer(memsize); 326 327 if (memsize < 1 || sharedmem == NULL) { 328 fLink.StartMessage(SERVER_FALSE); 329 fLink.Flush(); 330 break; 331 } 332 333 area_id owningArea = area_for(sharedmem); 334 area_info info; 335 336 if (owningArea == B_ERROR || get_area_info(owningArea, &info) < B_OK) { 337 fLink.StartMessage(SERVER_FALSE); 338 fLink.Flush(); 339 break; 340 } 341 342 int32 areaoffset = (addr_t)sharedmem - (addr_t)info.address; 343 STRACE(("Successfully allocated shared memory of size %ld\n",memsize)); 344 345 fLink.StartMessage(SERVER_TRUE); 346 fLink.Attach<area_id>(owningArea); 347 fLink.Attach<int32>(areaoffset); 348 fLink.Flush(); 349 break; 350 } 351 case AS_RELEASE_SERVERMEM: 352 { 353 // Received when a ServerMemIO object on destruction 354 // Attached Data: 355 // 1) area_id owning area 356 // 2) int32 area offset 357 358 area_id owningArea; 359 int32 areaoffset; 360 361 link.Read<area_id>(&owningArea); 362 link.Read<int32>(&areaoffset); 363 364 area_info areaInfo; 365 if (owningArea < 0 || get_area_info(owningArea, &areaInfo) != B_OK) 366 break; 367 368 STRACE(("Successfully freed shared memory\n")); 369 void *sharedmem = ((int32*)areaInfo.address) + areaoffset; 370 371 fSharedMem->ReleaseBuffer(sharedmem); 372 373 break; 374 } 375 376 case AS_CURRENT_WORKSPACE: 377 { 378 STRACE(("ServerApp %s: get current workspace\n", fSignature.String())); 379 380 // TODO: Locking this way is not nice 381 fLink.StartMessage(SERVER_TRUE); 382 fLink.Attach<int32>(0); 383 fLink.Flush(); 384 break; 385 } 386 387 case AS_ACTIVATE_WORKSPACE: 388 { 389 STRACE(("ServerApp %s: activate workspace\n", fSignature.String())); 390 391 // TODO: See above 392 int32 index; 393 link.Read<int32>(&index); 394 // no reply 395 396 break; 397 } 398 399 case AS_QUERY_CURSOR_HIDDEN: 400 { 401 STRACE(("ServerApp %s: Received IsCursorHidden request\n", fSignature.String())); 402 // Attached data 403 // 1) int32 port to reply to 404 fLink.StartMessage(fCursorHidden ? SERVER_TRUE : SERVER_FALSE); 405 fLink.Flush(); 406 break; 407 } 408 409 default: 410 printf("ServerApp %s received unhandled message code offset %lx\n", 411 fSignature.String(), code); 412 413 if (link.NeedsReply()) { 414 // the client is now blocking and waiting for a reply! 415 fLink.StartMessage(SERVER_FALSE); 416 fLink.Flush(); 417 } else 418 puts("message doesn't need a reply!"); 419 break; 420 } 421 } 422 423 424 int32 425 ServerApp::CountBitmaps() const 426 { 427 return fBitmapList ? fBitmapList->CountItems() : 0; 428 } 429 430 431 /*! 432 \brief Looks up a ServerApp's ServerBitmap in its list 433 \param token ID token of the bitmap to find 434 \return The bitmap having that ID or NULL if not found 435 */ 436 ServerBitmap * 437 ServerApp::FindBitmap(int32 token) const 438 { 439 ServerBitmap *bitmap; 440 for (int32 i = 0; i < fBitmapList->CountItems(); i++) { 441 bitmap = static_cast<ServerBitmap *>(fBitmapList->ItemAt(i)); 442 if (bitmap && bitmap->Token() == token) 443 return bitmap; 444 } 445 446 return NULL; 447 } 448 449 450 int32 451 ServerApp::CountPictures() const 452 { 453 return fPictureList ? fPictureList->CountItems() : 0; 454 } 455 456 457 ServerPicture * 458 ServerApp::FindPicture(int32 token) const 459 { 460 return NULL; 461 } 462 463 464 team_id 465 ServerApp::ClientTeamID() const 466 { 467 return fClientTeamID; 468 } 469 470 471 thread_id 472 ServerApp::MonitorThreadID() const 473 { 474 return fMonitorThreadID; 475 } 476 477