FreeRDP的连接过程分析
Posted 道亦无名
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FreeRDP的连接过程分析相关的知识,希望对你有一定的参考价值。
代码如下:
/** 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
*
* @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.
*
* @return TRUE if successful. FALSE otherwise.
*
*/
BOOL freerdp_connect(freerdp* instance)
{
UINT status2 = CHANNEL_RC_OK;
rdpRdp* rdp;
BOOL status = TRUE;
rdpSettings* settings;
ConnectionResultEventArgs e;
if (!instance)
return FALSE;
WINPR_ASSERT(instance->context);
/* We always set the return code to 0 before we start the connect sequence*/
instance->ConnectionCallbackState = CLIENT_STATE_INITIAL;
freerdp_set_last_error_log(instance->context, FREERDP_ERROR_SUCCESS);
clearChannelError(instance->context);
ResetEvent(instance->context->abortEvent);
rdp = instance->context->rdp;
WINPR_ASSERT(rdp);
settings = instance->settings;
WINPR_ASSERT(settings);
freerdp_channels_register_instance(instance->context->channels, instance);
if (!freerdp_settings_set_default_order_support(settings))
return FALSE;
IFCALLRET(instance->PreConnect, status, instance);
instance->ConnectionCallbackState = CLIENT_STATE_PRECONNECT_PASSED;
if (status)
status2 = freerdp_channels_pre_connect(instance->context->channels, instance);
/*如果键盘是KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002类型的, 需要进一步指定
keyboardtype keyboardsubtype和keybooardfunctionkey */
if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002)
{
settings->KeyboardType = 7;
settings->KeyboardSubType = 2;
settings->KeyboardFunctionKey = 12;
}
if (!status || (status2 != CHANNEL_RC_OK))
{
freerdp_set_last_error_if_not(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED);
WLog_ERR(TAG, "freerdp_pre_connect failed");
goto freerdp_connect_finally;
}
status = rdp_client_connect(rdp);
/* Pointers might have changed inbetween */
if (rdp && rdp->settings)
{
/* --authonly tests the connection without a UI */
if (rdp->settings->AuthenticationOnly)
{
WLog_ERR(TAG, "Authentication only, exit status %" PRId32 "", status);
goto freerdp_connect_finally;
}
if (rdp->settings->DumpRemoteFx)
{
rdp->update->pcap_rfx = pcap_open(rdp->settings->DumpRemoteFxFile, TRUE);
if (rdp->update->pcap_rfx)
rdp->update->dump_rfx = TRUE;
}
}
if (status)
{
pointer_cache_register_callbacks(instance->context->update);
IFCALLRET(instance->PostConnect, status, instance);
instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
if (status)
status2 = freerdp_channels_post_connect(instance->context->channels, instance);
}
else
{
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
status = freerdp_reconnect(instance);
else
goto freerdp_connect_finally;
}
if (!status || (status2 != CHANNEL_RC_OK) || !update_post_connect(instance->update))
{
WLog_ERR(TAG, "freerdp_post_connect failed");
freerdp_set_last_error_if_not(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED);
status = FALSE;
goto freerdp_connect_finally;
}
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)
goto freerdp_connect_finally;
else
update->play_rfx = TRUE;
status = TRUE;
while (pcap_has_next_record(update->pcap_rfx) && status)
{
pcap_get_next_record_header(update->pcap_rfx, &record);
s = transport_take_from_pool(rdp->transport, record.length);
if (!s)
break;
record.data = Stream_Buffer(s);
pcap_get_next_record_content(update->pcap_rfx, &record);
Stream_SetLength(s, record.length);
Stream_SetPosition(s, 0);
if (!update_begin_paint(update))
status = FALSE;
else
{
if (update_recv_surfcmds(update, s) < 0)
status = FALSE;
if (!update_end_paint(update))
status = FALSE;
}
Stream_Release(s);
}
pcap_close(update->pcap_rfx);
update->pcap_rfx = NULL;
goto freerdp_connect_finally;
}
if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
freerdp_set_last_error_log(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
transport_set_connected_event(rdp->transport);
freerdp_connect_finally:
EventArgsInit(&e, "freerdp");
e.result = status ? 0 : -1;
PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e);
if (!status)
freerdp_disconnect(instance);
return status;
}
主要功能:
主要进行链接服务器前的客户端接口绑定,channels的连接前处理, 链接, 连接后的客户端接口处理, channels连接后处理,链接失败处理逻辑
重置一些必要参数:setting,rdp,status,wStream,Event,Error等.
代码分析:
IFCALLRET(instance->PreConnect, status, instance);
调用连接前函数,PreConnect , 通过跟踪代码发现调用
下面的函数
/**
* 获取本机的显示器分辨率信息,加载channels信息,设置键盘信息
* @param instance
* @return
*/
static BOOL wl_pre_connect(freerdp* instance)
{
rdpSettings* settings;
wlfContext* context;
const UwacOutput* output;
UwacSize resolution;
if (!instance)
return FALSE;
context = (wlfContext*)instance->context;
settings = instance->settings;
if (!context || !settings)
return FALSE;
settings->OsMajorType = OSMAJORTYPE_UNIX;
settings->OsMinorType = OSMINORTYPE_NATIVE_WAYLAND;
PubSub_SubscribeChannelConnected(instance->context->pubSub, wlf_OnChannelConnectedEventHandler);
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
wlf_OnChannelDisconnectedEventHandler);
if (settings->Fullscreen)
{
// Use the resolution of the first display output
output = UwacDisplayGetOutput(context->display, 0);
if ((output != NULL) && (UwacOutputGetResolution(output, &resolution) == UWAC_SUCCESS))
{
settings->DesktopWidth = (UINT32)resolution.width;
settings->DesktopHeight = (UINT32)resolution.height;
}
else
{
WLog_WARN(TAG, "Failed to get output resolution! Check your display settings");
}
}
if (!freerdp_client_load_addins(instance->context->channels, instance->settings))
return FALSE;
return TRUE;
}
可以看到将分辨率信息赋值给settings。
加载channels信息, 通过freerdp_client_load_addins进行参数传递。
链接RDP服务器函数接口, 包括协议选择, socket建立等
为记录remoteFX的dump信息创建文件
目前就分析到这个地方,后面继续进行分析。待续~~~~。
以上是关于FreeRDP的连接过程分析的主要内容,如果未能解决你的问题,请参考以下文章