445 lines
10 KiB
C
445 lines
10 KiB
C
/**
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
* FreeRDP Mac OS X Server
|
|
*
|
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <sys/time.h>
|
|
|
|
#include <CoreGraphics/CGEvent.h>
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#include <freerdp/constants.h>
|
|
#include <freerdp/utils/sleep.h>
|
|
#include <freerdp/utils/memory.h>
|
|
|
|
#ifdef CHANNEL_RDPSND_SERVER
|
|
#include <freerdp/server/rdpsnd.h>
|
|
#include "mf_rdpsnd.h"
|
|
#endif
|
|
|
|
#ifdef CHANNEL_AUDIN_SERVER
|
|
#include "mf_audin.h"
|
|
#endif
|
|
|
|
#include "mfreerdp.h"
|
|
|
|
#include <mach/clock.h>
|
|
#include <mach/mach.h>
|
|
|
|
//refactor these
|
|
int info_last_sec = 0;
|
|
int info_last_nsec = 0;
|
|
|
|
void mf_peer_rfx_update(freerdp_peer* client)
|
|
{
|
|
|
|
//limit rate
|
|
clock_serv_t cclock;
|
|
mach_timespec_t mts;
|
|
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
|
clock_get_time(cclock, &mts);
|
|
mach_port_deallocate(mach_task_self(), cclock);
|
|
|
|
if ( (mts.tv_sec - info_last_sec > 0) && (mts.tv_nsec - info_last_nsec > 500000000) ) {
|
|
printf("rfx_update\n");
|
|
|
|
info_last_nsec = mts.tv_nsec;
|
|
info_last_sec = mts.tv_sec;
|
|
}
|
|
|
|
|
|
//capture entire screen
|
|
|
|
//encode
|
|
|
|
//send
|
|
}
|
|
|
|
void mf_peer_context_new(freerdp_peer* client, mfPeerContext* context)
|
|
{
|
|
context->rfx_context = rfx_context_new();
|
|
context->rfx_context->mode = RLGR3;
|
|
context->rfx_context->width = client->settings->DesktopWidth;
|
|
context->rfx_context->height = client->settings->DesktopHeight;
|
|
rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_R8G8B8);
|
|
|
|
context->nsc_context = nsc_context_new();
|
|
nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_R8G8B8);
|
|
|
|
context->s = stream_new(0xFFFF);
|
|
|
|
#ifdef WITH_SERVER_CHANNELS
|
|
context->vcm = WTSCreateVirtualChannelManager(client);
|
|
#endif
|
|
}
|
|
|
|
void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context)
|
|
{
|
|
if (context)
|
|
{
|
|
stream_free(context->s);
|
|
|
|
rfx_context_free(context->rfx_context);
|
|
nsc_context_free(context->nsc_context);
|
|
|
|
#ifdef CHANNEL_AUDIN_SERVER
|
|
if (context->audin)
|
|
audin_server_context_free(context->audin);
|
|
#endif
|
|
|
|
#ifdef CHANNEL_RDPSND_SERVER
|
|
if (context->rdpsnd)
|
|
rdpsnd_server_context_free(context->rdpsnd);
|
|
#endif
|
|
|
|
#ifdef WITH_SERVER_CHANNELS
|
|
WTSDestroyVirtualChannelManager(context->vcm);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void mf_peer_init(freerdp_peer* client)
|
|
{
|
|
client->context_size = sizeof(mfPeerContext);
|
|
client->ContextNew = (psPeerContextNew) mf_peer_context_new;
|
|
client->ContextFree = (psPeerContextFree) mf_peer_context_free;
|
|
freerdp_peer_context_new(client);
|
|
}
|
|
|
|
BOOL mf_peer_post_connect(freerdp_peer* client)
|
|
{
|
|
//mfPeerContext* context = (mfPeerContext*) client->context;
|
|
|
|
printf("Client %s is activated\n", client->hostname);
|
|
|
|
if (client->settings->AutoLogonEnabled)
|
|
{
|
|
printf(" and wants to login automatically as %s\\%s",
|
|
client->settings->Domain ? client->settings->Domain : "",
|
|
client->settings->Username);
|
|
|
|
/* A real server may perform OS login here if NLA is not executed previously. */
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Client requested desktop: %dx%dx%d\n",
|
|
client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth);
|
|
|
|
#ifdef WITH_SERVER_CHANNELS
|
|
/* Iterate all channel names requested by the client and activate those supported by the server */
|
|
int i;
|
|
for (i = 0; i < client->settings->ChannelCount; i++)
|
|
{
|
|
if (client->settings->ChannelDefArray[i].joined)
|
|
{
|
|
#ifdef CHANNEL_RDPSND_SERVER
|
|
if (strncmp(client->settings->ChannelDefArray[i].Name, "rdpsnd", 6) == 0)
|
|
{
|
|
mf_peer_rdpsnd_init(context); /* Audio Output */
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Dynamic Virtual Channels */
|
|
#endif
|
|
|
|
#ifdef CHANNEL_AUDIN_SERVER
|
|
mf_peer_audin_init(context); /* Audio Input */
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL mf_peer_activate(freerdp_peer* client)
|
|
{
|
|
mfPeerContext* context = (mfPeerContext*) client->context;
|
|
|
|
rfx_context_reset(context->rfx_context);
|
|
context->activated = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void mf_peer_synchronize_event(rdpInput* input, UINT32 flags)
|
|
{
|
|
printf("Client sent a synchronize event (flags:0x%08X)\n", flags);
|
|
}
|
|
|
|
void mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
|
{
|
|
printf("Client sent a keyboard event (flags:0x%04X code:0x%04X)\n", flags, code);
|
|
|
|
UINT16 down = 0x4000;
|
|
//UINT16 up = 0x8000;
|
|
|
|
bool state_down = FALSE;
|
|
|
|
if (flags == down)
|
|
{
|
|
state_down = TRUE;
|
|
}
|
|
|
|
CGEventRef event;
|
|
event = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, state_down);
|
|
CGEventPost(kCGHIDEventTap, event);
|
|
CFRelease(event);
|
|
}
|
|
|
|
void mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
|
{
|
|
printf("Client sent a unicode keyboard event (flags:0x%04X code:0x%04X)\n", flags, code);
|
|
}
|
|
|
|
void mf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
|
{
|
|
//printf("Client sent a mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y);
|
|
}
|
|
|
|
void mf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
|
{
|
|
//printf("Client sent an extended mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y);
|
|
}
|
|
|
|
static void mf_peer_refresh_rect(rdpContext* context, BYTE count, RECTANGLE_16* areas)
|
|
{
|
|
BYTE i;
|
|
|
|
printf("Client requested to refresh:\n");
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
printf(" (%d, %d) (%d, %d)\n", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom);
|
|
}
|
|
}
|
|
|
|
static void mf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_16* area)
|
|
{
|
|
if (allow > 0)
|
|
{
|
|
printf("Client restore output (%d, %d) (%d, %d).\n", area->left, area->top, area->right, area->bottom);
|
|
}
|
|
else
|
|
{
|
|
printf("Client minimized and suppress output.\n");
|
|
}
|
|
}
|
|
|
|
static void* mf_peer_main_loop(void* arg)
|
|
{
|
|
int i;
|
|
int fds;
|
|
int max_fds;
|
|
int rcount;
|
|
void* rfds[32];
|
|
fd_set rfds_set;
|
|
mfPeerContext* context;
|
|
freerdp_peer* client = (freerdp_peer*) arg;
|
|
|
|
memset(rfds, 0, sizeof(rfds));
|
|
|
|
mf_peer_init(client);
|
|
|
|
/* Initialize the real server settings here */
|
|
client->settings->CertificateFile = _strdup("server.crt");
|
|
client->settings->PrivateKeyFile = _strdup("server.key");
|
|
client->settings->NlaSecurity = FALSE;
|
|
client->settings->RemoteFxCodec = TRUE;
|
|
client->settings->SuppressOutput = TRUE;
|
|
client->settings->RefreshRect = TRUE;
|
|
|
|
client->PostConnect = mf_peer_post_connect;
|
|
client->Activate = mf_peer_activate;
|
|
|
|
client->input->SynchronizeEvent = mf_peer_synchronize_event;
|
|
client->input->KeyboardEvent = mf_peer_keyboard_event;
|
|
client->input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event;
|
|
client->input->MouseEvent = mf_peer_mouse_event;
|
|
client->input->ExtendedMouseEvent = mf_peer_extended_mouse_event;
|
|
|
|
client->update->RefreshRect = mf_peer_refresh_rect;
|
|
client->update->SuppressOutput = mf_peer_suppress_output;
|
|
|
|
client->Initialize(client);
|
|
context = (mfPeerContext*) client->context;
|
|
|
|
printf("We've got a client %s\n", client->local ? "(local)" : client->hostname);
|
|
|
|
while (1)
|
|
{
|
|
rcount = 0;
|
|
|
|
if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE)
|
|
{
|
|
printf("Failed to get FreeRDP file descriptor\n");
|
|
break;
|
|
}
|
|
|
|
#ifdef WITH_SERVER_CHANNELS
|
|
WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount);
|
|
#endif
|
|
|
|
max_fds = 0;
|
|
FD_ZERO(&rfds_set);
|
|
|
|
for (i = 0; i < rcount; i++)
|
|
{
|
|
fds = (int)(long)(rfds[i]);
|
|
|
|
if (fds > max_fds)
|
|
max_fds = fds;
|
|
|
|
FD_SET(fds, &rfds_set);
|
|
}
|
|
|
|
if (max_fds == 0)
|
|
break;
|
|
|
|
if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1)
|
|
{
|
|
/* these are not really errors */
|
|
if (!((errno == EAGAIN) ||
|
|
(errno == EWOULDBLOCK) ||
|
|
(errno == EINPROGRESS) ||
|
|
(errno == EINTR))) /* signal occurred */
|
|
{
|
|
printf("select failed\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (client->CheckFileDescriptor(client) != TRUE)
|
|
break;
|
|
|
|
mf_peer_rfx_update(client);
|
|
|
|
#ifdef WITH_SERVER_CHANNELS
|
|
if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
|
|
break;
|
|
#endif
|
|
|
|
}
|
|
|
|
printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname);
|
|
|
|
client->Disconnect(client);
|
|
freerdp_peer_context_free(client);
|
|
freerdp_peer_free(client);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
|
|
{
|
|
pthread_t th;
|
|
|
|
pthread_create(&th, 0, mf_peer_main_loop, client);
|
|
pthread_detach(th);
|
|
}
|
|
|
|
static void mf_server_main_loop(freerdp_listener* instance)
|
|
{
|
|
int i;
|
|
int fds;
|
|
int max_fds;
|
|
int rcount;
|
|
void* rfds[32];
|
|
fd_set rfds_set;
|
|
|
|
memset(rfds, 0, sizeof(rfds));
|
|
|
|
while (1)
|
|
{
|
|
rcount = 0;
|
|
|
|
if (instance->GetFileDescriptor(instance, rfds, &rcount) != TRUE)
|
|
{
|
|
printf("Failed to get FreeRDP file descriptor\n");
|
|
break;
|
|
}
|
|
|
|
max_fds = 0;
|
|
FD_ZERO(&rfds_set);
|
|
|
|
for (i = 0; i < rcount; i++)
|
|
{
|
|
fds = (int)(long)(rfds[i]);
|
|
|
|
if (fds > max_fds)
|
|
max_fds = fds;
|
|
|
|
FD_SET(fds, &rfds_set);
|
|
}
|
|
|
|
if (max_fds == 0)
|
|
break;
|
|
|
|
if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1)
|
|
{
|
|
/* these are not really errors */
|
|
if (!((errno == EAGAIN) ||
|
|
(errno == EWOULDBLOCK) ||
|
|
(errno == EINPROGRESS) ||
|
|
(errno == EINTR))) /* signal occurred */
|
|
{
|
|
printf("select failed\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (instance->CheckFileDescriptor(instance) != TRUE)
|
|
{
|
|
printf("Failed to check FreeRDP file descriptor\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
instance->Close(instance);
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
freerdp_listener* instance;
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
instance = freerdp_listener_new();
|
|
|
|
instance->PeerAccepted = mf_peer_accepted;
|
|
|
|
if (instance->Open(instance, NULL, 3389))
|
|
{
|
|
mf_server_main_loop(instance);
|
|
}
|
|
|
|
freerdp_listener_free(instance);
|
|
|
|
return 0;
|
|
}
|
|
|