2015-01-13 19:09:36 +03:00
|
|
|
/**
|
2012-10-09 07:02:04 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2011-07-28 08:38:25 +04:00
|
|
|
* FreeRDP Core
|
|
|
|
*
|
|
|
|
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2015-07-15 10:50:35 +03:00
|
|
|
* Copyright 2015 Thincast Technologies GmbH
|
|
|
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
2011-07-28 08:38:25 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2012-08-15 01:09:01 +04:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2011-07-28 08:38:25 +04:00
|
|
|
#include "rdp.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "update.h"
|
2011-08-28 23:51:49 +04:00
|
|
|
#include "surface.h"
|
2011-07-28 21:46:36 +04:00
|
|
|
#include "transport.h"
|
2011-07-28 19:09:51 +04:00
|
|
|
#include "connection.h"
|
2013-02-04 23:56:54 +04:00
|
|
|
#include "message.h"
|
2016-01-28 16:26:50 +03:00
|
|
|
#include "buildflags.h"
|
2019-10-01 10:47:26 +03:00
|
|
|
#include "gateway/rpc_fault.h"
|
2011-07-28 08:38:25 +04:00
|
|
|
|
2013-08-19 19:44:52 +04:00
|
|
|
#include <assert.h>
|
|
|
|
|
2018-08-24 14:49:19 +03:00
|
|
|
#include <winpr/crt.h>
|
2015-03-30 19:17:07 +03:00
|
|
|
#include <winpr/string.h>
|
2013-06-28 17:18:20 +04:00
|
|
|
#include <winpr/stream.h>
|
2014-02-17 05:41:19 +04:00
|
|
|
#include <winpr/wtsapi.h>
|
Winpr/openssl: Fix digests initialization in multi-thread
SSL functions like OpenSSL_add_all_digests should be invoked at very beginning as they are not MT safe.
If not we might meet double free exception as following:
#0 0x00007f23ddd71c37 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007f23ddd75028 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00007f23dddae2a4 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#3 0x00007f23dddba55e in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#4 0x00007f23dc6ecfcd in CRYPTO_free () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#5 0x00007f23dc6ef8d1 in OBJ_NAME_add () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#6 0x00007f23dc77dcd8 in EVP_add_digest () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#7 0x00007f23dc782321 in OpenSSL_add_all_digests () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#8 0x00007f23c781da28 in winpr_openssl_get_evp_md (md=4) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:52
#9 0x00007f23c781dccb in winpr_Digest_Init (ctx=0x7f22d064d470, md=<optimized out>) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:344
#10 0x00007f23d486139b in security_salted_mac_signature (rdp=0x7f23859f5a20, data=0x7f238542d4fb "\004\204\022\004", length=4743, encryption=<optimized out>, output=0x7
at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/security.c:378
#11 0x00007f23d488d73f in fastpath_send_update_pdu (fastpath=<optimized out>, updateCode=4 '\004', s=0x7f23859f5f40, skipCompression=true)
at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/fastpath.c:1076
#12 0x00007f23d4891c4f in update_send_surface_frame_bits (context=0x7f23859f5540, cmd=0x7f22b2ffcc80, first=true, last=true, frameId=6)
at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/update.c:1041
Related reports: https://rt.openssl.org/Ticket/Display.html?id=2216&user=guest&pass=guest
2016-12-26 17:21:36 +03:00
|
|
|
#include <winpr/ssl.h>
|
2016-10-27 15:36:48 +03:00
|
|
|
#include <winpr/debug.h>
|
2012-11-22 04:22:41 +04:00
|
|
|
|
2011-07-28 08:38:25 +04:00
|
|
|
#include <freerdp/freerdp.h>
|
2012-12-14 09:25:48 +04:00
|
|
|
#include <freerdp/error.h>
|
2013-06-19 00:55:23 +04:00
|
|
|
#include <freerdp/event.h>
|
2012-08-31 03:57:21 +04:00
|
|
|
#include <freerdp/locale/keyboard.h>
|
2014-02-16 00:26:34 +04:00
|
|
|
#include <freerdp/channels/channels.h>
|
2013-11-06 20:29:33 +04:00
|
|
|
#include <freerdp/version.h>
|
2014-09-12 16:36:29 +04:00
|
|
|
#include <freerdp/log.h>
|
2018-11-20 11:09:52 +03:00
|
|
|
#include <freerdp/cache/pointer.h>
|
2014-09-12 16:36:29 +04:00
|
|
|
|
2018-11-22 18:54:42 +03:00
|
|
|
#include "settings.h"
|
|
|
|
|
2014-09-12 16:36:29 +04:00
|
|
|
#define TAG FREERDP_TAG("core")
|
2011-07-28 08:38:25 +04:00
|
|
|
|
2013-01-25 21:08:00 +04:00
|
|
|
/* connectErrorCode is 'extern' in error.h. See comment there.*/
|
2012-04-13 15:16:08 +04:00
|
|
|
|
2016-12-19 16:13:36 +03:00
|
|
|
UINT freerdp_channel_add_init_handle_data(rdpChannelHandles* handles, void* pInitHandle,
|
|
|
|
void* pUserData)
|
2016-08-09 13:04:06 +03:00
|
|
|
{
|
2016-11-14 23:23:05 +03:00
|
|
|
if (!handles->init)
|
|
|
|
handles->init = ListDictionary_New(TRUE);
|
|
|
|
|
|
|
|
if (!handles->init)
|
2016-10-27 15:36:48 +03:00
|
|
|
{
|
2016-11-14 23:23:05 +03:00
|
|
|
WLog_ERR(TAG, "ListDictionary_New failed!");
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ListDictionary_Add(handles->init, pInitHandle, pUserData))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "ListDictionary_Add failed!");
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* freerdp_channel_get_init_handle_data(rdpChannelHandles* handles, void* pInitHandle)
|
|
|
|
{
|
|
|
|
void* pUserData = NULL;
|
|
|
|
pUserData = ListDictionary_GetItemValue(handles->init, pInitHandle);
|
|
|
|
return pUserData;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freerdp_channel_remove_init_handle_data(rdpChannelHandles* handles, void* pInitHandle)
|
|
|
|
{
|
|
|
|
ListDictionary_Remove(handles->init, pInitHandle);
|
|
|
|
|
|
|
|
if (ListDictionary_Count(handles->init) < 1)
|
|
|
|
{
|
|
|
|
ListDictionary_Free(handles->init);
|
|
|
|
handles->init = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-19 16:13:36 +03:00
|
|
|
UINT freerdp_channel_add_open_handle_data(rdpChannelHandles* handles, DWORD openHandle,
|
|
|
|
void* pUserData)
|
2016-11-14 23:23:05 +03:00
|
|
|
{
|
2016-12-19 16:13:36 +03:00
|
|
|
void* pOpenHandle = (void*)(size_t) openHandle;
|
2016-11-14 23:23:05 +03:00
|
|
|
|
|
|
|
if (!handles->open)
|
|
|
|
handles->open = ListDictionary_New(TRUE);
|
|
|
|
|
|
|
|
if (!handles->open)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "ListDictionary_New failed!");
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ListDictionary_Add(handles->open, pOpenHandle, pUserData))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "ListDictionary_Add failed!");
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
2016-10-27 15:36:48 +03:00
|
|
|
}
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2016-11-14 23:23:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* freerdp_channel_get_open_handle_data(rdpChannelHandles* handles, DWORD openHandle)
|
|
|
|
{
|
|
|
|
void* pUserData = NULL;
|
2016-12-19 16:13:36 +03:00
|
|
|
void* pOpenHandle = (void*)(size_t) openHandle;
|
2016-11-14 23:23:05 +03:00
|
|
|
pUserData = ListDictionary_GetItemValue(handles->open, pOpenHandle);
|
|
|
|
return pUserData;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freerdp_channel_remove_open_handle_data(rdpChannelHandles* handles, DWORD openHandle)
|
|
|
|
{
|
2016-12-19 16:13:36 +03:00
|
|
|
void* pOpenHandle = (void*)(size_t) openHandle;
|
2016-11-14 23:23:05 +03:00
|
|
|
ListDictionary_Remove(handles->open, pOpenHandle);
|
|
|
|
|
|
|
|
if (ListDictionary_Count(handles->open) < 1)
|
|
|
|
{
|
|
|
|
ListDictionary_Free(handles->open);
|
|
|
|
handles->open = NULL;
|
|
|
|
}
|
2016-08-09 13:04:06 +03:00
|
|
|
}
|
|
|
|
|
2012-02-23 19:30:04 +04:00
|
|
|
/** Creates a new connection based on the settings found in the "instance" parameter
|
|
|
|
* It will use the callbacks registered on the structure to process the pre/post connect operations
|
|
|
|
* that the caller requires.
|
|
|
|
* @see struct rdp_freerdp in freerdp.h
|
2012-02-23 19:22:05 +04:00
|
|
|
*
|
|
|
|
* @param instance - pointer to a rdp_freerdp structure that contains base information to establish the connection.
|
|
|
|
* On return, this function will be initialized with the new connection's settings.
|
|
|
|
*
|
2012-10-09 10:31:28 +04:00
|
|
|
* @return TRUE if successful. FALSE otherwise.
|
2012-02-23 19:30:04 +04:00
|
|
|
*
|
2012-02-23 19:22:05 +04:00
|
|
|
*/
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL freerdp_connect(freerdp* instance)
|
2012-02-27 13:16:00 +04:00
|
|
|
{
|
2016-10-11 12:20:54 +03:00
|
|
|
UINT status2 = CHANNEL_RC_OK;
|
2011-07-28 21:46:36 +04:00
|
|
|
rdpRdp* rdp;
|
2015-02-06 01:01:56 +03:00
|
|
|
BOOL status = TRUE;
|
2012-09-04 01:08:46 +04:00
|
|
|
rdpSettings* settings;
|
2013-07-04 00:18:45 +04:00
|
|
|
ConnectionResultEventArgs e;
|
2012-05-22 00:01:24 +04:00
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
if (!instance)
|
|
|
|
return FALSE;
|
|
|
|
|
2012-04-13 15:16:08 +04:00
|
|
|
/* We always set the return code to 0 before we start the connect sequence*/
|
2018-06-19 18:28:22 +03:00
|
|
|
instance->ConnectionCallbackState = CLIENT_STATE_INITIAL;
|
2012-05-22 00:01:24 +04:00
|
|
|
connectErrorCode = 0;
|
2018-04-11 10:30:40 +03:00
|
|
|
instance->context->LastError = FREERDP_ERROR_SUCCESS;
|
2015-09-03 14:43:08 +03:00
|
|
|
clearChannelError(instance->context);
|
2016-01-18 12:08:12 +03:00
|
|
|
ResetEvent(instance->context->abortEvent);
|
2011-10-16 08:50:10 +04:00
|
|
|
rdp = instance->context->rdp;
|
2012-09-04 01:08:46 +04:00
|
|
|
settings = instance->settings;
|
2018-11-22 18:54:42 +03:00
|
|
|
|
|
|
|
if (!freerdp_settings_set_default_order_support(settings))
|
|
|
|
return FALSE;
|
|
|
|
|
2015-02-06 22:21:26 +03:00
|
|
|
IFCALLRET(instance->PreConnect, status, instance);
|
2018-06-19 18:28:22 +03:00
|
|
|
instance->ConnectionCallbackState = CLIENT_STATE_PRECONNECT_PASSED;
|
2012-08-26 19:32:36 +04:00
|
|
|
|
2016-08-10 14:33:34 +03:00
|
|
|
if (status)
|
|
|
|
status2 = freerdp_channels_pre_connect(instance->context->channels,
|
2016-10-11 12:20:54 +03:00
|
|
|
instance);
|
2016-08-10 14:33:34 +03:00
|
|
|
|
2012-11-07 19:33:06 +04:00
|
|
|
if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002)
|
2012-09-22 22:27:30 +04:00
|
|
|
{
|
2012-11-07 19:33:06 +04:00
|
|
|
settings->KeyboardType = 7;
|
|
|
|
settings->KeyboardSubType = 2;
|
|
|
|
settings->KeyboardFunctionKey = 12;
|
2012-09-22 22:27:30 +04:00
|
|
|
}
|
2012-08-24 20:25:59 +04:00
|
|
|
|
2016-08-10 14:33:34 +03:00
|
|
|
if (!status || (status2 != CHANNEL_RC_OK))
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2014-03-21 02:19:54 +04:00
|
|
|
if (!freerdp_get_last_error(rdp->context))
|
|
|
|
freerdp_set_last_error(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED);
|
|
|
|
|
2015-02-18 05:01:27 +03:00
|
|
|
WLog_ERR(TAG, "freerdp_pre_connect failed");
|
2013-07-29 03:11:41 +04:00
|
|
|
goto freerdp_connect_finally;
|
2011-12-09 22:53:19 +04:00
|
|
|
}
|
2011-08-27 04:26:40 +04:00
|
|
|
|
2011-10-16 08:50:10 +04:00
|
|
|
status = rdp_client_connect(rdp);
|
2013-05-01 02:25:18 +04:00
|
|
|
|
2012-09-04 01:08:46 +04:00
|
|
|
/* --authonly tests the connection without a UI */
|
2012-11-08 03:23:25 +04:00
|
|
|
if (instance->settings->AuthenticationOnly)
|
2012-09-04 01:08:46 +04:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "Authentication only, exit status %"PRId32"", !status);
|
2013-07-29 03:11:41 +04:00
|
|
|
goto freerdp_connect_finally;
|
|
|
|
}
|
2011-08-27 04:26:40 +04:00
|
|
|
|
2018-07-10 14:26:25 +03:00
|
|
|
if (instance->settings->DumpRemoteFx)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2018-07-10 14:26:25 +03:00
|
|
|
instance->update->pcap_rfx = pcap_open(instance->settings->DumpRemoteFxFile,
|
|
|
|
TRUE);
|
2016-08-10 14:33:34 +03:00
|
|
|
|
2018-07-10 14:26:25 +03:00
|
|
|
if (instance->update->pcap_rfx)
|
|
|
|
instance->update->dump_rfx = TRUE;
|
|
|
|
}
|
2011-08-27 04:26:40 +04:00
|
|
|
|
2018-07-10 14:26:25 +03:00
|
|
|
if (status)
|
|
|
|
{
|
2018-11-20 11:09:52 +03:00
|
|
|
pointer_cache_register_callbacks(instance->context->update);
|
2015-02-06 22:21:26 +03:00
|
|
|
IFCALLRET(instance->PostConnect, status, instance);
|
2018-06-19 18:28:22 +03:00
|
|
|
instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
|
2015-02-06 01:01:56 +03:00
|
|
|
|
2016-08-10 14:33:34 +03:00
|
|
|
if (status)
|
|
|
|
status2 = freerdp_channels_post_connect(instance->context->channels, instance);
|
2018-07-10 14:26:25 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
|
|
|
|
status = freerdp_reconnect(instance);
|
2018-07-13 14:11:38 +03:00
|
|
|
else
|
|
|
|
goto freerdp_connect_finally;
|
2018-07-10 14:26:25 +03:00
|
|
|
}
|
2016-08-10 14:33:34 +03:00
|
|
|
|
2018-07-10 14:26:25 +03:00
|
|
|
if (!status || (status2 != CHANNEL_RC_OK)
|
|
|
|
|| !update_post_connect(instance->update))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "freerdp_post_connect failed");
|
2013-05-29 17:53:28 +04:00
|
|
|
|
2018-07-10 14:26:25 +03:00
|
|
|
if (!freerdp_get_last_error(rdp->context))
|
|
|
|
freerdp_set_last_error(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED);
|
|
|
|
|
|
|
|
status = FALSE;
|
|
|
|
goto freerdp_connect_finally;
|
|
|
|
}
|
2014-03-21 02:19:54 +04:00
|
|
|
|
2018-07-10 14:26:25 +03:00
|
|
|
if (instance->settings->PlayRemoteFx)
|
|
|
|
{
|
|
|
|
wStream* s;
|
|
|
|
rdpUpdate* update;
|
|
|
|
pcap_record record;
|
|
|
|
update = instance->update;
|
|
|
|
update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE);
|
|
|
|
status = FALSE;
|
|
|
|
|
|
|
|
if (!update->pcap_rfx)
|
2013-07-29 03:11:41 +04:00
|
|
|
goto freerdp_connect_finally;
|
2018-07-10 14:26:25 +03:00
|
|
|
else
|
|
|
|
update->play_rfx = TRUE;
|
|
|
|
|
|
|
|
status = TRUE;
|
2011-08-28 23:51:49 +04:00
|
|
|
|
2018-07-10 14:26:25 +03:00
|
|
|
while (pcap_has_next_record(update->pcap_rfx) && status)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2018-07-10 14:26:25 +03:00
|
|
|
pcap_get_next_record_header(update->pcap_rfx, &record);
|
|
|
|
|
|
|
|
if (!(s = StreamPool_Take(rdp->transport->ReceivePool, record.length)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
record.data = Stream_Buffer(s);
|
|
|
|
pcap_get_next_record_content(update->pcap_rfx, &record);
|
|
|
|
Stream_SetLength(s, record.length);
|
|
|
|
Stream_SetPosition(s, 0);
|
|
|
|
|
2019-04-11 16:30:05 +03:00
|
|
|
if (!update_begin_paint(update))
|
2018-07-10 14:26:25 +03:00
|
|
|
status = FALSE;
|
2019-04-11 16:30:05 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (update_recv_surfcmds(update, s) < 0)
|
|
|
|
status = FALSE;
|
|
|
|
|
|
|
|
if (!update_end_paint(update))
|
|
|
|
status = FALSE;
|
|
|
|
}
|
2018-07-10 14:26:25 +03:00
|
|
|
|
|
|
|
Stream_Release(s);
|
2011-08-28 23:51:49 +04:00
|
|
|
}
|
2018-07-10 14:26:25 +03:00
|
|
|
|
|
|
|
pcap_close(update->pcap_rfx);
|
|
|
|
update->pcap_rfx = NULL;
|
|
|
|
goto freerdp_connect_finally;
|
2011-08-27 04:26:40 +04:00
|
|
|
}
|
2012-05-22 00:01:24 +04:00
|
|
|
|
2013-05-29 17:53:28 +04:00
|
|
|
if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
|
2016-08-09 13:04:06 +03:00
|
|
|
freerdp_set_last_error(instance->context,
|
2016-10-11 12:20:54 +03:00
|
|
|
FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
|
2013-05-29 17:53:28 +04:00
|
|
|
|
2013-05-01 02:25:18 +04:00
|
|
|
SetEvent(rdp->transport->connectedEvent);
|
2015-02-09 19:33:43 +03:00
|
|
|
freerdp_connect_finally:
|
2013-07-04 00:18:45 +04:00
|
|
|
EventArgsInit(&e, "freerdp");
|
|
|
|
e.result = status ? 0 : -1;
|
|
|
|
PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e);
|
2017-11-15 11:11:12 +03:00
|
|
|
|
|
|
|
if (!status)
|
|
|
|
freerdp_disconnect(instance);
|
|
|
|
|
2011-07-28 21:46:36 +04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2015-07-03 12:49:40 +03:00
|
|
|
BOOL freerdp_abort_connect(freerdp* instance)
|
|
|
|
{
|
|
|
|
if (!instance || !instance->context)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return SetEvent(instance->context->abortEvent);
|
|
|
|
}
|
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds,
|
2016-10-11 12:20:54 +03:00
|
|
|
int* wcount)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2015-02-15 18:06:17 +03:00
|
|
|
rdpRdp* rdp = instance->context->rdp;
|
2011-08-20 16:30:18 +04:00
|
|
|
transport_get_fds(rdp->transport, rfds, rcount);
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-07-28 21:46:36 +04:00
|
|
|
}
|
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL freerdp_check_fds(freerdp* instance)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2011-08-01 08:43:53 +04:00
|
|
|
int status;
|
2011-10-16 08:50:10 +04:00
|
|
|
rdpRdp* rdp;
|
2011-07-28 21:46:36 +04:00
|
|
|
|
2014-05-30 20:31:26 +04:00
|
|
|
if (!instance)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!instance->context)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!instance->context->rdp)
|
|
|
|
return FALSE;
|
2013-11-12 18:01:25 +04:00
|
|
|
|
2011-10-16 08:50:10 +04:00
|
|
|
rdp = instance->context->rdp;
|
2011-08-01 08:43:53 +04:00
|
|
|
status = rdp_check_fds(rdp);
|
2011-10-16 08:50:10 +04:00
|
|
|
|
2011-08-01 08:43:53 +04:00
|
|
|
if (status < 0)
|
2013-06-19 00:55:23 +04:00
|
|
|
{
|
|
|
|
TerminateEventArgs e;
|
|
|
|
rdpContext* context = instance->context;
|
2015-03-19 02:41:29 +03:00
|
|
|
WLog_DBG(TAG, "rdp_check_fds() - %i", status);
|
2013-06-19 00:55:23 +04:00
|
|
|
EventArgsInit(&e, "freerdp");
|
|
|
|
e.code = 0;
|
|
|
|
PubSub_OnTerminate(context->pubSub, context, &e);
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2013-06-19 00:55:23 +04:00
|
|
|
}
|
2011-07-29 01:44:09 +04:00
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-07-28 19:09:51 +04:00
|
|
|
}
|
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events,
|
2016-10-11 12:20:54 +03:00
|
|
|
DWORD count)
|
2015-01-30 06:57:58 +03:00
|
|
|
{
|
2015-04-21 13:35:55 +03:00
|
|
|
DWORD nCount = 0;
|
2015-04-21 13:24:50 +03:00
|
|
|
nCount += transport_get_event_handles(context->rdp->transport, events, count);
|
2015-01-30 17:47:02 +03:00
|
|
|
|
2015-04-21 13:24:50 +03:00
|
|
|
if (nCount == 0)
|
|
|
|
return 0;
|
|
|
|
|
2016-09-13 14:42:42 +03:00
|
|
|
if (events && (nCount < count + 2))
|
2015-07-15 10:50:35 +03:00
|
|
|
{
|
2015-04-21 13:24:50 +03:00
|
|
|
events[nCount++] = freerdp_channels_get_event_handle(context->instance);
|
2015-07-15 10:50:35 +03:00
|
|
|
events[nCount++] = getChannelErrorEventHandle(context);
|
2016-09-13 14:42:42 +03:00
|
|
|
events[nCount++] = context->abortEvent;
|
2015-07-15 10:50:35 +03:00
|
|
|
}
|
2015-04-21 13:24:50 +03:00
|
|
|
else
|
|
|
|
return 0;
|
2015-01-30 17:47:02 +03:00
|
|
|
|
2016-09-13 10:53:16 +03:00
|
|
|
if (context->settings->AsyncInput)
|
|
|
|
{
|
|
|
|
if (nCount >= count)
|
|
|
|
return 0;
|
2016-10-11 12:20:54 +03:00
|
|
|
|
2016-09-13 10:53:16 +03:00
|
|
|
events[nCount++] = freerdp_get_message_queue_event_handle(
|
2016-10-11 12:20:54 +03:00
|
|
|
context->instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
2016-09-13 10:53:16 +03:00
|
|
|
}
|
|
|
|
|
2015-01-30 17:47:02 +03:00
|
|
|
return nCount;
|
2015-01-30 06:57:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL freerdp_check_event_handles(rdpContext* context)
|
|
|
|
{
|
2015-01-30 17:47:02 +03:00
|
|
|
BOOL status;
|
|
|
|
status = freerdp_check_fds(context->instance);
|
|
|
|
|
|
|
|
if (!status)
|
2015-05-02 06:26:08 +03:00
|
|
|
{
|
2017-11-06 16:02:22 +03:00
|
|
|
if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
|
|
|
|
WLog_ERR(TAG, "freerdp_check_fds() failed - %"PRIi32"", status);
|
|
|
|
|
2015-01-30 17:47:02 +03:00
|
|
|
return FALSE;
|
2015-03-17 05:10:58 +03:00
|
|
|
}
|
2015-01-30 17:47:02 +03:00
|
|
|
|
|
|
|
status = freerdp_channels_check_fds(context->channels, context->instance);
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-05-02 06:26:08 +03:00
|
|
|
if (!status)
|
|
|
|
{
|
2017-11-06 16:02:22 +03:00
|
|
|
if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
|
|
|
|
WLog_ERR(TAG, "freerdp_channels_check_fds() failed - %"PRIi32"", status);
|
|
|
|
|
2015-03-17 05:10:58 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
2015-01-30 17:47:02 +03:00
|
|
|
|
2015-07-15 10:50:35 +03:00
|
|
|
if (!status)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
status = checkChannelErrorEvent(context);
|
2016-09-13 10:53:16 +03:00
|
|
|
|
|
|
|
if (!status)
|
2018-07-09 18:45:50 +03:00
|
|
|
{
|
|
|
|
if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
|
|
|
|
WLog_ERR(TAG, "checkChannelErrorEvent() failed - %"PRIi32"", status);
|
2018-07-10 13:04:27 +03:00
|
|
|
|
2016-09-13 10:53:16 +03:00
|
|
|
return FALSE;
|
2018-07-09 18:45:50 +03:00
|
|
|
}
|
2016-09-13 10:53:16 +03:00
|
|
|
|
|
|
|
if (context->settings->AsyncInput)
|
|
|
|
{
|
2018-07-09 18:45:50 +03:00
|
|
|
int rc = freerdp_message_queue_process_pending_messages(
|
2016-10-11 12:20:54 +03:00
|
|
|
context->instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
2018-07-10 13:04:27 +03:00
|
|
|
|
2018-07-09 18:45:50 +03:00
|
|
|
if (rc < 0)
|
|
|
|
return FALSE;
|
|
|
|
else
|
|
|
|
status = TRUE;
|
2016-09-13 10:53:16 +03:00
|
|
|
}
|
|
|
|
|
2015-01-30 17:47:02 +03:00
|
|
|
return status;
|
2015-01-30 06:57:58 +03:00
|
|
|
}
|
|
|
|
|
2013-02-05 00:47:13 +04:00
|
|
|
wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id)
|
2013-01-25 21:08:00 +04:00
|
|
|
{
|
2013-02-05 00:47:13 +04:00
|
|
|
wMessageQueue* queue = NULL;
|
2013-01-25 21:08:00 +04:00
|
|
|
|
2013-02-05 00:47:13 +04:00
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case FREERDP_UPDATE_MESSAGE_QUEUE:
|
|
|
|
queue = instance->update->queue;
|
|
|
|
break;
|
2013-01-25 21:08:00 +04:00
|
|
|
|
2013-02-05 00:47:13 +04:00
|
|
|
case FREERDP_INPUT_MESSAGE_QUEUE:
|
|
|
|
queue = instance->input->queue;
|
|
|
|
break;
|
|
|
|
}
|
2013-01-25 21:08:00 +04:00
|
|
|
|
2013-02-05 00:47:13 +04:00
|
|
|
return queue;
|
2013-01-25 21:08:00 +04:00
|
|
|
}
|
|
|
|
|
2013-02-05 00:47:13 +04:00
|
|
|
HANDLE freerdp_get_message_queue_event_handle(freerdp* instance, DWORD id)
|
2013-01-28 06:07:17 +04:00
|
|
|
{
|
|
|
|
HANDLE event = NULL;
|
2013-02-05 00:47:13 +04:00
|
|
|
wMessageQueue* queue = NULL;
|
|
|
|
queue = freerdp_get_message_queue(instance, id);
|
|
|
|
|
|
|
|
if (queue)
|
|
|
|
event = MessageQueue_Event(queue);
|
2013-01-28 06:07:17 +04:00
|
|
|
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
int freerdp_message_queue_process_message(freerdp* instance, DWORD id,
|
2016-10-11 12:20:54 +03:00
|
|
|
wMessage* message)
|
2013-02-05 00:47:13 +04:00
|
|
|
{
|
|
|
|
int status = -1;
|
|
|
|
|
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case FREERDP_UPDATE_MESSAGE_QUEUE:
|
|
|
|
status = update_message_queue_process_message(instance->update, message);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_INPUT_MESSAGE_QUEUE:
|
|
|
|
status = input_message_queue_process_message(instance->input, message);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id)
|
2013-01-28 06:07:17 +04:00
|
|
|
{
|
2013-02-05 00:47:13 +04:00
|
|
|
int status = -1;
|
|
|
|
|
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case FREERDP_UPDATE_MESSAGE_QUEUE:
|
|
|
|
status = update_message_queue_process_pending_messages(instance->update);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_INPUT_MESSAGE_QUEUE:
|
|
|
|
status = input_message_queue_process_pending_messages(instance->input);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
2013-01-28 06:07:17 +04:00
|
|
|
}
|
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
static int freerdp_send_channel_data(freerdp* instance, UINT16 channelId,
|
2016-10-11 12:20:54 +03:00
|
|
|
BYTE* data, int size)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2014-02-14 02:06:33 +04:00
|
|
|
return rdp_send_channel_data(instance->context->rdp, channelId, data, size);
|
2011-08-03 07:00:56 +04:00
|
|
|
}
|
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL freerdp_disconnect(freerdp* instance)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2016-08-09 17:48:02 +03:00
|
|
|
BOOL rc = TRUE;
|
2011-08-24 19:07:55 +04:00
|
|
|
rdpRdp* rdp;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
|
|
|
if (!instance || !instance->context || !instance->context->rdp)
|
|
|
|
return FALSE;
|
|
|
|
|
2011-10-16 08:50:10 +04:00
|
|
|
rdp = instance->context->rdp;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
|
|
|
if (!rdp_client_disconnect(rdp))
|
|
|
|
rc = FALSE;
|
|
|
|
|
2014-07-14 21:27:50 +04:00
|
|
|
update_post_disconnect(instance->update);
|
2016-08-09 23:37:02 +03:00
|
|
|
|
2016-09-13 10:53:16 +03:00
|
|
|
if (instance->settings->AsyncInput)
|
|
|
|
{
|
|
|
|
wMessageQueue* inputQueue = freerdp_get_message_queue(instance,
|
2016-10-11 12:20:54 +03:00
|
|
|
FREERDP_INPUT_MESSAGE_QUEUE);
|
|
|
|
MessageQueue_PostQuit(inputQueue, 0);
|
2016-09-13 10:53:16 +03:00
|
|
|
}
|
|
|
|
|
2016-09-06 15:20:07 +03:00
|
|
|
IFCALL(instance->PostDisconnect, instance);
|
|
|
|
|
2013-08-29 13:07:19 +04:00
|
|
|
if (instance->update->pcap_rfx)
|
|
|
|
{
|
|
|
|
instance->update->dump_rfx = FALSE;
|
|
|
|
pcap_close(instance->update->pcap_rfx);
|
|
|
|
instance->update->pcap_rfx = NULL;
|
|
|
|
}
|
|
|
|
|
2016-08-09 23:37:02 +03:00
|
|
|
freerdp_channels_close(instance->context->channels, instance);
|
2016-08-09 17:48:02 +03:00
|
|
|
return rc;
|
2011-08-24 19:07:55 +04:00
|
|
|
}
|
|
|
|
|
2018-04-09 15:03:05 +03:00
|
|
|
BOOL freerdp_disconnect_before_reconnect(freerdp* instance)
|
|
|
|
{
|
|
|
|
rdpRdp* rdp = instance->context->rdp;
|
2018-04-11 10:30:40 +03:00
|
|
|
return rdp_client_disconnect_and_clear(rdp);
|
2018-04-09 15:03:05 +03:00
|
|
|
}
|
|
|
|
|
2014-01-17 02:38:56 +04:00
|
|
|
BOOL freerdp_reconnect(freerdp* instance)
|
|
|
|
{
|
2015-02-06 22:21:26 +03:00
|
|
|
BOOL status;
|
2015-02-06 01:01:56 +03:00
|
|
|
rdpRdp* rdp = instance->context->rdp;
|
2016-02-10 13:20:52 +03:00
|
|
|
ResetEvent(instance->context->abortEvent);
|
2015-02-06 22:21:26 +03:00
|
|
|
status = rdp_client_reconnect(rdp);
|
2015-02-06 01:01:56 +03:00
|
|
|
return status;
|
2014-01-17 02:38:56 +04:00
|
|
|
}
|
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL freerdp_shall_disconnect(freerdp* instance)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2015-09-05 15:57:30 +03:00
|
|
|
if (!instance || !instance->context)
|
|
|
|
return FALSE;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-09-05 15:57:30 +03:00
|
|
|
if (WaitForSingleObject(instance->context->abortEvent, 0) != WAIT_OBJECT_0)
|
2015-07-30 09:18:57 +03:00
|
|
|
return FALSE;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-09-05 15:57:30 +03:00
|
|
|
return TRUE;
|
2012-02-07 01:37:18 +04:00
|
|
|
}
|
|
|
|
|
2016-02-26 21:25:49 +03:00
|
|
|
BOOL freerdp_focus_required(freerdp* instance)
|
2013-04-15 14:14:09 +04:00
|
|
|
{
|
|
|
|
rdpRdp* rdp;
|
|
|
|
BOOL bRetCode = FALSE;
|
|
|
|
rdp = instance->context->rdp;
|
|
|
|
|
|
|
|
if (rdp->resendFocus)
|
|
|
|
{
|
|
|
|
bRetCode = TRUE;
|
|
|
|
rdp->resendFocus = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bRetCode;
|
|
|
|
}
|
|
|
|
|
2014-10-03 18:27:47 +04:00
|
|
|
void freerdp_set_focus(freerdp* instance)
|
|
|
|
{
|
|
|
|
rdpRdp* rdp;
|
|
|
|
rdp = instance->context->rdp;
|
|
|
|
rdp->resendFocus = TRUE;
|
|
|
|
}
|
|
|
|
|
2012-02-27 13:13:39 +04:00
|
|
|
void freerdp_get_version(int* major, int* minor, int* revision)
|
|
|
|
{
|
2012-01-14 22:33:04 +04:00
|
|
|
if (major != NULL)
|
|
|
|
*major = FREERDP_VERSION_MAJOR;
|
|
|
|
|
|
|
|
if (minor != NULL)
|
|
|
|
*minor = FREERDP_VERSION_MINOR;
|
|
|
|
|
|
|
|
if (revision != NULL)
|
|
|
|
*revision = FREERDP_VERSION_REVISION;
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:09:02 +03:00
|
|
|
const char* freerdp_get_version_string(void)
|
2015-03-30 18:50:47 +03:00
|
|
|
{
|
|
|
|
return FREERDP_VERSION_FULL;
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:09:02 +03:00
|
|
|
const char* freerdp_get_build_date(void)
|
2015-03-30 18:50:47 +03:00
|
|
|
{
|
2016-01-28 16:26:50 +03:00
|
|
|
static char build_date[] = __DATE__ " " __TIME__;
|
2015-03-30 18:50:47 +03:00
|
|
|
return build_date;
|
|
|
|
}
|
|
|
|
|
2016-01-28 16:26:50 +03:00
|
|
|
const char* freerdp_get_build_config(void)
|
|
|
|
{
|
|
|
|
static const char build_config[] =
|
2016-08-09 13:04:06 +03:00
|
|
|
"Build configuration: " BUILD_CONFIG "\n"
|
|
|
|
"Build type: " BUILD_TYPE "\n"
|
|
|
|
"CFLAGS: " CFLAGS "\n"
|
|
|
|
"Compiler: " COMPILER_ID ", " COMPILER_VERSION "\n"
|
|
|
|
"Target architecture: " TARGET_ARCH "\n";
|
2016-01-28 16:26:50 +03:00
|
|
|
return build_config;
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:09:02 +03:00
|
|
|
const char* freerdp_get_build_revision(void)
|
2015-03-30 18:50:47 +03:00
|
|
|
{
|
|
|
|
return GIT_REVISION;
|
|
|
|
}
|
|
|
|
|
2013-06-19 05:23:26 +04:00
|
|
|
static wEventType FreeRDP_Events[] =
|
2013-06-16 01:39:45 +04:00
|
|
|
{
|
2015-02-09 19:33:43 +03:00
|
|
|
DEFINE_EVENT_ENTRY(WindowStateChange)
|
|
|
|
DEFINE_EVENT_ENTRY(ResizeWindow)
|
|
|
|
DEFINE_EVENT_ENTRY(LocalResizeWindow)
|
|
|
|
DEFINE_EVENT_ENTRY(EmbedWindow)
|
|
|
|
DEFINE_EVENT_ENTRY(PanningChange)
|
|
|
|
DEFINE_EVENT_ENTRY(ZoomingChange)
|
|
|
|
DEFINE_EVENT_ENTRY(ErrorInfo)
|
|
|
|
DEFINE_EVENT_ENTRY(Terminate)
|
|
|
|
DEFINE_EVENT_ENTRY(ConnectionResult)
|
|
|
|
DEFINE_EVENT_ENTRY(ChannelConnected)
|
|
|
|
DEFINE_EVENT_ENTRY(ChannelDisconnected)
|
|
|
|
DEFINE_EVENT_ENTRY(MouseEvent)
|
2017-12-19 11:38:24 +03:00
|
|
|
DEFINE_EVENT_ENTRY(Activated)
|
|
|
|
DEFINE_EVENT_ENTRY(Timer)
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
DEFINE_EVENT_ENTRY(GraphicsReset)
|
2013-06-16 01:39:45 +04:00
|
|
|
};
|
|
|
|
|
2012-02-23 19:22:05 +04:00
|
|
|
/** Allocator function for a rdp context.
|
|
|
|
* The function will allocate a rdpRdp structure using rdp_new(), then copy
|
2012-02-23 19:30:04 +04:00
|
|
|
* its contents to the appropriate fields in the rdp_freerdp structure given in parameters.
|
2012-03-02 01:06:03 +04:00
|
|
|
* It will also initialize the 'context' field in the rdp_freerdp structure as needed.
|
2012-02-23 19:30:04 +04:00
|
|
|
* If the caller has set the ContextNew callback in the 'instance' parameter, it will be called at the end of the function.
|
2012-02-23 19:22:05 +04:00
|
|
|
*
|
|
|
|
* @param instance - Pointer to the rdp_freerdp structure that will be initialized with the new context.
|
|
|
|
*/
|
2015-04-28 18:00:41 +03:00
|
|
|
BOOL freerdp_context_new(freerdp* instance)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2011-10-16 08:50:10 +04:00
|
|
|
rdpRdp* rdp;
|
2013-06-14 06:11:23 +04:00
|
|
|
rdpContext* context;
|
2015-04-28 18:00:41 +03:00
|
|
|
BOOL ret = TRUE;
|
2015-03-23 19:25:23 +03:00
|
|
|
instance->context = (rdpContext*) calloc(1, instance->ContextSize);
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-23 19:25:23 +03:00
|
|
|
if (!instance->context)
|
2015-04-28 18:00:41 +03:00
|
|
|
return FALSE;
|
2013-07-20 05:52:28 +04:00
|
|
|
|
2013-06-19 00:55:23 +04:00
|
|
|
context = instance->context;
|
2013-07-20 05:52:28 +04:00
|
|
|
context->instance = instance;
|
2013-10-13 02:20:25 +04:00
|
|
|
context->ServerMode = FALSE;
|
|
|
|
context->settings = instance->settings;
|
2018-09-19 17:36:39 +03:00
|
|
|
context->disconnectUltimatum = 0;
|
2013-06-19 00:55:23 +04:00
|
|
|
context->pubSub = PubSub_New(TRUE);
|
2016-08-09 13:04:06 +03:00
|
|
|
|
|
|
|
if (!context->pubSub)
|
2016-08-09 17:48:02 +03:00
|
|
|
goto fail;
|
2013-06-19 00:55:23 +04:00
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
PubSub_AddEventTypes(context->pubSub, FreeRDP_Events,
|
2018-02-14 12:14:33 +03:00
|
|
|
ARRAYSIZE(FreeRDP_Events));
|
2014-05-26 20:30:58 +04:00
|
|
|
context->metrics = metrics_new(context);
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-23 19:25:23 +03:00
|
|
|
if (!context->metrics)
|
2016-08-09 17:48:02 +03:00
|
|
|
goto fail;
|
2015-03-23 19:25:23 +03:00
|
|
|
|
2013-07-20 05:52:28 +04:00
|
|
|
rdp = rdp_new(context);
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-23 19:25:23 +03:00
|
|
|
if (!rdp)
|
2016-08-09 17:48:02 +03:00
|
|
|
goto fail;
|
2015-03-23 19:25:23 +03:00
|
|
|
|
2011-10-16 08:50:10 +04:00
|
|
|
instance->input = rdp->input;
|
|
|
|
instance->update = rdp->update;
|
|
|
|
instance->settings = rdp->settings;
|
2014-10-28 18:29:40 +03:00
|
|
|
instance->autodetect = rdp->autodetect;
|
2013-06-14 06:11:23 +04:00
|
|
|
context->graphics = graphics_new(context);
|
2016-08-09 13:04:06 +03:00
|
|
|
|
|
|
|
if (!context->graphics)
|
2016-08-09 17:48:02 +03:00
|
|
|
goto fail;
|
2015-03-23 19:25:23 +03:00
|
|
|
|
2013-06-14 06:11:23 +04:00
|
|
|
context->rdp = rdp;
|
|
|
|
context->input = instance->input;
|
|
|
|
context->update = instance->update;
|
|
|
|
context->settings = instance->settings;
|
2014-10-28 18:29:40 +03:00
|
|
|
context->autodetect = instance->autodetect;
|
2011-10-16 08:50:10 +04:00
|
|
|
instance->update->context = instance->context;
|
2011-11-22 02:48:03 +04:00
|
|
|
instance->update->pointer->context = instance->context;
|
2011-11-22 03:11:43 +04:00
|
|
|
instance->update->primary->context = instance->context;
|
2011-11-22 04:41:49 +04:00
|
|
|
instance->update->secondary->context = instance->context;
|
2011-11-22 04:53:38 +04:00
|
|
|
instance->update->altsec->context = instance->context;
|
2013-06-14 06:11:23 +04:00
|
|
|
instance->input->context = context;
|
2014-10-28 18:29:40 +03:00
|
|
|
instance->autodetect->context = context;
|
|
|
|
|
2015-07-15 10:50:35 +03:00
|
|
|
if (!(context->errorDescription = calloc(1, 500)))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
2016-08-09 17:48:02 +03:00
|
|
|
goto fail;
|
2015-07-15 10:50:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(context->channelErrorEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "CreateEvent failed!");
|
2016-08-09 17:48:02 +03:00
|
|
|
goto fail;
|
2015-07-15 10:50:35 +03:00
|
|
|
}
|
|
|
|
|
2012-05-26 17:34:09 +04:00
|
|
|
update_register_client_callbacks(rdp->update);
|
2015-07-03 12:49:40 +03:00
|
|
|
instance->context->abortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-07-03 12:49:40 +03:00
|
|
|
if (!instance->context->abortEvent)
|
2016-08-09 17:48:02 +03:00
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (!(context->channels = freerdp_channels_new(instance)))
|
|
|
|
goto fail;
|
2015-07-03 12:49:40 +03:00
|
|
|
|
2015-04-28 18:00:41 +03:00
|
|
|
IFCALLRET(instance->ContextNew, ret, instance, instance->context);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return TRUE;
|
2015-08-04 14:34:28 +03:00
|
|
|
|
2016-08-09 17:48:02 +03:00
|
|
|
fail:
|
|
|
|
freerdp_context_free(instance);
|
2015-04-28 18:00:41 +03:00
|
|
|
return FALSE;
|
2011-10-16 08:50:10 +04:00
|
|
|
}
|
|
|
|
|
2012-02-23 19:22:05 +04:00
|
|
|
/** Deallocator function for a rdp context.
|
|
|
|
* The function will deallocate the resources from the 'instance' parameter that were allocated from a call
|
|
|
|
* to freerdp_context_new().
|
|
|
|
* If the ContextFree callback is set in the 'instance' parameter, it will be called before deallocation occurs.
|
|
|
|
*
|
|
|
|
* @param instance - Pointer to the rdp_freerdp structure that was initialized by a call to freerdp_context_new().
|
|
|
|
* On return, the fields associated to the context are invalid.
|
|
|
|
*/
|
2012-02-27 13:13:39 +04:00
|
|
|
void freerdp_context_free(freerdp* instance)
|
|
|
|
{
|
2013-11-01 05:12:06 +04:00
|
|
|
if (!instance)
|
|
|
|
return;
|
|
|
|
|
2013-04-12 21:44:23 +04:00
|
|
|
if (!instance->context)
|
2012-02-11 00:35:22 +04:00
|
|
|
return;
|
2012-02-11 00:50:29 +04:00
|
|
|
|
2011-10-16 08:50:10 +04:00
|
|
|
IFCALL(instance->ContextFree, instance, instance->context);
|
2012-02-02 03:42:20 +04:00
|
|
|
rdp_free(instance->context->rdp);
|
2013-06-28 17:18:20 +04:00
|
|
|
instance->context->rdp = NULL;
|
2012-02-02 03:42:20 +04:00
|
|
|
graphics_free(instance->context->graphics);
|
2013-06-28 17:18:20 +04:00
|
|
|
instance->context->graphics = NULL;
|
2013-06-16 01:39:45 +04:00
|
|
|
PubSub_Free(instance->context->pubSub);
|
2014-05-26 20:30:58 +04:00
|
|
|
metrics_free(instance->context->metrics);
|
2015-07-15 10:50:35 +03:00
|
|
|
CloseHandle(instance->context->channelErrorEvent);
|
|
|
|
free(instance->context->errorDescription);
|
2015-07-03 12:49:40 +03:00
|
|
|
CloseHandle(instance->context->abortEvent);
|
|
|
|
instance->context->abortEvent = NULL;
|
2016-08-09 17:48:02 +03:00
|
|
|
freerdp_channels_free(instance->context->channels);
|
2012-10-09 07:21:26 +04:00
|
|
|
free(instance->context);
|
2012-02-11 00:35:22 +04:00
|
|
|
instance->context = NULL;
|
2011-10-16 08:50:10 +04:00
|
|
|
}
|
|
|
|
|
2018-09-19 17:36:39 +03:00
|
|
|
int freerdp_get_disconnect_ultimatum(rdpContext* context)
|
2018-09-18 23:31:10 +03:00
|
|
|
{
|
2018-09-19 17:36:39 +03:00
|
|
|
return context->disconnectUltimatum;
|
2018-09-18 23:31:10 +03:00
|
|
|
}
|
|
|
|
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 freerdp_error_info(freerdp* instance)
|
2012-02-27 13:13:39 +04:00
|
|
|
{
|
2011-10-24 22:37:21 +04:00
|
|
|
return instance->context->rdp->errorInfo;
|
|
|
|
}
|
|
|
|
|
2016-03-14 17:27:15 +03:00
|
|
|
void freerdp_set_error_info(rdpRdp* rdp, UINT32 error)
|
|
|
|
{
|
|
|
|
if (!rdp)
|
|
|
|
return;
|
|
|
|
|
2016-02-04 13:40:42 +03:00
|
|
|
rdp_set_error_info(rdp, error);
|
2015-01-13 19:09:36 +03:00
|
|
|
}
|
|
|
|
|
2019-05-19 14:34:00 +03:00
|
|
|
BOOL freerdp_send_error_info(rdpRdp* rdp)
|
|
|
|
{
|
|
|
|
if (!rdp)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return rdp_send_error_info(rdp);
|
|
|
|
}
|
|
|
|
|
2014-03-23 01:42:44 +04:00
|
|
|
UINT32 freerdp_get_last_error(rdpContext* context)
|
|
|
|
{
|
|
|
|
return context->LastError;
|
|
|
|
}
|
|
|
|
|
2015-03-19 13:05:16 +03:00
|
|
|
const char* freerdp_get_last_error_name(UINT32 code)
|
|
|
|
{
|
2016-08-09 13:04:06 +03:00
|
|
|
const char* name = NULL;
|
2015-03-19 13:05:16 +03:00
|
|
|
const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
|
|
|
|
const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
|
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
switch (cls)
|
2015-03-19 13:05:16 +03:00
|
|
|
{
|
|
|
|
case FREERDP_ERROR_ERRBASE_CLASS:
|
|
|
|
name = freerdp_get_error_base_name(type);
|
|
|
|
break;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-19 13:05:16 +03:00
|
|
|
case FREERDP_ERROR_ERRINFO_CLASS:
|
|
|
|
name = freerdp_get_error_info_name(type);
|
|
|
|
break;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-19 13:05:16 +03:00
|
|
|
case FREERDP_ERROR_CONNECT_CLASS:
|
|
|
|
name = freerdp_get_error_connect_name(type);
|
|
|
|
break;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-19 13:05:16 +03:00
|
|
|
default:
|
2019-10-01 10:47:26 +03:00
|
|
|
name = rpc_error_to_string(code);
|
2015-03-19 13:05:16 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* freerdp_get_last_error_string(UINT32 code)
|
|
|
|
{
|
|
|
|
const char* string = NULL;
|
|
|
|
const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
|
|
|
|
const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
|
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
switch (cls)
|
2015-03-19 13:05:16 +03:00
|
|
|
{
|
|
|
|
case FREERDP_ERROR_ERRBASE_CLASS:
|
|
|
|
string = freerdp_get_error_base_string(type);
|
|
|
|
break;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-19 13:05:16 +03:00
|
|
|
case FREERDP_ERROR_ERRINFO_CLASS:
|
|
|
|
string = freerdp_get_error_info_string(type);
|
|
|
|
break;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-19 13:05:16 +03:00
|
|
|
case FREERDP_ERROR_CONNECT_CLASS:
|
|
|
|
string = freerdp_get_error_connect_string(type);
|
|
|
|
break;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-03-19 13:05:16 +03:00
|
|
|
default:
|
2019-10-01 10:47:26 +03:00
|
|
|
string = rpc_error_to_string(code);
|
2015-03-19 13:05:16 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
2014-03-23 01:42:44 +04:00
|
|
|
void freerdp_set_last_error(rdpContext* context, UINT32 lastError)
|
|
|
|
{
|
|
|
|
if (lastError)
|
2019-09-23 12:22:45 +03:00
|
|
|
WLog_ERR(TAG, "%s %s [0x%08"PRIX32"]", __FUNCTION__,
|
2016-10-11 12:20:54 +03:00
|
|
|
freerdp_get_last_error_name(lastError), lastError);
|
2014-03-23 01:42:44 +04:00
|
|
|
|
2019-09-23 12:22:45 +03:00
|
|
|
if (lastError == FREERDP_ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WLog_INFO(TAG, "%s resetting error state", __FUNCTION__);
|
|
|
|
}
|
|
|
|
else if (context->LastError != 0)
|
2016-12-19 16:13:36 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "TODO: Trying to set error code %s, but %s already set!",
|
|
|
|
freerdp_get_last_error_name(lastError),
|
|
|
|
freerdp_get_last_error_name(context->LastError));
|
|
|
|
}
|
|
|
|
|
2014-03-23 01:42:44 +04:00
|
|
|
context->LastError = lastError;
|
2015-02-18 05:01:27 +03:00
|
|
|
|
|
|
|
switch (lastError)
|
|
|
|
{
|
|
|
|
case FREERDP_ERROR_PRE_CONNECT_FAILED:
|
|
|
|
connectErrorCode = PREECONNECTERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_CONNECT_UNDEFINED:
|
|
|
|
connectErrorCode = UNDEFINEDCONNECTERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_POST_CONNECT_FAILED:
|
|
|
|
connectErrorCode = POSTCONNECTERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_DNS_ERROR:
|
|
|
|
connectErrorCode = DNSERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
|
|
|
|
connectErrorCode = DNSNAMENOTFOUND;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_CONNECT_FAILED:
|
|
|
|
connectErrorCode = CONNECTERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR:
|
|
|
|
connectErrorCode = MCSCONNECTINITIALERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_TLS_CONNECT_FAILED:
|
|
|
|
connectErrorCode = TLSCONNECTERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_AUTHENTICATION_FAILED:
|
|
|
|
connectErrorCode = AUTHENTICATIONERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_INSUFFICIENT_PRIVILEGES:
|
|
|
|
connectErrorCode = INSUFFICIENTPRIVILEGESERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_CONNECT_CANCELLED:
|
|
|
|
connectErrorCode = CANCELEDBYUSER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
|
|
|
|
connectErrorCode = CONNECTERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
|
|
|
|
connectErrorCode = CONNECTERROR;
|
|
|
|
break;
|
|
|
|
}
|
2014-03-23 01:42:44 +04:00
|
|
|
}
|
|
|
|
|
2017-03-01 13:38:37 +03:00
|
|
|
const char* freerdp_get_logon_error_info_type(UINT32 type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case LOGON_MSG_DISCONNECT_REFUSED:
|
|
|
|
return "LOGON_MSG_DISCONNECT_REFUSED";
|
|
|
|
|
|
|
|
case LOGON_MSG_NO_PERMISSION:
|
|
|
|
return "LOGON_MSG_NO_PERMISSION";
|
|
|
|
|
|
|
|
case LOGON_MSG_BUMP_OPTIONS:
|
|
|
|
return "LOGON_MSG_BUMP_OPTIONS";
|
|
|
|
|
|
|
|
case LOGON_MSG_RECONNECT_OPTIONS:
|
|
|
|
return "LOGON_MSG_RECONNECT_OPTIONS";
|
|
|
|
|
|
|
|
case LOGON_MSG_SESSION_TERMINATE:
|
|
|
|
return "LOGON_MSG_SESSION_TERMINATE";
|
|
|
|
|
|
|
|
case LOGON_MSG_SESSION_CONTINUE:
|
|
|
|
return "LOGON_MSG_SESSION_CONTINUE";
|
|
|
|
|
|
|
|
default:
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* freerdp_get_logon_error_info_data(UINT32 data)
|
|
|
|
{
|
|
|
|
switch (data)
|
|
|
|
{
|
|
|
|
case LOGON_FAILED_BAD_PASSWORD:
|
|
|
|
return "LOGON_FAILED_BAD_PASSWORD";
|
|
|
|
|
|
|
|
case LOGON_FAILED_UPDATE_PASSWORD:
|
|
|
|
return "LOGON_FAILED_UPDATE_PASSWORD";
|
|
|
|
|
|
|
|
case LOGON_FAILED_OTHER:
|
|
|
|
return "LOGON_FAILED_OTHER";
|
|
|
|
|
|
|
|
case LOGON_WARNING:
|
|
|
|
return "LOGON_WARNING";
|
|
|
|
|
|
|
|
default:
|
|
|
|
return "SESSION_ID";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-23 19:22:05 +04:00
|
|
|
/** Allocator function for the rdp_freerdp structure.
|
|
|
|
* @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free()
|
|
|
|
*/
|
2012-02-27 13:13:39 +04:00
|
|
|
freerdp* freerdp_new()
|
|
|
|
{
|
2011-07-28 08:38:25 +04:00
|
|
|
freerdp* instance;
|
2015-03-23 19:25:23 +03:00
|
|
|
instance = (freerdp*) calloc(1, sizeof(freerdp));
|
2011-07-28 08:38:25 +04:00
|
|
|
|
2015-03-23 19:25:23 +03:00
|
|
|
if (!instance)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
instance->ContextSize = sizeof(rdpContext);
|
|
|
|
instance->SendChannelData = freerdp_send_channel_data;
|
|
|
|
instance->ReceiveChannelData = freerdp_channels_data;
|
2011-07-28 08:38:25 +04:00
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2012-02-23 19:22:05 +04:00
|
|
|
/** Deallocator function for the rdp_freerdp structure.
|
|
|
|
* @param instance - pointer to the rdp_freerdp structure to deallocate.
|
|
|
|
* On return, this pointer is not valid anymore.
|
|
|
|
*/
|
2012-02-27 13:13:39 +04:00
|
|
|
void freerdp_free(freerdp* instance)
|
|
|
|
{
|
2015-05-11 10:07:39 +03:00
|
|
|
free(instance);
|
2011-07-28 08:38:25 +04:00
|
|
|
}
|
2015-04-14 13:49:01 +03:00
|
|
|
|
2016-08-09 13:04:06 +03:00
|
|
|
ULONG freerdp_get_transport_sent(rdpContext* context, BOOL resetCount)
|
|
|
|
{
|
2015-04-14 13:49:01 +03:00
|
|
|
ULONG written = context->rdp->transport->written;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-04-14 13:49:01 +03:00
|
|
|
if (resetCount)
|
|
|
|
context->rdp->transport->written = 0;
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-04-14 13:49:01 +03:00
|
|
|
return written;
|
|
|
|
}
|
2015-07-15 10:50:35 +03:00
|
|
|
|
2019-03-08 12:10:43 +03:00
|
|
|
BOOL freerdp_nla_impersonate(rdpContext* context)
|
|
|
|
{
|
|
|
|
rdpNla* nla;
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!context->rdp)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!context->rdp->transport)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
nla = context->rdp->transport->nla;
|
|
|
|
return nla_impersonate(nla);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL freerdp_nla_revert_to_self(rdpContext* context)
|
|
|
|
{
|
|
|
|
rdpNla* nla;
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!context->rdp)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!context->rdp->transport)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
nla = context->rdp->transport->nla;
|
|
|
|
return nla_revert_to_self(nla);
|
|
|
|
}
|
|
|
|
|
2016-02-26 21:25:49 +03:00
|
|
|
HANDLE getChannelErrorEventHandle(rdpContext* context)
|
2015-07-15 10:50:35 +03:00
|
|
|
{
|
|
|
|
return context->channelErrorEvent;
|
|
|
|
}
|
|
|
|
|
2016-02-26 21:25:49 +03:00
|
|
|
BOOL checkChannelErrorEvent(rdpContext* context)
|
2015-07-15 10:50:35 +03:00
|
|
|
{
|
2016-08-09 13:04:06 +03:00
|
|
|
if (WaitForSingleObject(context->channelErrorEvent, 0) == WAIT_OBJECT_0)
|
2015-07-15 10:50:35 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "%s. Error was %"PRIu32"", context->errorDescription,
|
2016-10-11 12:20:54 +03:00
|
|
|
context->channelErrorNum);
|
2015-07-15 10:50:35 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
2016-08-09 13:04:06 +03:00
|
|
|
|
2015-07-15 10:50:35 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2016-02-26 21:25:49 +03:00
|
|
|
UINT getChannelError(rdpContext* context)
|
2015-07-15 10:50:35 +03:00
|
|
|
{
|
|
|
|
return context->channelErrorNum;
|
|
|
|
}
|
2015-09-03 14:43:08 +03:00
|
|
|
|
2016-02-26 21:25:49 +03:00
|
|
|
const char* getChannelErrorDescription(rdpContext* context)
|
2015-07-15 10:50:35 +03:00
|
|
|
{
|
|
|
|
return context->errorDescription;
|
|
|
|
}
|
2015-09-03 14:43:08 +03:00
|
|
|
|
2016-02-26 21:25:49 +03:00
|
|
|
void clearChannelError(rdpContext* context)
|
2015-09-03 14:43:08 +03:00
|
|
|
{
|
|
|
|
context->channelErrorNum = 0;
|
|
|
|
memset(context->errorDescription, 0, 500);
|
|
|
|
ResetEvent(context->channelErrorEvent);
|
|
|
|
}
|
|
|
|
|
2016-02-26 21:25:49 +03:00
|
|
|
void setChannelError(rdpContext* context, UINT errorNum, char* description)
|
2015-07-15 10:50:35 +03:00
|
|
|
{
|
|
|
|
context->channelErrorNum = errorNum;
|
|
|
|
strncpy(context->errorDescription, description, 499);
|
|
|
|
SetEvent(context->channelErrorEvent);
|
|
|
|
}
|
2019-05-17 15:32:54 +03:00
|
|
|
|
|
|
|
const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length)
|
|
|
|
{
|
|
|
|
if (!context || !context->rdp)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return (const char*)nego_get_routing_token(context->rdp->nego, length);
|
|
|
|
}
|