1 /* 2 * Copyright 2009, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include "RemoteHWInterface.h" 10 #include "RemoteDrawingEngine.h" 11 #include "RemoteEventStream.h" 12 #include "RemoteMessage.h" 13 14 #include "NetReceiver.h" 15 #include "NetSender.h" 16 #include "StreamingRingBuffer.h" 17 18 #include <Autolock.h> 19 #include <NetEndpoint.h> 20 21 #include <new> 22 #include <string.h> 23 24 25 #define TRACE(x...) /*debug_printf("RemoteHWInterface: "x)*/ 26 #define TRACE_ALWAYS(x...) debug_printf("RemoteHWInterface: "x) 27 #define TRACE_ERROR(x...) debug_printf("RemoteHWInterface: "x) 28 29 30 struct callback_info { 31 uint32 token; 32 RemoteHWInterface::CallbackFunction callback; 33 void* cookie; 34 }; 35 36 37 RemoteHWInterface::RemoteHWInterface(const char* target) 38 : 39 HWInterface(), 40 fTarget(target), 41 fRemoteHost(NULL), 42 fRemotePort(10900), 43 fIsConnected(false), 44 fProtocolVersion(100), 45 fConnectionSpeed(0), 46 fListenPort(10901), 47 fSendEndpoint(NULL), 48 fReceiveEndpoint(NULL), 49 fSendBuffer(NULL), 50 fReceiveBuffer(NULL), 51 fSender(NULL), 52 fReceiver(NULL), 53 fEventThread(-1), 54 fEventStream(NULL), 55 fCallbackLocker("callback locker") 56 { 57 fDisplayMode.virtual_width = 640; 58 fDisplayMode.virtual_height = 480; 59 fDisplayMode.space = B_RGB32; 60 61 fRemoteHost = strdup(fTarget); 62 char *portStart = strchr(fRemoteHost, ':'); 63 if (portStart != NULL) { 64 portStart[0] = 0; 65 portStart++; 66 if (sscanf(portStart, "%lu", &fRemotePort) != 1) { 67 fInitStatus = B_BAD_VALUE; 68 return; 69 } 70 71 fListenPort = fRemotePort + 1; 72 } 73 74 fSendEndpoint = new(std::nothrow) BNetEndpoint(); 75 if (fSendEndpoint == NULL) { 76 fInitStatus = B_NO_MEMORY; 77 return; 78 } 79 80 fReceiveEndpoint = new(std::nothrow) BNetEndpoint(); 81 if (fReceiveEndpoint == NULL) { 82 fInitStatus = B_NO_MEMORY; 83 return; 84 } 85 86 fInitStatus = fReceiveEndpoint->Bind(fListenPort); 87 if (fInitStatus != B_OK) 88 return; 89 90 fSendBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024); 91 if (fSendBuffer == NULL) { 92 fInitStatus = B_NO_MEMORY; 93 return; 94 } 95 96 fInitStatus = fSendBuffer->InitCheck(); 97 if (fInitStatus != B_OK) 98 return; 99 100 fReceiveBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024); 101 if (fReceiveBuffer == NULL) { 102 fInitStatus = B_NO_MEMORY; 103 return; 104 } 105 106 fInitStatus = fReceiveBuffer->InitCheck(); 107 if (fInitStatus != B_OK) 108 return; 109 110 fSender = new(std::nothrow) NetSender(fSendEndpoint, fSendBuffer); 111 if (fSender == NULL) { 112 fInitStatus = B_NO_MEMORY; 113 return; 114 } 115 116 fReceiver = new(std::nothrow) NetReceiver(fReceiveEndpoint, fReceiveBuffer); 117 if (fReceiver == NULL) { 118 fInitStatus = B_NO_MEMORY; 119 return; 120 } 121 122 fEventStream = new(std::nothrow) RemoteEventStream(); 123 if (fEventStream == NULL) { 124 fInitStatus = B_NO_MEMORY; 125 return; 126 } 127 128 fSendEndpoint->SetTimeout(3 * 1000 * 1000); 129 fInitStatus = _Connect(); 130 if (fInitStatus != B_OK) 131 return; 132 133 fEventThread = spawn_thread(_EventThreadEntry, "remote event thread", 134 B_NORMAL_PRIORITY, this); 135 if (fEventThread < 0) { 136 fInitStatus = fEventThread; 137 return; 138 } 139 140 resume_thread(fEventThread); 141 } 142 143 144 RemoteHWInterface::~RemoteHWInterface() 145 { 146 delete fReceiver; 147 delete fReceiveBuffer; 148 149 delete fSendBuffer; 150 delete fSender; 151 152 delete fReceiveEndpoint; 153 delete fSendEndpoint; 154 155 delete fEventStream; 156 157 free(fRemoteHost); 158 } 159 160 161 status_t 162 RemoteHWInterface::Initialize() 163 { 164 return fInitStatus; 165 } 166 167 168 status_t 169 RemoteHWInterface::Shutdown() 170 { 171 _Disconnect(); 172 return B_OK; 173 } 174 175 176 DrawingEngine* 177 RemoteHWInterface::CreateDrawingEngine() 178 { 179 return new(std::nothrow) RemoteDrawingEngine(this); 180 } 181 182 183 EventStream* 184 RemoteHWInterface::CreateEventStream() 185 { 186 return fEventStream; 187 } 188 189 190 status_t 191 RemoteHWInterface::AddCallback(uint32 token, CallbackFunction callback, 192 void* cookie) 193 { 194 BAutolock lock(fCallbackLocker); 195 int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare); 196 if (index >= 0) 197 return B_NAME_IN_USE; 198 199 callback_info* info = new(std::nothrow) callback_info; 200 if (info == NULL) 201 return B_NO_MEMORY; 202 203 info->token = token; 204 info->callback = callback; 205 info->cookie = cookie; 206 207 fCallbacks.AddItem(info, -index - 1); 208 return B_OK; 209 } 210 211 212 bool 213 RemoteHWInterface::RemoveCallback(uint32 token) 214 { 215 BAutolock lock(fCallbackLocker); 216 int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare); 217 if (index < 0) 218 return false; 219 220 delete fCallbacks.RemoveItemAt(index); 221 return true; 222 } 223 224 225 callback_info* 226 RemoteHWInterface::_FindCallback(uint32 token) 227 { 228 BAutolock lock(fCallbackLocker); 229 return fCallbacks.BinarySearchByKey(token, &_CallbackCompare); 230 } 231 232 233 int 234 RemoteHWInterface::_CallbackCompare(const uint32* key, 235 const callback_info* info) 236 { 237 if (info->token == *key) 238 return 0; 239 240 if (info->token < *key) 241 return -1; 242 243 return 1; 244 } 245 246 247 int32 248 RemoteHWInterface::_EventThreadEntry(void* data) 249 { 250 return ((RemoteHWInterface*)data)->_EventThread(); 251 } 252 253 254 status_t 255 RemoteHWInterface::_EventThread() 256 { 257 RemoteMessage message(fReceiveBuffer, fSendBuffer); 258 while (true) { 259 uint16 code; 260 status_t result = message.NextMessage(code); 261 if (result != B_OK) { 262 TRACE_ERROR("failed to read message from receiver: %s\n", 263 strerror(result)); 264 return result; 265 } 266 267 TRACE("got message code %u with %lu bytes\n", code, message.DataLeft()); 268 269 if (code >= RP_MOUSE_MOVED && code <= RP_MODIFIERS_CHANGED) { 270 // an input event, dispatch to the event stream 271 if (fEventStream->EventReceived(message)) 272 continue; 273 } 274 275 switch (code) { 276 case RP_UPDATE_DISPLAY_MODE: 277 { 278 // TODO: implement, we only handle it in the context of the 279 // initial mode setup on connect 280 break; 281 } 282 283 default: 284 { 285 uint32 token; 286 if (message.Read(token) == B_OK) { 287 callback_info* info = _FindCallback(token); 288 if (info != NULL && info->callback(info->cookie, message)) 289 break; 290 } 291 292 TRACE_ERROR("unhandled remote event code %u\n", code); 293 break; 294 } 295 } 296 } 297 } 298 299 300 status_t 301 RemoteHWInterface::_Connect() 302 { 303 TRACE("connecting to host \"%s\" port %lu\n", fRemoteHost, fRemotePort); 304 status_t result = fSendEndpoint->Connect(fRemoteHost, (uint16)fRemotePort); 305 if (result != B_OK) { 306 TRACE_ERROR("failed to connect to host \"%s\" port %lu\n", fRemoteHost, 307 fRemotePort); 308 return result; 309 } 310 311 RemoteMessage message(fReceiveBuffer, fSendBuffer); 312 message.Start(RP_INIT_CONNECTION); 313 message.Add(fListenPort); 314 result = message.Flush(); 315 if (result != B_OK) { 316 TRACE_ERROR("failed to send init connection message\n"); 317 return result; 318 } 319 320 uint16 code; 321 result = message.NextMessage(code); 322 if (result != B_OK) { 323 TRACE_ERROR("failed to read message from receiver: %s\n", 324 strerror(result)); 325 return result; 326 } 327 328 TRACE("code %u with %lu bytes of data\n", code, message.DataLeft()); 329 if (code != RP_UPDATE_DISPLAY_MODE) { 330 TRACE_ERROR("invalid connection init code %u\n", code); 331 return B_ERROR; 332 } 333 334 int32 width, height; 335 message.Read(width); 336 result = message.Read(height); 337 if (result != B_OK) { 338 TRACE_ERROR("failed to get initial display mode\n"); 339 return result; 340 } 341 342 fDisplayMode.virtual_width = width; 343 fDisplayMode.virtual_height = height; 344 return B_OK; 345 } 346 347 348 void 349 RemoteHWInterface::_Disconnect() 350 { 351 if (fIsConnected) { 352 RemoteMessage message(NULL, fSendBuffer); 353 message.Start(RP_CLOSE_CONNECTION); 354 message.Flush(); 355 fIsConnected = false; 356 } 357 358 if (fSendEndpoint != NULL) 359 fSendEndpoint->Close(); 360 if (fReceiveEndpoint != NULL) 361 fReceiveEndpoint->Close(); 362 } 363 364 365 status_t 366 RemoteHWInterface::SetMode(const display_mode& mode) 367 { 368 // The display mode depends on the screen resolution of the client, we 369 // don't allow to change it. 370 return B_UNSUPPORTED; 371 } 372 373 374 void 375 RemoteHWInterface::GetMode(display_mode* mode) 376 { 377 if (mode == NULL || !ReadLock()) 378 return; 379 380 *mode = fDisplayMode; 381 ReadUnlock(); 382 } 383 384 385 status_t 386 RemoteHWInterface::GetDeviceInfo(accelerant_device_info* info) 387 { 388 if (!ReadLock()) 389 return B_ERROR; 390 391 info->version = fProtocolVersion; 392 info->dac_speed = fConnectionSpeed; 393 info->memory = 33554432; // 32MB 394 snprintf(info->name, sizeof(info->name), "Haiku, Inc. RemoteHWInterface"); 395 snprintf(info->chipset, sizeof(info->chipset), "Haiku, Inc. Chipset"); 396 snprintf(info->serial_no, sizeof(info->serial_no), fTarget); 397 398 ReadUnlock(); 399 return B_OK; 400 } 401 402 403 status_t 404 RemoteHWInterface::GetFrameBufferConfig(frame_buffer_config& config) 405 { 406 // We don't actually have a frame buffer. 407 return B_UNSUPPORTED; 408 } 409 410 411 status_t 412 RemoteHWInterface::GetModeList(display_mode** _modes, uint32* _count) 413 { 414 AutoReadLocker _(this); 415 416 display_mode* modes = new(std::nothrow) display_mode[1]; 417 if (modes == NULL) 418 return B_NO_MEMORY; 419 420 modes[0] = fDisplayMode; 421 *_modes = modes; 422 *_count = 1; 423 return B_OK; 424 } 425 426 427 status_t 428 RemoteHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low, 429 uint32* high) 430 { 431 return B_UNSUPPORTED; 432 } 433 434 435 status_t 436 RemoteHWInterface::GetTimingConstraints(display_timing_constraints* constraints) 437 { 438 return B_UNSUPPORTED; 439 } 440 441 442 status_t 443 RemoteHWInterface::ProposeMode(display_mode* candidate, const display_mode* low, 444 const display_mode* high) 445 { 446 return B_UNSUPPORTED; 447 } 448 449 450 status_t 451 RemoteHWInterface::SetDPMSMode(uint32 state) 452 { 453 return B_UNSUPPORTED; 454 } 455 456 457 uint32 458 RemoteHWInterface::DPMSMode() 459 { 460 return B_UNSUPPORTED; 461 } 462 463 464 uint32 465 RemoteHWInterface::DPMSCapabilities() 466 { 467 return 0; 468 } 469 470 471 sem_id 472 RemoteHWInterface::RetraceSemaphore() 473 { 474 return -1; 475 } 476 477 478 status_t 479 RemoteHWInterface::WaitForRetrace(bigtime_t timeout) 480 { 481 return B_UNSUPPORTED; 482 } 483 484 485 void 486 RemoteHWInterface::SetCursor(ServerCursor* cursor) 487 { 488 HWInterface::SetCursor(cursor); 489 RemoteMessage message(NULL, fSendBuffer); 490 message.Start(RP_SET_CURSOR); 491 message.AddCursor(Cursor().Get()); 492 } 493 494 495 void 496 RemoteHWInterface::SetCursorVisible(bool visible) 497 { 498 HWInterface::SetCursorVisible(visible); 499 RemoteMessage message(NULL, fSendBuffer); 500 message.Start(RP_SET_CURSOR_VISIBLE); 501 message.Add(visible); 502 } 503 504 505 void 506 RemoteHWInterface::MoveCursorTo(float x, float y) 507 { 508 HWInterface::MoveCursorTo(x, y); 509 RemoteMessage message(NULL, fSendBuffer); 510 message.Start(RP_MOVE_CURSOR_TO); 511 message.Add(x); 512 message.Add(y); 513 } 514 515 516 void 517 RemoteHWInterface::SetDragBitmap(const ServerBitmap* bitmap, 518 const BPoint& offsetFromCursor) 519 { 520 HWInterface::SetDragBitmap(bitmap, offsetFromCursor); 521 RemoteMessage message(NULL, fSendBuffer); 522 message.Start(RP_SET_CURSOR); 523 message.AddCursor(CursorAndDragBitmap().Get()); 524 } 525 526 527 RenderingBuffer* 528 RemoteHWInterface::FrontBuffer() const 529 { 530 return NULL; 531 } 532 533 534 RenderingBuffer* 535 RemoteHWInterface::BackBuffer() const 536 { 537 return NULL; 538 } 539 540 541 bool 542 RemoteHWInterface::IsDoubleBuffered() const 543 { 544 return false; 545 } 546 547 548 status_t 549 RemoteHWInterface::InvalidateRegion(BRegion& region) 550 { 551 RemoteMessage message(NULL, fSendBuffer); 552 message.Start(RP_INVALIDATE_REGION); 553 message.AddRegion(region); 554 return B_OK; 555 } 556 557 558 status_t 559 RemoteHWInterface::Invalidate(const BRect& frame) 560 { 561 RemoteMessage message(NULL, fSendBuffer); 562 message.Start(RP_INVALIDATE_RECT); 563 message.Add(frame); 564 return B_OK; 565 } 566 567 568 status_t 569 RemoteHWInterface::CopyBackToFront(const BRect& frame) 570 { 571 return B_OK; 572 } 573