diff options
Diffstat (limited to 'server/Mac/mf_peer.c')
-rw-r--r-- | server/Mac/mf_peer.c | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/server/Mac/mf_peer.c b/server/Mac/mf_peer.c new file mode 100644 index 0000000..0669127 --- /dev/null +++ b/server/Mac/mf_peer.c @@ -0,0 +1,485 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Mac OS X Server + * + * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <freerdp/config.h> + +#include <freerdp/listener.h> +#include <freerdp/codec/rfx.h> +#include <winpr/stream.h> +#include <freerdp/peer.h> +#include <freerdp/codec/color.h> + +#include <winpr/crt.h> +#include <winpr/assert.h> + +#include "mf_peer.h" +#include "mf_info.h" +#include "mf_input.h" +#include "mf_event.h" +#include "mf_rdpsnd.h" +#include "mf_audin.h" + +#include <mach/clock.h> +#include <mach/mach.h> +#include <dispatch/dispatch.h> + +#include "OpenGL/OpenGL.h" +#include "OpenGL/gl.h" + +#include "CoreVideo/CoreVideo.h" + +#include <freerdp/log.h> +#define TAG SERVER_TAG("mac") + +// refactor these +static int info_last_sec = 0; +static int info_last_nsec = 0; + +static dispatch_source_t info_timer; +static dispatch_queue_t info_queue; + +static mfEventQueue* info_event_queue; + +static CGLContextObj glContext; +static CGContextRef bmp; +static CGImageRef img; + +static void mf_peer_context_free(freerdp_peer* client, rdpContext* context); + +static BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) +{ + if (info_event_queue->pipe_fd[0] == -1) + return TRUE; + + rfds[*rcount] = (void*)(long)info_event_queue->pipe_fd[0]; + (*rcount)++; + return TRUE; +} + +static void mf_peer_rfx_update(freerdp_peer* client) +{ + // check + mfInfo* mfi = mf_info_get_instance(); + mf_info_find_invalid_region(mfi); + + if (mf_info_have_invalid_region(mfi) == false) + { + return; + } + + long width; + long height; + int pitch; + BYTE* dataBits = NULL; + mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch); + mf_info_clear_invalid_region(mfi); + // encode + wStream* s; + RFX_RECT rect; + rdpUpdate* update; + mfPeerContext* mfp; + SURFACE_BITS_COMMAND cmd = { 0 }; + + WINPR_ASSERT(client); + + mfp = (mfPeerContext*)client->context; + WINPR_ASSERT(mfp); + + update = client->context->update; + WINPR_ASSERT(update); + + s = mfp->s; + WINPR_ASSERT(s); + + Stream_Clear(s); + Stream_SetPosition(s, 0); + UINT32 x = mfi->invalid.x / mfi->scale; + UINT32 y = mfi->invalid.y / mfi->scale; + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + + rfx_context_reset(mfp->rfx_context, mfi->servscreen_width, mfi->servscreen_height); + + if (!(rfx_compose_message(mfp->rfx_context, s, &rect, 1, (BYTE*)dataBits, rect.width, + rect.height, pitch))) + { + return; + } + + cmd.destLeft = x; + cmd.destTop = y; + cmd.destRight = x + rect.width; + cmd.destBottom = y + rect.height; + cmd.bmp.bpp = 32; + cmd.bmp.codecID = 3; + cmd.bmp.width = rect.width; + cmd.bmp.height = rect.height; + cmd.bmp.bitmapDataLength = Stream_GetPosition(s); + cmd.bmp.bitmapData = Stream_Buffer(s); + // send + update->SurfaceBits(update->context, &cmd); + // clean up... maybe? +} + +static BOOL mf_peer_check_fds(freerdp_peer* client) +{ + mfPeerContext* context = (mfPeerContext*)client->context; + mfEvent* event; + + if (context->activated == FALSE) + return TRUE; + + event = mf_event_peek(info_event_queue); + + if (event != NULL) + { + if (event->type == FREERDP_SERVER_MAC_EVENT_TYPE_REGION) + { + } + else if (event->type == FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK) + { + event = mf_event_pop(info_event_queue); + mf_peer_rfx_update(client); + mf_event_free(event); + } + } + + return TRUE; +} + +/* Called when we have a new peer connecting */ +static BOOL mf_peer_context_new(freerdp_peer* client, rdpContext* context) +{ + rdpSettings* settings; + mfPeerContext* peer = (mfPeerContext*)context; + + WINPR_ASSERT(client); + WINPR_ASSERT(context); + + settings = context->settings; + WINPR_ASSERT(settings); + + if (!(peer->info = mf_info_get_instance())) + return FALSE; + + if (!(peer->rfx_context = rfx_context_new_ex( + TRUE, freerdp_settings_get_uint32(settings, FreeRDP_ThreadingFlags)))) + goto fail; + + rfx_context_reset(peer->rfx_context, + freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth), + freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)); + rfx_context_set_mode(peer->rfx_context, RLGR3); + rfx_context_set_pixel_format(peer->rfx_context, PIXEL_FORMAT_BGRA32); + + if (!(peer->s = Stream_New(NULL, 0xFFFF))) + goto fail; + + peer->vcm = WTSOpenServerA((LPSTR)client->context); + + if (!peer->vcm || (peer->vcm == INVALID_HANDLE_VALUE)) + goto fail; + + mf_info_peer_register(peer->info, peer); + return TRUE; +fail: + mf_peer_context_free(client, context); + return FALSE; +} + +/* Called after a peer disconnects */ +static void mf_peer_context_free(freerdp_peer* client, rdpContext* context) +{ + mfPeerContext* peer = (mfPeerContext*)context; + if (context) + { + mf_info_peer_unregister(peer->info, peer); + dispatch_suspend(info_timer); + Stream_Free(peer->s, TRUE); + rfx_context_free(peer->rfx_context); + // nsc_context_free(peer->nsc_context); +#ifdef CHANNEL_AUDIN_SERVER + + mf_peer_audin_uninit(peer); + +#endif +#ifdef CHANNEL_RDPSND_SERVER + mf_peer_rdpsnd_stop(); + + if (peer->rdpsnd) + rdpsnd_server_context_free(peer->rdpsnd); + +#endif + WTSCloseServer(peer->vcm); + } +} + +/* Called when a new client connects */ +static BOOL mf_peer_init(freerdp_peer* client) +{ + client->ContextSize = sizeof(mfPeerContext); + client->ContextNew = mf_peer_context_new; + client->ContextFree = mf_peer_context_free; + + if (!freerdp_peer_context_new(client)) + return FALSE; + + info_event_queue = mf_event_queue_new(); + info_queue = dispatch_queue_create("FreeRDP.update.timer", DISPATCH_QUEUE_SERIAL); + info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue); + + if (info_timer) + { + // DEBUG_WARN( "created timer\n"); + dispatch_source_set_timer(info_timer, DISPATCH_TIME_NOW, 42ull * NSEC_PER_MSEC, + 100ull * NSEC_PER_MSEC); + dispatch_source_set_event_handler(info_timer, ^{ + // DEBUG_WARN( "dispatch\n"); + mfEvent* event = mf_event_new(FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK); + mf_event_push(info_event_queue, (mfEvent*)event); + }); + dispatch_resume(info_timer); + } + + return TRUE; +} + +static BOOL mf_peer_post_connect(freerdp_peer* client) +{ + mfInfo* mfi = mf_info_get_instance(); + + WINPR_ASSERT(client); + + mfPeerContext* context = (mfPeerContext*)client->context; + WINPR_ASSERT(context); + + rdpSettings* settings = client->context->settings; + WINPR_ASSERT(settings); + + mfi->scale = 1; + // mfi->servscreen_width = 2880 / mfi->scale; + // mfi->servscreen_height = 1800 / mfi->scale; + UINT32 bitsPerPixel = 32; + + if ((freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != mfi->servscreen_width) || + (freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) != mfi->servscreen_height)) + { + } + + if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, mfi->servscreen_width)) + return FALSE; + if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, mfi->servscreen_height)) + return FALSE; + if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, bitsPerPixel)) + return FALSE; + + WINPR_ASSERT(client->context->update); + WINPR_ASSERT(client->context->update->DesktopResize); + client->context->update->DesktopResize(client->context); + + mfi->mouse_down_left = FALSE; + mfi->mouse_down_right = FALSE; + mfi->mouse_down_other = FALSE; +#ifdef CHANNEL_RDPSND_SERVER + + if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd")) + { + mf_peer_rdpsnd_init(context); /* Audio Output */ + } + +#endif + /* Dynamic Virtual Channels */ +#ifdef CHANNEL_AUDIN_SERVER + mf_peer_audin_init(context); /* Audio Input */ +#endif + return TRUE; +} + +static BOOL mf_peer_activate(freerdp_peer* client) +{ + WINPR_ASSERT(client); + + mfPeerContext* context = (mfPeerContext*)client->context; + WINPR_ASSERT(context); + + rdpSettings* settings = client->context->settings; + WINPR_ASSERT(settings); + + rfx_context_reset(context->rfx_context, + freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth), + freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)); + context->activated = TRUE; + return TRUE; +} + +static BOOL mf_peer_synchronize_event(rdpInput* input, UINT32 flags) +{ + return TRUE; +} + +static BOOL mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code) +{ + bool state_down = FALSE; + + if (flags == KBD_FLAGS_DOWN) + { + state_down = TRUE; + } + return TRUE; +} + +static BOOL mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) +{ + return FALSE; +} + +static BOOL mf_peer_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area) +{ + return FALSE; +} + +static void* mf_peer_main_loop(void* arg) +{ + mfPeerContext* context; + rdpSettings* settings; + rdpInput* input; + rdpUpdate* update; + freerdp_peer* client = (freerdp_peer*)arg; + + if (!mf_peer_init(client)) + goto fail; + + const mf_server_info* info = client->ContextExtra; + WINPR_ASSERT(info); + + WINPR_ASSERT(client->context); + + settings = client->context->settings; + WINPR_ASSERT(settings); + + /* Initialize the real server settings here */ + rdpPrivateKey* key = freerdp_key_new_from_file(info->key); + if (!key) + goto fail; + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1)) + goto fail; + rdpCertificate* cert = freerdp_certificate_new_from_file(info->cert); + if (!cert) + goto fail; + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1)) + goto fail; + + if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE)) + goto fail; + if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE)) + goto fail; + if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32)) + goto fail; + + if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE)) + goto fail; + if (!freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, FALSE)) + goto fail; + + client->PostConnect = mf_peer_post_connect; + client->Activate = mf_peer_activate; + + input = client->context->input; + WINPR_ASSERT(input); + + input->SynchronizeEvent = mf_peer_synchronize_event; + input->KeyboardEvent = mf_input_keyboard_event; // mf_peer_keyboard_event; + input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event; + input->MouseEvent = mf_input_mouse_event; + input->ExtendedMouseEvent = mf_input_extended_mouse_event; + + update = client->context->update; + WINPR_ASSERT(update); + + // update->RefreshRect = mf_peer_refresh_rect; + update->SuppressOutput = mf_peer_suppress_output; + + WINPR_ASSERT(client->Initialize); + const BOOL rc = client->Initialize(client); + if (!rc) + goto fail; + context = (mfPeerContext*)client->context; + + while (1) + { + DWORD status; + HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 }; + DWORD count = client->GetEventHandles(client, handles, ARRAYSIZE(handles)); + + if ((count == 0) || (count == MAXIMUM_WAIT_OBJECTS)) + { + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); + break; + } + + handles[count++] = WTSVirtualChannelManagerGetEventHandle(context->vcm); + + status = WaitForMultipleObjects(count, handles, FALSE, INFINITE); + if (status == WAIT_FAILED) + { + WLog_ERR(TAG, "WaitForMultipleObjects failed"); + break; + } + + if (client->CheckFileDescriptor(client) != TRUE) + { + break; + } + + if ((mf_peer_check_fds(client)) != TRUE) + { + break; + } + + if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE) + { + break; + } + } + + client->Disconnect(client); + freerdp_peer_context_free(client); +fail: + freerdp_peer_free(client); + return NULL; +} + +BOOL mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) +{ + pthread_t th; + + WINPR_ASSERT(instance); + WINPR_ASSERT(client); + + client->ContextExtra = instance->info; + if (pthread_create(&th, 0, mf_peer_main_loop, client) == 0) + { + pthread_detach(th); + return TRUE; + } + + return FALSE; +} |