1 /* 2 * Copyright 2001-2011, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Christian Packmann 10 */ 11 12 13 #include "AppServer.h" 14 15 #include "BitmapManager.h" 16 #include "Desktop.h" 17 #include "FontManager.h" 18 #include "InputManager.h" 19 #include "ScreenManager.h" 20 #include "ServerProtocol.h" 21 22 #include <PortLink.h> 23 24 #include <syslog.h> 25 26 27 //#define DEBUG_SERVER 28 #ifdef DEBUG_SERVER 29 # include <stdio.h> 30 # define STRACE(x) printf x 31 #else 32 # define STRACE(x) ; 33 #endif 34 35 36 // Globals 37 port_id gAppServerPort; 38 static AppServer* sAppServer; 39 BTokenSpace gTokenSpace; 40 uint32 gAppServerSIMDFlags = 0; 41 42 43 /*! \brief Constructor 44 45 This loads the default fonts, allocates all the major global variables, 46 spawns the main housekeeping threads, loads user preferences for the UI 47 and decorator, and allocates various locks. 48 */ 49 AppServer::AppServer() 50 : 51 MessageLooper("app_server"), 52 fMessagePort(-1), 53 fDesktops(), 54 fDesktopLock("AppServerDesktopLock") 55 { 56 openlog("app_server", 0, LOG_DAEMON); 57 58 fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, SERVER_PORT_NAME); 59 if (fMessagePort < B_OK) 60 debugger("app_server could not create message port"); 61 62 fLink.SetReceiverPort(fMessagePort); 63 64 sAppServer = this; 65 66 gInputManager = new InputManager(); 67 68 // Create the font server and scan the proper directories. 69 gFontManager = new FontManager; 70 if (gFontManager->InitCheck() != B_OK) 71 debugger("font manager could not be initialized!"); 72 73 gFontManager->Run(); 74 75 gScreenManager = new ScreenManager(); 76 gScreenManager->Run(); 77 78 // Create the bitmap allocator. Object declared in BitmapManager.cpp 79 gBitmapManager = new BitmapManager(); 80 } 81 82 83 /*! \brief Destructor 84 Reached only when the server is asked to shut down in Test mode. 85 */ 86 AppServer::~AppServer() 87 { 88 delete gBitmapManager; 89 90 gScreenManager->Lock(); 91 gScreenManager->Quit(); 92 93 gFontManager->Lock(); 94 gFontManager->Quit(); 95 96 closelog(); 97 } 98 99 100 void 101 AppServer::RunLooper() 102 { 103 rename_thread(find_thread(NULL), "picasso"); 104 _message_thread((void*)this); 105 } 106 107 108 /*! \brief Creates a desktop object for an authorized user 109 */ 110 Desktop* 111 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen) 112 { 113 BAutolock locker(fDesktopLock); 114 Desktop* desktop = NULL; 115 try { 116 desktop = new Desktop(userID, targetScreen); 117 118 status_t status = desktop->Init(); 119 if (status == B_OK) { 120 if (!desktop->Run()) 121 status = B_ERROR; 122 } 123 if (status == B_OK && !fDesktops.AddItem(desktop)) 124 status = B_NO_MEMORY; 125 126 if (status != B_OK) { 127 syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n", 128 strerror(status)); 129 delete desktop; 130 return NULL; 131 } 132 } catch (...) { 133 // there is obviously no memory left 134 return NULL; 135 } 136 137 return desktop; 138 } 139 140 141 /*! \brief Finds the desktop object that belongs to a certain user 142 */ 143 Desktop* 144 AppServer::_FindDesktop(uid_t userID, const char* targetScreen) 145 { 146 BAutolock locker(fDesktopLock); 147 148 for (int32 i = 0; i < fDesktops.CountItems(); i++) { 149 Desktop* desktop = fDesktops.ItemAt(i); 150 151 if (desktop->UserID() == userID 152 && ((desktop->TargetScreen() == NULL && targetScreen == NULL) 153 || (desktop->TargetScreen() != NULL && targetScreen != NULL 154 && strcmp(desktop->TargetScreen(), targetScreen) == 0))) { 155 return desktop; 156 } 157 } 158 159 return NULL; 160 } 161 162 163 /*! \brief Message handling function for all messages sent to the app_server 164 \param code ID of the message sent 165 \param buffer Attachment buffer for the message. 166 167 */ 168 void 169 AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg) 170 { 171 switch (code) { 172 case AS_GET_DESKTOP: 173 { 174 Desktop* desktop = NULL; 175 176 port_id replyPort; 177 msg.Read<port_id>(&replyPort); 178 179 int32 userID; 180 msg.Read<int32>(&userID); 181 182 char* targetScreen = NULL; 183 msg.ReadString(&targetScreen); 184 if (targetScreen != NULL && strlen(targetScreen) == 0) { 185 free(targetScreen); 186 targetScreen = NULL; 187 } 188 189 int32 version; 190 if (msg.Read<int32>(&version) < B_OK 191 || version != AS_PROTOCOL_VERSION) { 192 syslog(LOG_ERR, "Application for user %" B_PRId32 " with port " 193 "%" B_PRId32 " does not support the current server " 194 "protocol.\n", userID, replyPort); 195 } else { 196 desktop = _FindDesktop(userID, targetScreen); 197 if (desktop == NULL) { 198 // we need to create a new desktop object for this user 199 // TODO: test if the user exists on the system 200 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for 201 // authorizing the user 202 desktop = _CreateDesktop(userID, targetScreen); 203 } 204 } 205 206 free(targetScreen); 207 208 BPrivate::LinkSender reply(replyPort); 209 if (desktop != NULL) { 210 reply.StartMessage(B_OK); 211 reply.Attach<port_id>(desktop->MessagePort()); 212 } else 213 reply.StartMessage(B_ERROR); 214 215 reply.Flush(); 216 break; 217 } 218 219 #if TEST_MODE 220 case B_QUIT_REQUESTED: 221 { 222 // We've been asked to quit, so (for now) broadcast to all 223 // desktops to quit. This situation will occur only when the server 224 // is compiled as a regular Be application. 225 226 fQuitting = true; 227 228 while (fDesktops.CountItems() > 0) { 229 Desktop *desktop = fDesktops.RemoveItemAt(0); 230 231 thread_id thread = desktop->Thread(); 232 desktop->PostMessage(B_QUIT_REQUESTED); 233 234 // we just wait for the desktop to kill itself 235 status_t status; 236 wait_for_thread(thread, &status); 237 } 238 239 delete this; 240 241 // we are now clear to exit 242 exit(0); 243 break; 244 } 245 #endif 246 247 default: 248 STRACE(("Server::MainLoop received unexpected code %" B_PRId32 " " 249 "(offset %" B_PRId32 ")\n", code, code - SERVER_TRUE)); 250 break; 251 } 252 } 253 254 255 // #pragma mark - 256 257 258 int 259 main(int argc, char** argv) 260 { 261 // There can be only one.... 262 if (find_port(SERVER_PORT_NAME) >= B_OK) 263 return -1; 264 265 srand(real_time_clock_usecs()); 266 267 AppServer* server = new AppServer; 268 server->RunLooper(); 269 270 return 0; 271 } 272