1 /* 2 * Copyright 2001-2016, 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 <syslog.h> 16 17 #include <LaunchRoster.h> 18 #include <PortLink.h> 19 20 #include "BitmapManager.h" 21 #include "Desktop.h" 22 #include "FontManager.h" 23 #include "InputManager.h" 24 #include "ScreenManager.h" 25 #include "ServerProtocol.h" 26 27 28 //#define DEBUG_SERVER 29 #ifdef DEBUG_SERVER 30 # include <stdio.h> 31 # define STRACE(x) printf x 32 #else 33 # define STRACE(x) ; 34 #endif 35 36 37 // Globals 38 port_id gAppServerPort; 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(status_t* status) 50 : 51 SERVER_BASE("application/x-vnd.Haiku-app_server", "picasso", -1, false, 52 status), 53 fDesktopLock("AppServerDesktopLock") 54 { 55 openlog("app_server", 0, LOG_DAEMON); 56 57 gInputManager = new InputManager(); 58 59 // Create the font server and scan the proper directories. 60 gFontManager = new FontManager; 61 if (gFontManager->InitCheck() != B_OK) 62 debugger("font manager could not be initialized!"); 63 64 gFontManager->Run(); 65 66 gScreenManager = new ScreenManager(); 67 gScreenManager->Run(); 68 69 // Create the bitmap allocator. Object declared in BitmapManager.cpp 70 gBitmapManager = new BitmapManager(); 71 72 // TODO: check the attached displays, and launch login session for them 73 BMessage data; 74 data.AddString("name", "app_server"); 75 data.AddInt32("session", 0); 76 BLaunchRoster().Target("login", data); 77 } 78 79 80 /*! \brief Destructor 81 Reached only when the server is asked to shut down in Test mode. 82 */ 83 AppServer::~AppServer() 84 { 85 delete gBitmapManager; 86 87 gScreenManager->Lock(); 88 gScreenManager->Quit(); 89 90 gFontManager->Lock(); 91 gFontManager->Quit(); 92 93 closelog(); 94 } 95 96 97 void 98 AppServer::MessageReceived(BMessage* message) 99 { 100 switch (message->what) { 101 case AS_GET_DESKTOP: 102 { 103 Desktop* desktop = NULL; 104 105 int32 userID = message->GetInt32("user", 0); 106 int32 version = message->GetInt32("version", 0); 107 const char* targetScreen = message->GetString("target"); 108 109 if (version != AS_PROTOCOL_VERSION) { 110 syslog(LOG_ERR, "Application for user %" B_PRId32 " does not " 111 "support the current server protocol (%" B_PRId32 ").\n", 112 userID, version); 113 } else { 114 desktop = _FindDesktop(userID, targetScreen); 115 if (desktop == NULL) { 116 // we need to create a new desktop object for this user 117 // TODO: test if the user exists on the system 118 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for 119 // authorizing the user 120 desktop = _CreateDesktop(userID, targetScreen); 121 } 122 } 123 124 BMessage reply; 125 if (desktop != NULL) 126 reply.AddInt32("port", desktop->MessagePort()); 127 else 128 reply.what = (uint32)B_ERROR; 129 130 message->SendReply(&reply); 131 break; 132 } 133 134 default: 135 // We don't allow application scripting 136 STRACE(("AppServer received unexpected code %" B_PRId32 "\n", 137 message->what)); 138 break; 139 } 140 } 141 142 143 bool 144 AppServer::QuitRequested() 145 { 146 #if TEST_MODE 147 while (fDesktops.CountItems() > 0) { 148 Desktop *desktop = fDesktops.RemoveItemAt(0); 149 150 thread_id thread = desktop->Thread(); 151 desktop->PostMessage(B_QUIT_REQUESTED); 152 153 // we just wait for the desktop to kill itself 154 status_t status; 155 wait_for_thread(thread, &status); 156 } 157 158 delete this; 159 exit(0); 160 161 return SERVER_BASE::QuitRequested(); 162 #else 163 return false; 164 #endif 165 166 } 167 168 169 /*! \brief Creates a desktop object for an authorized user 170 */ 171 Desktop* 172 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen) 173 { 174 BAutolock locker(fDesktopLock); 175 Desktop* desktop = NULL; 176 try { 177 desktop = new Desktop(userID, targetScreen); 178 179 status_t status = desktop->Init(); 180 if (status == B_OK) 181 status = desktop->Run(); 182 if (status == B_OK && !fDesktops.AddItem(desktop)) 183 status = B_NO_MEMORY; 184 185 if (status != B_OK) { 186 syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n", 187 strerror(status)); 188 delete desktop; 189 return NULL; 190 } 191 } catch (...) { 192 // there is obviously no memory left 193 return NULL; 194 } 195 196 return desktop; 197 } 198 199 200 /*! \brief Finds the desktop object that belongs to a certain user 201 */ 202 Desktop* 203 AppServer::_FindDesktop(uid_t userID, const char* targetScreen) 204 { 205 BAutolock locker(fDesktopLock); 206 207 for (int32 i = 0; i < fDesktops.CountItems(); i++) { 208 Desktop* desktop = fDesktops.ItemAt(i); 209 210 if (desktop->UserID() == userID 211 && ((desktop->TargetScreen() == NULL && targetScreen == NULL) 212 || (desktop->TargetScreen() != NULL && targetScreen != NULL 213 && strcmp(desktop->TargetScreen(), targetScreen) == 0))) { 214 return desktop; 215 } 216 } 217 218 return NULL; 219 } 220 221 222 // #pragma mark - 223 224 225 int 226 main(int argc, char** argv) 227 { 228 srand(real_time_clock_usecs()); 229 230 status_t status; 231 AppServer* server = new AppServer(&status); 232 if (status == B_OK) 233 server->Run(); 234 235 return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE; 236 } 237