FreeRDP
Loading...
Searching...
No Matches
ios_freerdp.m
1/*
2 RDP run-loop
3
4 Copyright 2013 Thincast Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
5
6 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
7 If a copy of the MPL was not distributed with this file, You can obtain one at
8 http://mozilla.org/MPL/2.0/.
9 */
10
11#include <winpr/assert.h>
12#import <winpr/clipboard.h>
13
14#import <freerdp/gdi/gdi.h>
15#import <freerdp/channels/channels.h>
16#import <freerdp/client/channels.h>
17#import <freerdp/client/cmdline.h>
18#import <freerdp/freerdp.h>
19#import <freerdp/gdi/gfx.h>
20#import <freerdp/client/cliprdr.h>
21
22#import "ios_freerdp.h"
23#import "ios_freerdp_ui.h"
24#import "ios_freerdp_events.h"
25#import "ios_cliprdr.h"
26
27#import "RDPSession.h"
28#import "Utils.h"
29
30#include <errno.h>
31
32#define TAG FREERDP_TAG("iOS")
33
34#pragma mark Connection helpers
35
36static void ios_OnChannelConnectedEventHandler(void *context, const ChannelConnectedEventArgs *e)
37{
38 WLog_INFO(TAG, "ios_OnChannelConnectedEventHandler, channel %s", e->name);
39 rdpSettings *settings;
40 mfContext *afc;
41
42 if (!context || !e)
43 {
44 WLog_FATAL(TAG, "(context=%p, EventArgs=%p", context, (void *)e);
45 return;
46 }
47
48 afc = (mfContext *)context;
49 settings = afc->_p.settings;
50
51 if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
52 {
53 if (freerdp_settings_get_bool(settings, FreeRDP_SoftwareGdi))
54 {
55 gdi_graphics_pipeline_init(afc->_p.gdi, (RdpgfxClientContext *)e->pInterface);
56 }
57 else
58 {
59 WLog_WARN(TAG, "GFX without software GDI requested. "
60 " This is not supported, add /gdi:sw");
61 }
62 }
63 else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
64 {
65 ios_cliprdr_init(afc, (CliprdrClientContext *)e->pInterface);
66 }
67}
68
69static void ios_OnChannelDisconnectedEventHandler(void *context,
70 const ChannelDisconnectedEventArgs *e)
71{
72 WLog_INFO(TAG, "ios_OnChannelConnectedEventHandler, channel %s", e->name);
73 rdpSettings *settings;
74 mfContext *afc;
75
76 if (!context || !e)
77 {
78 WLog_FATAL(TAG, "(context=%p, EventArgs=%p", context, (void *)e);
79 return;
80 }
81
82 afc = (mfContext *)context;
83 settings = afc->_p.settings;
84
85 if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
86 {
87 if (freerdp_settings_get_bool(settings, FreeRDP_SoftwareGdi))
88 {
89 gdi_graphics_pipeline_uninit(afc->_p.gdi, (RdpgfxClientContext *)e->pInterface);
90 }
91 else
92 {
93 WLog_WARN(TAG, "GFX without software GDI requested. "
94 " This is not supported, add /gdi:sw");
95 }
96 }
97 else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
98 {
99 ios_cliprdr_uninit(afc, (CliprdrClientContext *)e->pInterface);
100 }
101}
102
103static BOOL ios_pre_connect(freerdp *instance)
104{
105 int rc;
106 rdpSettings *settings;
107
108 if (!instance || !instance->context)
109 return FALSE;
110
111 settings = instance->context->settings;
112 WINPR_ASSERT(settings);
113
114 const char *Password = freerdp_settings_get_string(settings, FreeRDP_Password);
115 if (!freerdp_settings_set_bool(settings, FreeRDP_AutoLogonEnabled,
116 Password && (Password && (strlen(Password) > 0))))
117 return FALSE;
118
119 // Verify screen width/height are sane
120 if ((freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) < 64) ||
121 (freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) < 64) ||
122 (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) > 4096) ||
123 (freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) > 4096))
124 {
125 NSLog(@"%s: invalid dimensions %d %d", __func__,
126 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
127 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
128 return FALSE;
129 }
130
131 rc = PubSub_SubscribeChannelConnected(instance->context->pubSub,
132 ios_OnChannelConnectedEventHandler);
133
134 if (rc != CHANNEL_RC_OK)
135 {
136 WLog_ERR(TAG, "Could not subscribe to connect event handler [%l08X]", rc);
137 return FALSE;
138 }
139
140 rc = PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
141 ios_OnChannelDisconnectedEventHandler);
142
143 if (rc != CHANNEL_RC_OK)
144 {
145 WLog_ERR(TAG, "Could not subscribe to disconnect event handler [%l08X]", rc);
146 return FALSE;
147 }
148
149 if (!freerdp_client_load_addins(instance->context->channels, settings))
150 {
151 WLog_ERR(TAG, "Failed to load addins [%l08X]", GetLastError());
152 return FALSE;
153 }
154
155 return TRUE;
156}
157
158static BOOL ios_Pointer_New(rdpContext *context, rdpPointer *pointer)
159{
160 if (!context || !pointer || !context->gdi)
161 return FALSE;
162
163 return TRUE;
164}
165
166static void ios_Pointer_Free(rdpContext *context, rdpPointer *pointer)
167{
168 if (!context || !pointer)
169 return;
170}
171
172static BOOL ios_Pointer_Set(rdpContext *context, rdpPointer *pointer)
173{
174 if (!context)
175 return FALSE;
176
177 return TRUE;
178}
179
180static BOOL ios_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y)
181{
182 if (!context)
183 return FALSE;
184
185 return TRUE;
186}
187
188static BOOL ios_Pointer_SetNull(rdpContext *context)
189{
190 if (!context)
191 return FALSE;
192
193 return TRUE;
194}
195
196static BOOL ios_Pointer_SetDefault(rdpContext *context)
197{
198 if (!context)
199 return FALSE;
200
201 return TRUE;
202}
203
204static BOOL ios_register_pointer(rdpGraphics *graphics)
205{
206 rdpPointer pointer = { 0 };
207
208 if (!graphics)
209 return FALSE;
210
211 pointer.size = sizeof(pointer);
212 pointer.New = ios_Pointer_New;
213 pointer.Free = ios_Pointer_Free;
214 pointer.Set = ios_Pointer_Set;
215 pointer.SetNull = ios_Pointer_SetNull;
216 pointer.SetDefault = ios_Pointer_SetDefault;
217 pointer.SetPosition = ios_Pointer_SetPosition;
218 graphics_register_pointer(graphics, &pointer);
219 return TRUE;
220}
221
222static BOOL ios_post_connect(freerdp *instance)
223{
224 mfInfo *mfi;
225
226 if (!instance)
227 return FALSE;
228
229 mfi = MFI_FROM_INSTANCE(instance);
230
231 if (!mfi)
232 return FALSE;
233
234 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
235 return FALSE;
236
237 if (!ios_register_pointer(instance->context->graphics))
238 return FALSE;
239
240 ios_allocate_display_buffer(mfi);
241 instance->context->update->BeginPaint = ios_ui_begin_paint;
242 instance->context->update->EndPaint = ios_ui_end_paint;
243 instance->context->update->DesktopResize = ios_ui_resize_window;
244 [mfi->session performSelectorOnMainThread:@selector(sessionDidConnect)
245 withObject:nil
246 waitUntilDone:YES];
247 return TRUE;
248}
249
250static void ios_post_disconnect(freerdp *instance)
251{
252 gdi_free(instance);
253}
254
255#pragma mark -
256#pragma mark Running the connection
257
258int ios_run_freerdp(freerdp *instance)
259{
260 mfContext *context = (mfContext *)instance->context;
261 mfInfo *mfi = context->mfi;
262 rdpChannels *channels = instance->context->channels;
263 mfi->connection_state = TSXConnectionConnecting;
264
265 if (!freerdp_connect(instance))
266 {
267 NSLog(@"%s: inst->rdp_connect failed", __func__);
268 return mfi->unwanted ? MF_EXIT_CONN_CANCELED : MF_EXIT_CONN_FAILED;
269 }
270
271 if (mfi->unwanted)
272 return MF_EXIT_CONN_CANCELED;
273
274 mfi->connection_state = TSXConnectionConnected;
275 // Connection main loop
276 NSAutoreleasePool *pool;
277
278 while (!freerdp_shall_disconnect_context(instance->context))
279 {
280 DWORD status;
281 DWORD nCount = 0;
282 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
283 pool = [[NSAutoreleasePool alloc] init];
284
285 nCount = freerdp_get_event_handles(instance->context, handles, ARRAYSIZE(handles));
286 if (nCount == 0)
287 {
288 NSLog(@"%s: freerdp_get_event_handles failed", __func__);
289 break;
290 }
291
292 handles[nCount++] = ios_events_get_handle(mfi);
293
294 status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
295
296 if (WAIT_FAILED == status)
297 {
298 NSLog(@"%s: WaitForMultipleObjects failed!", __func__);
299 break;
300 }
301
302 // Check the libfreerdp fds
303 if (!freerdp_check_event_handles(instance->context))
304 {
305 NSLog(@"%s: freerdp_check_event_handles failed.", __func__);
306 break;
307 }
308
309 // Check input event fds
310 if (ios_events_check_handle(mfi) != TRUE)
311 {
312 // This event will fail when the app asks for a disconnect.
313 // NSLog(@"%s: ios_events_check_fds failed: terminating connection.", __func__);
314 break;
315 }
316
317 [pool release];
318 pool = nil;
319 }
320
321 CGContextRelease(mfi->bitmap_context);
322 mfi->bitmap_context = NULL;
323 mfi->connection_state = TSXConnectionDisconnected;
324 // Cleanup
325 freerdp_disconnect(instance);
326 gdi_free(instance);
327 cache_free(instance->context->cache);
328 [pool release];
329 pool = nil;
330 return MF_EXIT_SUCCESS;
331}
332
333#pragma mark -
334#pragma mark Context callbacks
335
336static BOOL ios_client_new(freerdp *instance, rdpContext *context)
337{
338 mfContext *ctx = (mfContext *)context;
339
340 if (!instance || !context)
341 return FALSE;
342
343 if ((ctx->mfi = calloc(1, sizeof(mfInfo))) == NULL)
344 return FALSE;
345
346 ctx->mfi->context = (mfContext *)context;
347 ctx->mfi->_context = context;
348 ctx->mfi->instance = instance;
349
350 if (!ios_events_create_pipe(ctx->mfi))
351 return FALSE;
352
353 instance->PreConnect = ios_pre_connect;
354 instance->PostConnect = ios_post_connect;
355 instance->PostDisconnect = ios_post_disconnect;
356 instance->Authenticate = ios_ui_authenticate;
357 instance->GatewayAuthenticate = ios_ui_gw_authenticate;
358 instance->VerifyCertificateEx = ios_ui_verify_certificate_ex;
359 instance->VerifyChangedCertificateEx = ios_ui_verify_changed_certificate_ex;
360 instance->LogonErrorInfo = NULL;
361 return TRUE;
362}
363
364static void ios_client_free(freerdp *instance, rdpContext *context)
365{
366 mfInfo *mfi;
367
368 if (!context)
369 return;
370
371 mfi = ((mfContext *)context)->mfi;
372 ios_events_free_pipe(mfi);
373 free(mfi);
374}
375
376static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS *pEntryPoints)
377{
378 WINPR_ASSERT(pEntryPoints);
379
380 ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
381 pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
382 pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
383 pEntryPoints->GlobalInit = NULL;
384 pEntryPoints->GlobalUninit = NULL;
385 pEntryPoints->ContextSize = sizeof(mfContext);
386 pEntryPoints->ClientNew = ios_client_new;
387 pEntryPoints->ClientFree = ios_client_free;
388 pEntryPoints->ClientStart = NULL;
389 pEntryPoints->ClientStop = NULL;
390 return 0;
391}
392
393#pragma mark -
394#pragma mark Initialization and cleanup
395
396freerdp *ios_freerdp_new()
397{
398 rdpContext *context;
399 RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
400 RdpClientEntry(&clientEntryPoints);
401 context = freerdp_client_context_new(&clientEntryPoints);
402
403 if (!context)
404 return NULL;
405
406 return context->instance;
407}
408
409void ios_freerdp_free(freerdp *instance)
410{
411 if (!instance || !instance->context)
412 return;
413
414 freerdp_client_context_free(instance->context);
415}
416
417void ios_init_freerdp()
418{
419 signal(SIGPIPE, SIG_IGN);
420}
421
422void ios_uninit_freerdp()
423{
424}
425
426/* compatibility functions */
427size_t fwrite$UNIX2003(const void *ptr, size_t size, size_t nmemb, FILE *stream)
428{
429 return fwrite(ptr, size, nmemb, stream);
430}
431
432void ios_send_clipboard_data(void *context, const void *data, UINT32 size)
433{
434 mfContext *afc = (mfContext *)context;
435 ClipboardLock(afc->clipboard);
436 UINT32 formatId = ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING");
437 if (size)
438 ClipboardSetData(afc->clipboard, formatId, data, size);
439 else
440 ClipboardEmpty(afc->clipboard);
441 ClipboardUnlock(afc->clipboard);
442 ios_cliprdr_send_client_format_list(afc->cliprdr);
443}
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.