Merge pull request #51 from llyzs/server
Initial server implementation (still in progress)
This commit is contained in:
commit
e4c7f28acf
@ -134,3 +134,4 @@ if(NOT WIN32)
|
||||
endif()
|
||||
|
||||
add_subdirectory(client)
|
||||
add_subdirectory(server)
|
||||
|
64
include/freerdp/listener.h
Normal file
64
include/freerdp/listener.h
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* RDP Server Listener
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __FREERDP_LISTENER_H
|
||||
#define __FREERDP_LISTENER_H
|
||||
|
||||
typedef struct rdp_freerdp_listener freerdp_listener;
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/peer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef boolean (*psListenerOpen)(freerdp_listener* instance, const char* bind_address, uint16 port);
|
||||
typedef boolean (*psListenerGetFileDescriptor)(freerdp_listener* instance, void** rfds, int* rcount);
|
||||
typedef boolean (*psListenerCheckFileDescriptor)(freerdp_listener* instance);
|
||||
typedef void (*psListenerClose)(freerdp_listener* instance);
|
||||
typedef void (*psPeerAccepted)(freerdp_listener* instance, freerdp_peer* client);
|
||||
|
||||
struct rdp_freerdp_listener
|
||||
{
|
||||
void* listener;
|
||||
void* param1;
|
||||
void* param2;
|
||||
void* param3;
|
||||
void* param4;
|
||||
|
||||
psListenerOpen Open;
|
||||
psListenerGetFileDescriptor GetFileDescriptor;
|
||||
psListenerCheckFileDescriptor CheckFileDescriptor;
|
||||
psListenerClose Close;
|
||||
|
||||
psPeerAccepted PeerAccepted;
|
||||
};
|
||||
|
||||
FREERDP_API freerdp_listener* freerdp_listener_new(void);
|
||||
FREERDP_API void freerdp_listener_free(freerdp_listener* instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
54
include/freerdp/peer.h
Normal file
54
include/freerdp/peer.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* RDP Server Peer
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __FREERDP_PEER_H
|
||||
#define __FREERDP_PEER_H
|
||||
|
||||
typedef struct rdp_freerdp_peer freerdp_peer;
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/settings.h>
|
||||
|
||||
typedef boolean (*psPeerInitialize)(freerdp_peer* client);
|
||||
typedef boolean (*psPeerGetFileDescriptor)(freerdp_peer* client, void** rfds, int* rcount);
|
||||
typedef boolean (*psPeerCheckFileDescriptor)(freerdp_peer* client);
|
||||
typedef void (*psPeerDisconnect)(freerdp_peer* client);
|
||||
|
||||
struct rdp_freerdp_peer
|
||||
{
|
||||
void* peer;
|
||||
void* param1;
|
||||
void* param2;
|
||||
void* param3;
|
||||
void* param4;
|
||||
|
||||
rdpSettings* settings;
|
||||
|
||||
psPeerInitialize Initialize;
|
||||
psPeerGetFileDescriptor GetFileDescriptor;
|
||||
psPeerCheckFileDescriptor CheckFileDescriptor;
|
||||
psPeerDisconnect Disconnect;
|
||||
};
|
||||
|
||||
FREERDP_API freerdp_peer* freerdp_peer_new(int sockfd);
|
||||
FREERDP_API void freerdp_peer_free(freerdp_peer* client);
|
||||
|
||||
#endif /* __FREERDP_PEER_H */
|
||||
|
@ -171,6 +171,7 @@ struct rdp_settings
|
||||
uint32 kbd_subtype;
|
||||
uint32 kbd_fn_keys;
|
||||
uint32 client_build;
|
||||
uint32 requested_protocols;
|
||||
uint32 selected_protocol;
|
||||
uint32 encryption_method;
|
||||
uint32 encryption_level;
|
||||
@ -204,6 +205,9 @@ struct rdp_settings
|
||||
char* directory;
|
||||
uint32 performance_flags;
|
||||
|
||||
char* cert_file;
|
||||
char* privatekey_file;
|
||||
|
||||
boolean autologon;
|
||||
boolean compression;
|
||||
|
||||
|
@ -84,6 +84,10 @@ set(LIBFREERDP_CORE_SRCS
|
||||
vchan.h
|
||||
window.c
|
||||
window.h
|
||||
listener.c
|
||||
listener.h
|
||||
peer.c
|
||||
peer.h
|
||||
)
|
||||
|
||||
add_library(freerdp-core SHARED ${LIBFREERDP_CORE_SRCS})
|
||||
|
@ -251,6 +251,13 @@ boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 count)
|
||||
return True;
|
||||
}
|
||||
|
||||
void ber_write_enumerated(STREAM* s, uint8 enumerated, uint8 count)
|
||||
{
|
||||
ber_write_universal_tag(s, BER_TAG_ENUMERATED, False);
|
||||
ber_write_length(s, 1);
|
||||
stream_write_uint8(s, enumerated);
|
||||
}
|
||||
|
||||
boolean ber_read_bit_string(STREAM* s, int* length, uint8* padding)
|
||||
{
|
||||
ber_read_universal_tag(s, BER_TAG_BIT_STRING, False);
|
||||
@ -294,6 +301,27 @@ int ber_skip_octet_string(int length)
|
||||
return 1 + _ber_skip_length(length) + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a BER BOOLEAN
|
||||
* @param s
|
||||
* @param value
|
||||
*/
|
||||
|
||||
boolean ber_read_boolean(STREAM* s, boolean* value)
|
||||
{
|
||||
int length;
|
||||
uint8 v;
|
||||
|
||||
if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, False))
|
||||
return False;
|
||||
ber_read_length(s, &length);
|
||||
if (length != 1)
|
||||
return False;
|
||||
stream_read_uint8(s, v);
|
||||
*value = (v ? True : False);
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a BER BOOLEAN
|
||||
* @param s
|
||||
|
@ -60,6 +60,7 @@ boolean ber_read_application_tag(STREAM* s, uint8 tag, int* length);
|
||||
void ber_write_application_tag(STREAM* s, uint8 tag, int length);
|
||||
boolean ber_read_application_tag(STREAM* s, uint8 tag, int* length);
|
||||
boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 count);
|
||||
void ber_write_enumerated(STREAM* s, uint8 enumerated, uint8 count);
|
||||
boolean ber_read_contextual_tag(STREAM* s, uint8 tag, int* length, boolean pc);
|
||||
int ber_write_contextual_tag(STREAM* s, uint8 tag, int length, boolean pc);
|
||||
int ber_skip_contextual_tag(int length);
|
||||
@ -72,6 +73,7 @@ boolean ber_read_octet_string(STREAM* s, int* length);
|
||||
void ber_write_octet_string(STREAM* s, uint8* oct_str, int length);
|
||||
int ber_write_octet_string_tag(STREAM* s, int length);
|
||||
int ber_skip_octet_string(int length);
|
||||
boolean ber_read_boolean(STREAM* s, boolean* value);
|
||||
void ber_write_boolean(STREAM* s, boolean value);
|
||||
boolean ber_read_integer(STREAM* s, uint32* value);
|
||||
int ber_write_integer(STREAM* s, uint32 value);
|
||||
|
@ -108,3 +108,108 @@ boolean rdp_client_connect(rdpRdp* rdp)
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
|
||||
{
|
||||
boolean ret;
|
||||
|
||||
transport_set_blocking_mode(rdp->transport, True);
|
||||
|
||||
if (!nego_recv_request(rdp->nego, s))
|
||||
return False;
|
||||
if (rdp->nego->requested_protocols == PROTOCOL_RDP)
|
||||
{
|
||||
printf("Standard RDP encryption is not supported.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("Requested protocols:");
|
||||
if ((rdp->nego->requested_protocols | PROTOCOL_TLS))
|
||||
{
|
||||
printf(" TLS");
|
||||
if (rdp->settings->tls_security)
|
||||
{
|
||||
printf("(Y)");
|
||||
rdp->nego->selected_protocol |= PROTOCOL_TLS;
|
||||
}
|
||||
else
|
||||
printf("(n)");
|
||||
}
|
||||
if ((rdp->nego->requested_protocols | PROTOCOL_NLA))
|
||||
{
|
||||
printf(" NLA");
|
||||
if (rdp->settings->nla_security)
|
||||
{
|
||||
printf("(Y)");
|
||||
rdp->nego->selected_protocol |= PROTOCOL_NLA;
|
||||
}
|
||||
else
|
||||
printf("(n)");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
nego_send_negotiation_response(rdp->nego);
|
||||
|
||||
ret = False;
|
||||
if (rdp->nego->selected_protocol & PROTOCOL_NLA)
|
||||
ret = transport_accept_nla(rdp->transport);
|
||||
else if (rdp->nego->selected_protocol & PROTOCOL_TLS)
|
||||
ret = transport_accept_tls(rdp->transport);
|
||||
else if (rdp->nego->selected_protocol & PROTOCOL_RDP)
|
||||
ret = transport_accept_rdp(rdp->transport);
|
||||
|
||||
if (!ret)
|
||||
return False;
|
||||
|
||||
transport_set_blocking_mode(rdp->transport, False);
|
||||
|
||||
rdp->state = CONNECTION_STATE_NEGO;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, STREAM* s)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mcs_read_connect_initial(rdp->mcs, s))
|
||||
return False;
|
||||
|
||||
printf("Accepted client: %s\n", rdp->settings->client_hostname);
|
||||
printf("Accepted channels:");
|
||||
for (i = 0; i < rdp->settings->num_channels; i++)
|
||||
{
|
||||
printf(" %s", rdp->settings->channels[i].name);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (!mcs_send_connect_response(rdp->mcs))
|
||||
return False;
|
||||
|
||||
rdp->state = CONNECTION_STATE_MCS_CONNECT;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, STREAM* s)
|
||||
{
|
||||
if (!mcs_read_erect_domain_request(rdp->mcs, s))
|
||||
return False;
|
||||
|
||||
rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, STREAM* s)
|
||||
{
|
||||
if (!mcs_read_attach_user_request(rdp->mcs, s))
|
||||
return False;
|
||||
|
||||
if (!mcs_send_attach_user_confirm(rdp->mcs))
|
||||
return False;
|
||||
|
||||
rdp->state = CONNECTION_STATE_MCS_ATTACH_USER;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,20 @@
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
|
||||
enum CONNECTION_STATE
|
||||
{
|
||||
CONNECTION_STATE_INITIAL = 0,
|
||||
CONNECTION_STATE_NEGO,
|
||||
CONNECTION_STATE_MCS_CONNECT,
|
||||
CONNECTION_STATE_MCS_ERECT_DOMAIN,
|
||||
CONNECTION_STATE_MCS_ATTACH_USER
|
||||
};
|
||||
|
||||
boolean rdp_client_connect(rdpRdp* rdp);
|
||||
|
||||
boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s);
|
||||
boolean rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, STREAM* s);
|
||||
boolean rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, STREAM* s);
|
||||
boolean rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, STREAM* s);
|
||||
|
||||
#endif /* __CONNECTION_H */
|
||||
|
@ -123,6 +123,63 @@ uint8 t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
|
||||
uint8 h221_cs_key[4] = "Duca";
|
||||
uint8 h221_sc_key[4] = "McDn";
|
||||
|
||||
/**
|
||||
* Read a GCC Conference Create Request.\n
|
||||
* @msdn{cc240836}
|
||||
* @param s stream
|
||||
* @param settings rdp settings
|
||||
*/
|
||||
|
||||
boolean gcc_read_conference_create_request(STREAM* s, rdpSettings* settings)
|
||||
{
|
||||
uint16 length;
|
||||
uint8 choice;
|
||||
uint8 number;
|
||||
uint8 selection;
|
||||
|
||||
/* ConnectData */
|
||||
if (!per_read_choice(s, &choice))
|
||||
return False;
|
||||
if (!per_read_object_identifier(s, t124_02_98_oid))
|
||||
return False;
|
||||
|
||||
/* ConnectData::connectPDU (OCTET_STRING) */
|
||||
if (!per_read_length(s, &length))
|
||||
return False;
|
||||
|
||||
/* ConnectGCCPDU */
|
||||
if (!per_read_choice(s, &choice))
|
||||
return False;
|
||||
if (!per_read_selection(s, &selection))
|
||||
return False;
|
||||
|
||||
/* ConferenceCreateRequest::conferenceName */
|
||||
if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */
|
||||
return False;
|
||||
if (!per_read_padding(s, 1)) /* padding */
|
||||
return False;
|
||||
|
||||
/* UserData (SET OF SEQUENCE) */
|
||||
if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */
|
||||
return False;
|
||||
if (!per_read_choice(s, &choice) || choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */
|
||||
return False;
|
||||
|
||||
/* h221NonStandard */
|
||||
if (!per_read_octet_string(s, h221_cs_key, 4, 4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
|
||||
return False;
|
||||
|
||||
/* userData::value (OCTET_STRING) */
|
||||
if (!per_read_length(s, &length))
|
||||
return False;
|
||||
if (stream_get_left(s) < length)
|
||||
return False;
|
||||
if (!gcc_read_client_data_blocks(s, settings, length))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a GCC Conference Create Request.\n
|
||||
* @msdn{cc240836}
|
||||
@ -200,6 +257,89 @@ void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
|
||||
gcc_read_server_data_blocks(s, settings, length);
|
||||
}
|
||||
|
||||
void gcc_write_conference_create_response(STREAM* s, STREAM* user_data)
|
||||
{
|
||||
/* ConnectData */
|
||||
per_write_choice(s, 0);
|
||||
per_write_object_identifier(s, t124_02_98_oid);
|
||||
|
||||
/* ConnectData::connectPDU (OCTET_STRING) */
|
||||
per_write_length(s, stream_get_length(user_data) + 2);
|
||||
|
||||
/* ConnectGCCPDU */
|
||||
per_write_choice(s, 0x14);
|
||||
|
||||
/* ConferenceCreateResponse::nodeID (UserID) */
|
||||
per_write_integer16(s, 0x79F3, 1001);
|
||||
|
||||
/* ConferenceCreateResponse::tag (INTEGER) */
|
||||
per_write_integer(s, 1);
|
||||
|
||||
/* ConferenceCreateResponse::result (ENUMERATED) */
|
||||
per_write_enumerated(s, 0, MCS_Result_enum_length);
|
||||
|
||||
/* number of UserData sets */
|
||||
per_write_number_of_sets(s, 1);
|
||||
|
||||
/* UserData::value present + select h221NonStandard (1) */
|
||||
per_write_choice(s, 0xC0);
|
||||
|
||||
/* h221NonStandard */
|
||||
per_write_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
|
||||
|
||||
/* userData (OCTET_STRING) */
|
||||
per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of server data blocks */
|
||||
}
|
||||
|
||||
boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length)
|
||||
{
|
||||
uint16 type;
|
||||
uint16 blockLength;
|
||||
int pos;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
pos = stream_get_pos(s);
|
||||
gcc_read_user_data_header(s, &type, &blockLength);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CS_CORE:
|
||||
if (!gcc_read_client_core_data(s, settings, blockLength - 4))
|
||||
return False;
|
||||
break;
|
||||
|
||||
case CS_SECURITY:
|
||||
if (!gcc_read_client_security_data(s, settings, blockLength - 4))
|
||||
return False;
|
||||
break;
|
||||
|
||||
case CS_NET:
|
||||
if (!gcc_read_client_network_data(s, settings, blockLength - 4))
|
||||
return False;
|
||||
break;
|
||||
|
||||
case CS_CLUSTER:
|
||||
if (!gcc_read_client_cluster_data(s, settings, blockLength - 4))
|
||||
return False;
|
||||
break;
|
||||
|
||||
case CS_MONITOR:
|
||||
if (!gcc_read_client_monitor_data(s, settings, blockLength - 4))
|
||||
return False;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
length -= blockLength;
|
||||
stream_set_pos(s, pos + blockLength);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings)
|
||||
{
|
||||
gcc_write_client_core_data(s, settings);
|
||||
@ -241,6 +381,13 @@ void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
|
||||
}
|
||||
}
|
||||
|
||||
void gcc_write_server_data_blocks(STREAM* s, rdpSettings *settings)
|
||||
{
|
||||
gcc_write_server_core_data(s, settings);
|
||||
gcc_write_server_network_data(s, settings);
|
||||
gcc_write_server_security_data(s, settings);
|
||||
}
|
||||
|
||||
void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
|
||||
{
|
||||
stream_read_uint16(s, *type); /* type */
|
||||
@ -261,6 +408,161 @@ void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
|
||||
stream_write_uint16(s, length); /* length */
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a client core data block (TS_UD_CS_CORE).\n
|
||||
* @msdn{cc240510}
|
||||
* @param s stream
|
||||
* @param settings rdp settings
|
||||
*/
|
||||
|
||||
boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
|
||||
{
|
||||
uint32 version;
|
||||
uint16 colorDepth = 0;
|
||||
uint16 postBeta2ColorDepth = 0;
|
||||
uint16 highColorDepth = 0;
|
||||
uint16 supportedColorDepths = 0;
|
||||
uint16 earlyCapabilityFlags = 0;
|
||||
uint32 serverSelectedProtocol = 0;
|
||||
char* str;
|
||||
|
||||
/* Length of all required fields, until imeFileName */
|
||||
if (blockLength < 128)
|
||||
return False;
|
||||
|
||||
stream_read_uint32(s, version); /* version */
|
||||
settings->rdp_version = (version == RDP_VERSION_4 ? 4 : 7);
|
||||
|
||||
stream_read_uint16(s, settings->width); /* desktopWidth */
|
||||
stream_read_uint16(s, settings->height); /* desktopHeight */
|
||||
stream_read_uint16(s, colorDepth); /* colorDepth */
|
||||
stream_seek_uint16(s); /* SASSequence (Secure Access Sequence) */
|
||||
stream_read_uint32(s, settings->kbd_layout); /* keyboardLayout */
|
||||
stream_read_uint32(s, settings->client_build); /* clientBuild */
|
||||
|
||||
/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
|
||||
str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 32);
|
||||
stream_seek(s, 32);
|
||||
snprintf(settings->client_hostname, sizeof(settings->client_hostname), "%s", str);
|
||||
xfree(str);
|
||||
|
||||
stream_read_uint32(s, settings->kbd_type); /* keyboardType */
|
||||
stream_read_uint32(s, settings->kbd_subtype); /* keyboardSubType */
|
||||
stream_read_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
|
||||
|
||||
stream_seek(s, 64); /* imeFileName */
|
||||
|
||||
blockLength -= 128;
|
||||
|
||||
/**
|
||||
* The following fields are all optional. If one field is present, all of the preceding
|
||||
* fields MUST also be present. If one field is not present, all of the subsequent fields
|
||||
* MUST NOT be present.
|
||||
* We must check the bytes left before reading each field.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
if (blockLength < 2)
|
||||
break;
|
||||
stream_read_uint16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */
|
||||
blockLength -= 2;
|
||||
|
||||
if (blockLength < 2)
|
||||
break;
|
||||
stream_seek_uint16(s); /* clientProductID */
|
||||
blockLength -= 2;
|
||||
|
||||
if (blockLength < 4)
|
||||
break;
|
||||
stream_seek_uint32(s); /* serialNumber */
|
||||
blockLength -= 4;
|
||||
|
||||
if (blockLength < 2)
|
||||
break;
|
||||
stream_read_uint16(s, highColorDepth); /* highColorDepth */
|
||||
blockLength -= 2;
|
||||
|
||||
if (blockLength < 2)
|
||||
break;
|
||||
stream_read_uint16(s, supportedColorDepths); /* supportedColorDepths */
|
||||
blockLength -= 2;
|
||||
|
||||
if (blockLength < 2)
|
||||
break;
|
||||
stream_read_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
|
||||
blockLength -= 2;
|
||||
|
||||
if (blockLength < 64)
|
||||
break;
|
||||
str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
|
||||
stream_seek(s, 64);
|
||||
snprintf(settings->client_product_id, sizeof(settings->client_product_id), "%s", str);
|
||||
xfree(str);
|
||||
blockLength -= 64;
|
||||
|
||||
if (blockLength < 1)
|
||||
break;
|
||||
stream_read_uint8(s, settings->performance_flags); /* connectionType */
|
||||
blockLength -= 1;
|
||||
|
||||
if (blockLength < 1)
|
||||
break;
|
||||
stream_seek_uint8(s); /* pad1octet */
|
||||
blockLength -= 1;
|
||||
|
||||
if (blockLength < 4)
|
||||
break;
|
||||
stream_read_uint32(s, serverSelectedProtocol); /* serverSelectedProtocol */
|
||||
blockLength -= 4;
|
||||
|
||||
if (settings->selected_protocol != serverSelectedProtocol)
|
||||
return False;
|
||||
} while (0);
|
||||
|
||||
if (highColorDepth > 0)
|
||||
settings->color_depth = highColorDepth;
|
||||
else if (postBeta2ColorDepth > 0)
|
||||
{
|
||||
switch (postBeta2ColorDepth)
|
||||
{
|
||||
case RNS_UD_COLOR_4BPP:
|
||||
settings->color_depth = 4;
|
||||
break;
|
||||
case RNS_UD_COLOR_8BPP:
|
||||
settings->color_depth = 8;
|
||||
break;
|
||||
case RNS_UD_COLOR_16BPP_555:
|
||||
settings->color_depth = 15;
|
||||
break;
|
||||
case RNS_UD_COLOR_16BPP_565:
|
||||
settings->color_depth = 16;
|
||||
break;
|
||||
case RNS_UD_COLOR_24BPP:
|
||||
settings->color_depth = 24;
|
||||
break;
|
||||
default:
|
||||
return False;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (colorDepth)
|
||||
{
|
||||
case RNS_UD_COLOR_4BPP:
|
||||
settings->color_depth = 4;
|
||||
break;
|
||||
case RNS_UD_COLOR_8BPP:
|
||||
settings->color_depth = 8;
|
||||
break;
|
||||
default:
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a client core data block (TS_UD_CS_CORE).\n
|
||||
* @msdn{cc240510}
|
||||
@ -373,6 +675,33 @@ void gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
|
||||
settings->rdp_version = 7;
|
||||
}
|
||||
|
||||
void gcc_write_server_core_data(STREAM* s, rdpSettings *settings)
|
||||
{
|
||||
gcc_write_user_data_header(s, SC_CORE, 12);
|
||||
|
||||
stream_write_uint32(s, settings->rdp_version == 4 ? RDP_VERSION_4 : RDP_VERSION_5_PLUS);
|
||||
stream_write_uint32(s, settings->requested_protocols); /* clientRequestedProtocols */
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a client security data block (TS_UD_CS_SEC).\n
|
||||
* @msdn{cc240511}
|
||||
* @param s stream
|
||||
* @param settings rdp settings
|
||||
*/
|
||||
|
||||
boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
|
||||
{
|
||||
if (blockLength < 8)
|
||||
return False;
|
||||
|
||||
stream_read_uint32(s, settings->encryption_method); /* encryptionMethods */
|
||||
if (settings->encryption_method == 0)
|
||||
stream_read_uint32(s, settings->encryption_method); /* extEncryptionMethods */
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a client security data block (TS_UD_CS_SEC).\n
|
||||
* @msdn{cc240511}
|
||||
@ -432,6 +761,50 @@ void gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
|
||||
}
|
||||
}
|
||||
|
||||
void gcc_write_server_security_data(STREAM* s, rdpSettings *settings)
|
||||
{
|
||||
gcc_write_user_data_header(s, SC_SECURITY, 12);
|
||||
|
||||
stream_write_uint32(s, ENCRYPTION_METHOD_NONE); /* encryptionMethod */
|
||||
stream_write_uint32(s, ENCRYPTION_LEVEL_NONE); /* encryptionLevel */
|
||||
#if 0
|
||||
stream_write_uint32(s, 0); /* serverRandomLen */
|
||||
stream_write_uint32(s, 0); /* serverCertLen */
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a client network data block (TS_UD_CS_NET).\n
|
||||
* @msdn{cc240512}
|
||||
* @param s stream
|
||||
* @param settings rdp settings
|
||||
*/
|
||||
|
||||
boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (blockLength < 4)
|
||||
return False;
|
||||
|
||||
stream_read_uint32(s, settings->num_channels); /* channelCount */
|
||||
if (blockLength < 4 + settings->num_channels * 12)
|
||||
return False;
|
||||
if (settings->num_channels > 16)
|
||||
return False;
|
||||
|
||||
/* channelDefArray */
|
||||
for (i = 0; i < settings->num_channels; i++)
|
||||
{
|
||||
/* CHANNEL_DEF */
|
||||
stream_read(s, settings->channels[i].name, 8); /* name (8 bytes) */
|
||||
stream_read_uint32(s, settings->channels[i].options); /* options (4 bytes) */
|
||||
settings->channels[i].chan_id = MCS_GLOBAL_CHANNEL_ID + 1 + i;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a client network data block (TS_UD_CS_NET).\n
|
||||
* @msdn{cc240512}
|
||||
@ -487,6 +860,46 @@ void gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
|
||||
stream_seek(s, 2); /* padding */
|
||||
}
|
||||
|
||||
void gcc_write_server_network_data(STREAM* s, rdpSettings *settings)
|
||||
{
|
||||
int i;
|
||||
|
||||
gcc_write_user_data_header(s, SC_NET, 8 + settings->num_channels * 2 + (settings->num_channels % 2 == 1 ? 2 : 0));
|
||||
|
||||
stream_write_uint16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
|
||||
stream_write_uint16(s, settings->num_channels); /* channelCount */
|
||||
|
||||
for (i = 0; i < settings->num_channels; i++)
|
||||
{
|
||||
stream_write_uint16(s, settings->channels[i].chan_id);
|
||||
}
|
||||
|
||||
if (settings->num_channels % 2 == 1)
|
||||
stream_write_uint16(s, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a client cluster data block (TS_UD_CS_CLUSTER).\n
|
||||
* @msdn{cc240514}
|
||||
* @param s stream
|
||||
* @param settings rdp settings
|
||||
*/
|
||||
|
||||
boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
|
||||
{
|
||||
uint32 flags;
|
||||
|
||||
if (blockLength < 8)
|
||||
return False;
|
||||
|
||||
stream_read_uint32(s, flags); /* flags */
|
||||
|
||||
if ((flags | REDIRECTED_SESSIONID_FIELD_VALID))
|
||||
stream_read_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a client cluster data block (TS_UD_CS_CLUSTER).\n
|
||||
* @msdn{cc240514}
|
||||
@ -509,6 +922,19 @@ void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
|
||||
stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a client monitor data block (TS_UD_CS_MONITOR).\n
|
||||
* @msdn{dd305336}
|
||||
* @param s stream
|
||||
* @param settings rdp settings
|
||||
*/
|
||||
|
||||
boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
|
||||
{
|
||||
printf("CS_MONITOR\n");
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a client monitor data block (TS_UD_CS_MONITOR).\n
|
||||
* @msdn{dd305336}
|
||||
@ -546,3 +972,4 @@ void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,19 +100,31 @@
|
||||
/* Monitor Flags */
|
||||
#define MONITOR_PRIMARY 0x00000001
|
||||
|
||||
boolean gcc_read_conference_create_request(STREAM* s, rdpSettings* settings);
|
||||
void gcc_write_conference_create_request(STREAM* s, STREAM* user_data);
|
||||
void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings);
|
||||
void gcc_write_conference_create_response(STREAM* s, STREAM* user_data);
|
||||
boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length);
|
||||
void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings);
|
||||
void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length);
|
||||
void gcc_write_server_data_blocks(STREAM* s, rdpSettings *settings);
|
||||
void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length);
|
||||
void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length);
|
||||
boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength);
|
||||
void gcc_write_client_core_data(STREAM* s, rdpSettings *settings);
|
||||
void gcc_read_server_core_data(STREAM* s, rdpSettings *settings);
|
||||
void gcc_write_server_core_data(STREAM* s, rdpSettings *settings);
|
||||
boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings, uint16 blockLength);
|
||||
void gcc_write_client_security_data(STREAM* s, rdpSettings *settings);
|
||||
void gcc_read_server_security_data(STREAM* s, rdpSettings *settings);
|
||||
void gcc_write_server_security_data(STREAM* s, rdpSettings *settings);
|
||||
boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings, uint16 blockLength);
|
||||
void gcc_write_client_network_data(STREAM* s, rdpSettings *settings);
|
||||
void gcc_read_server_network_data(STREAM* s, rdpSettings *settings);
|
||||
void gcc_write_server_network_data(STREAM* s, rdpSettings *settings);
|
||||
boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings, uint16 blockLength);
|
||||
void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings);
|
||||
boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings, uint16 blockLength);
|
||||
void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings);
|
||||
|
||||
#endif /* __GCC_H */
|
||||
|
215
libfreerdp-core/listener.c
Normal file
215
libfreerdp-core/listener.c
Normal file
@ -0,0 +1,215 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* RDP Server Listener
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#define close(_fd) closesocket(_fd)
|
||||
#endif
|
||||
|
||||
#include "listener.h"
|
||||
|
||||
static boolean freerdp_listener_open(freerdp_listener* instance, const char* bind_address, uint16 port)
|
||||
{
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
int status;
|
||||
int sockfd;
|
||||
char servname[10];
|
||||
struct addrinfo hints = { 0 };
|
||||
struct addrinfo* res;
|
||||
struct addrinfo* ai;
|
||||
int option_value;
|
||||
void* sin_addr;
|
||||
char buf[50];
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (bind_address == NULL)
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
snprintf(servname, sizeof(servname), "%d", port);
|
||||
status = getaddrinfo(bind_address, servname, &hints, &res);
|
||||
if (status != 0)
|
||||
{
|
||||
perror("getaddrinfo");
|
||||
return False;
|
||||
}
|
||||
|
||||
for (ai = res; ai && listener->num_sockfds < 5; ai = ai->ai_next)
|
||||
{
|
||||
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (sockfd == -1)
|
||||
{
|
||||
perror("socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
option_value = 1;
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option_value, sizeof(option_value)) == -1)
|
||||
{
|
||||
perror("setsockopt");
|
||||
}
|
||||
fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
status = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
|
||||
if (status != 0)
|
||||
{
|
||||
perror("bind");
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
status = listen(sockfd, 10);
|
||||
if (status != 0)
|
||||
{
|
||||
perror("listen");
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
listener->sockfds[listener->num_sockfds++] = sockfd;
|
||||
|
||||
if (ai->ai_family == AF_INET)
|
||||
sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr);
|
||||
else
|
||||
sin_addr = &(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr);
|
||||
|
||||
printf("Listening on %s port %s.\n", inet_ntop(ai->ai_family, sin_addr, buf, sizeof(buf)), servname);
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
return (listener->num_sockfds > 0 ? True : False);
|
||||
}
|
||||
|
||||
static void freerdp_listener_close(freerdp_listener* instance)
|
||||
{
|
||||
int i;
|
||||
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
|
||||
for (i = 0; i < listener->num_sockfds; i++)
|
||||
{
|
||||
close(listener->sockfds[i]);
|
||||
}
|
||||
listener->num_sockfds = 0;
|
||||
}
|
||||
|
||||
static boolean freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
|
||||
{
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
int i;
|
||||
|
||||
if (listener->num_sockfds < 1)
|
||||
return False;
|
||||
|
||||
for (i = 0; i < listener->num_sockfds; i++)
|
||||
{
|
||||
rfds[*rcount] = (void*)(long)(listener->sockfds[i]);
|
||||
(*rcount)++;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static boolean freerdp_listener_check_fds(freerdp_listener* instance)
|
||||
{
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
struct sockaddr_storage peer_addr;
|
||||
socklen_t peer_addr_size;
|
||||
int peer_sockfd;
|
||||
int i;
|
||||
freerdp_peer* client;
|
||||
void* sin_addr;
|
||||
|
||||
if (listener->num_sockfds < 1)
|
||||
return False;
|
||||
|
||||
for (i = 0; i < listener->num_sockfds; i++)
|
||||
{
|
||||
peer_addr_size = sizeof(peer_addr);
|
||||
peer_sockfd = accept(listener->sockfds[i], (struct sockaddr *)&peer_addr, &peer_addr_size);
|
||||
if (peer_sockfd == -1)
|
||||
{
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
continue;
|
||||
|
||||
perror("accept");
|
||||
return False;
|
||||
}
|
||||
|
||||
client = freerdp_peer_new(peer_sockfd);
|
||||
|
||||
if (peer_addr.ss_family == AF_INET)
|
||||
sin_addr = &(((struct sockaddr_in*)&peer_addr)->sin_addr);
|
||||
else
|
||||
sin_addr = &(((struct sockaddr_in6*)&peer_addr)->sin6_addr);
|
||||
client->settings->hostname = xzalloc(50);
|
||||
inet_ntop(peer_addr.ss_family, sin_addr, client->settings->hostname, 50);
|
||||
|
||||
printf("Accepted client from %s.\n", client->settings->hostname);
|
||||
|
||||
IFCALL(instance->PeerAccepted, instance, client);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
freerdp_listener* freerdp_listener_new(void)
|
||||
{
|
||||
freerdp_listener* instance;
|
||||
rdpListener* listener;
|
||||
|
||||
instance = xnew(freerdp_listener);
|
||||
instance->Open = freerdp_listener_open;
|
||||
instance->GetFileDescriptor = freerdp_listener_get_fds;
|
||||
instance->CheckFileDescriptor = freerdp_listener_check_fds;
|
||||
instance->Close = freerdp_listener_close;
|
||||
|
||||
listener = xnew(rdpListener);
|
||||
listener->instance = instance;
|
||||
|
||||
instance->listener = (void*)listener;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void freerdp_listener_free(freerdp_listener* instance)
|
||||
{
|
||||
rdpListener* listener;
|
||||
|
||||
listener = (rdpListener*)instance->listener;
|
||||
xfree(listener);
|
||||
|
||||
xfree(instance);
|
||||
}
|
||||
|
37
libfreerdp-core/listener.h
Normal file
37
libfreerdp-core/listener.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* RDP Server Listener
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LISTENER_H
|
||||
#define __LISTENER_H
|
||||
|
||||
typedef struct rdp_listener rdpListener;
|
||||
|
||||
#include "rdp.h"
|
||||
#include <freerdp/listener.h>
|
||||
|
||||
struct rdp_listener
|
||||
{
|
||||
freerdp_listener* instance;
|
||||
|
||||
int sockfds[5];
|
||||
int num_sockfds;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -247,11 +247,11 @@ boolean mcs_read_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU* domainMCSPDU
|
||||
* @param length TPKT length
|
||||
*/
|
||||
|
||||
void mcs_write_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU domainMCSPDU, int length)
|
||||
void mcs_write_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU domainMCSPDU, int length, uint8 options)
|
||||
{
|
||||
tpkt_write_header(s, length);
|
||||
tpdu_write_data(s);
|
||||
per_write_choice(s, domainMCSPDU << 2);
|
||||
per_write_choice(s, (domainMCSPDU << 2) | options);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -347,6 +347,58 @@ void mcs_print_domain_parameters(DomainParameters* domainParameters)
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an MCS Connect Initial PDU.\n
|
||||
* @msdn{cc240508}
|
||||
* @param mcs MCS module
|
||||
* @param s stream
|
||||
*/
|
||||
|
||||
boolean mcs_read_connect_initial(rdpMcs* mcs, STREAM* s)
|
||||
{
|
||||
int length;
|
||||
boolean upwardFlag;
|
||||
|
||||
tpkt_read_header(s);
|
||||
|
||||
if (tpdu_read_data(s) == 0)
|
||||
return False;
|
||||
|
||||
if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length))
|
||||
return False;
|
||||
|
||||
/* callingDomainSelector (OCTET_STRING) */
|
||||
if (!ber_read_octet_string(s, &length))
|
||||
return False;
|
||||
stream_seek(s, length);
|
||||
|
||||
/* calledDomainSelector (OCTET_STRING) */
|
||||
if (!ber_read_octet_string(s, &length))
|
||||
return False;
|
||||
stream_seek(s, length);
|
||||
|
||||
/* upwardFlag (BOOLEAN) */
|
||||
if (!ber_read_boolean(s, &upwardFlag))
|
||||
return False;
|
||||
|
||||
/* targetParameters (DomainParameters) */
|
||||
mcs_read_domain_parameters(s, &mcs->targetParameters);
|
||||
|
||||
/* minimumParameters (DomainParameters) */
|
||||
mcs_read_domain_parameters(s, &mcs->minimumParameters);
|
||||
|
||||
/* maximumParameters (DomainParameters) */
|
||||
mcs_read_domain_parameters(s, &mcs->maximumParameters);
|
||||
|
||||
if (!ber_read_octet_string(s, &length))
|
||||
return False;
|
||||
|
||||
if (!gcc_read_conference_create_request(s, mcs->transport->settings))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an MCS Connect Initial PDU.\n
|
||||
* @msdn{cc240508}
|
||||
@ -395,6 +447,41 @@ void mcs_write_connect_initial(STREAM* s, rdpMcs* mcs, STREAM* user_data)
|
||||
stream_set_mark(s, em);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an MCS Connect Response PDU.\n
|
||||
* @msdn{cc240508}
|
||||
* @param s stream
|
||||
* @param mcs MCS module
|
||||
* @param user_data GCC Conference Create Response
|
||||
*/
|
||||
|
||||
void mcs_write_connect_response(STREAM* s, rdpMcs* mcs, STREAM* user_data)
|
||||
{
|
||||
int length;
|
||||
uint8 *bm, *em;
|
||||
|
||||
int gcc_CCrsp_length = stream_get_length(user_data);
|
||||
|
||||
stream_get_mark(s, bm);
|
||||
stream_seek(s, 3);
|
||||
|
||||
ber_write_enumerated(s, 0, MCS_Result_enum_length);
|
||||
ber_write_integer(s, 0); /* calledConnectId */
|
||||
|
||||
mcs->domainParameters = mcs->targetParameters;
|
||||
mcs_write_domain_parameters(s, &(mcs->domainParameters));
|
||||
|
||||
/* userData (OCTET_STRING) */
|
||||
ber_write_octet_string(s, user_data->data, gcc_CCrsp_length);
|
||||
|
||||
stream_get_mark(s, em);
|
||||
length = (em - bm) - 3;
|
||||
stream_set_mark(s, bm);
|
||||
|
||||
ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length);
|
||||
stream_set_mark(s, em);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send MCS Connect Initial.\n
|
||||
* @msdn{cc240508}
|
||||
@ -467,6 +554,67 @@ void mcs_recv_connect_response(rdpMcs* mcs)
|
||||
gcc_read_conference_create_response(s, mcs->transport->settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send MCS Connect Response.\n
|
||||
* @msdn{cc240501}
|
||||
* @param mcs mcs module
|
||||
*/
|
||||
|
||||
boolean mcs_send_connect_response(rdpMcs* mcs)
|
||||
{
|
||||
STREAM* s;
|
||||
int length;
|
||||
uint8 *bm, *em;
|
||||
STREAM* gcc_CCrsp;
|
||||
STREAM* server_data;
|
||||
|
||||
server_data = stream_new(512);
|
||||
gcc_write_server_data_blocks(server_data, mcs->transport->settings);
|
||||
|
||||
gcc_CCrsp = stream_new(512);
|
||||
gcc_write_conference_create_response(gcc_CCrsp, server_data);
|
||||
length = stream_get_length(gcc_CCrsp) + 7;
|
||||
|
||||
s = transport_send_stream_init(mcs->transport, 1024);
|
||||
stream_get_mark(s, bm);
|
||||
stream_seek(s, 7);
|
||||
|
||||
mcs_write_connect_response(s, mcs, gcc_CCrsp);
|
||||
stream_get_mark(s, em);
|
||||
length = (em - bm);
|
||||
stream_set_mark(s, bm);
|
||||
|
||||
tpkt_write_header(s, length);
|
||||
tpdu_write_data(s);
|
||||
stream_set_mark(s, em);
|
||||
|
||||
transport_write(mcs->transport, s);
|
||||
|
||||
stream_free(gcc_CCrsp);
|
||||
stream_free(server_data);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read MCS Erect Domain Request.\n
|
||||
* @msdn{cc240523}
|
||||
* @param mcs
|
||||
* @param s stream
|
||||
*/
|
||||
|
||||
boolean mcs_read_erect_domain_request(rdpMcs* mcs, STREAM* s)
|
||||
{
|
||||
int length;
|
||||
enum DomainMCSPDU MCSPDU;
|
||||
|
||||
MCSPDU = DomainMCSPDU_ErectDomainRequest;
|
||||
if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send MCS Erect Domain Request.\n
|
||||
* @msdn{cc240523}
|
||||
@ -479,7 +627,7 @@ void mcs_send_erect_domain_request(rdpMcs* mcs)
|
||||
int length = 12;
|
||||
s = transport_send_stream_init(mcs->transport, length);
|
||||
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length);
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length, 0);
|
||||
|
||||
per_write_integer(s, 0); /* subHeight (INTEGER) */
|
||||
per_write_integer(s, 0); /* subInterval (INTEGER) */
|
||||
@ -487,6 +635,25 @@ void mcs_send_erect_domain_request(rdpMcs* mcs)
|
||||
transport_write(mcs->transport, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read MCS Attach User Request.\n
|
||||
* @msdn{cc240524}
|
||||
* @param mcs mcs module
|
||||
* @param s stream
|
||||
*/
|
||||
|
||||
boolean mcs_read_attach_user_request(rdpMcs* mcs, STREAM* s)
|
||||
{
|
||||
int length;
|
||||
enum DomainMCSPDU MCSPDU;
|
||||
|
||||
MCSPDU = DomainMCSPDU_AttachUserRequest;
|
||||
if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send MCS Attach User Request.\n
|
||||
* @msdn{cc240524}
|
||||
@ -499,7 +666,7 @@ void mcs_send_attach_user_request(rdpMcs* mcs)
|
||||
int length = 8;
|
||||
s = transport_send_stream_init(mcs->transport, length);
|
||||
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length);
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length, 0);
|
||||
|
||||
transport_write(mcs->transport, s);
|
||||
}
|
||||
@ -527,6 +694,30 @@ void mcs_recv_attach_user_confirm(rdpMcs* mcs)
|
||||
per_read_integer16(s, &(mcs->user_id), MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Send MCS Attach User Confirm.\n
|
||||
* @msdn{cc240525}
|
||||
* @param mcs mcs module
|
||||
*/
|
||||
|
||||
boolean mcs_send_attach_user_confirm(rdpMcs* mcs)
|
||||
{
|
||||
STREAM* s;
|
||||
int length = 11;
|
||||
|
||||
s = transport_send_stream_init(mcs->transport, length);
|
||||
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, length, 2);
|
||||
|
||||
per_write_enumerated(s, 0, MCS_Result_enum_length); /* result */
|
||||
mcs->user_id = 1002;
|
||||
per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
|
||||
|
||||
transport_write(mcs->transport, s);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send MCS Channel Join Request.\n
|
||||
* @msdn{cc240526}
|
||||
@ -540,7 +731,7 @@ void mcs_send_channel_join_request(rdpMcs* mcs, uint16 channel_id)
|
||||
int length = 12;
|
||||
s = transport_send_stream_init(mcs->transport, 12);
|
||||
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length);
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length, 0);
|
||||
|
||||
per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID);
|
||||
per_write_integer16(s, channel_id, 0);
|
||||
|
@ -129,16 +129,22 @@ typedef struct rdp_mcs rdpMcs;
|
||||
boolean mcs_connect(rdpMcs* mcs);
|
||||
|
||||
void mcs_write_connect_initial(STREAM* s, rdpMcs* mcs, STREAM* user_data);
|
||||
void mcs_write_connect_response(STREAM* s, rdpMcs* mcs, STREAM* user_data);
|
||||
|
||||
boolean mcs_read_connect_initial(rdpMcs* mcs, STREAM* s);
|
||||
void mcs_send_connect_initial(rdpMcs* mcs);
|
||||
void mcs_recv_connect_response(rdpMcs* mcs);
|
||||
boolean mcs_send_connect_response(rdpMcs* mcs);
|
||||
boolean mcs_read_erect_domain_request(rdpMcs* mcs, STREAM* s);
|
||||
void mcs_send_erect_domain_request(rdpMcs* mcs);
|
||||
boolean mcs_read_attach_user_request(rdpMcs* mcs, STREAM* s);
|
||||
void mcs_send_attach_user_request(rdpMcs* mcs);
|
||||
void mcs_recv_attach_user_confirm(rdpMcs* mcs);
|
||||
boolean mcs_send_attach_user_confirm(rdpMcs* mcs);
|
||||
void mcs_send_channel_join_request(rdpMcs* mcs, uint16 channel_id);
|
||||
void mcs_recv_channel_join_confirm(rdpMcs* mcs);
|
||||
boolean mcs_read_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU* domainMCSPDU, int* length);
|
||||
void mcs_write_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU domainMCSPDU, int length);
|
||||
void mcs_write_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU domainMCSPDU, int length, uint8 options);
|
||||
|
||||
rdpMcs* mcs_new(rdpTransport* transport);
|
||||
void mcs_free(rdpMcs* mcs);
|
||||
|
@ -82,6 +82,7 @@ boolean nego_connect(rdpNego* nego)
|
||||
DEBUG_NEGO("Negotiated %s security", PROTOCOL_SECURITY_STRINGS[nego->selected_protocol]);
|
||||
|
||||
/* update settings with negotiated protocol security */
|
||||
nego->transport->settings->requested_protocols = nego->requested_protocols;
|
||||
nego->transport->settings->selected_protocol = nego->selected_protocol;
|
||||
|
||||
return True;
|
||||
@ -269,6 +270,59 @@ int nego_recv(rdpTransport* transport, STREAM* s, void* extra)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive protocol security negotiation request message.\n
|
||||
* @param nego
|
||||
* @param s stream
|
||||
*/
|
||||
|
||||
boolean nego_recv_request(rdpNego* nego, STREAM* s)
|
||||
{
|
||||
uint8 li;
|
||||
uint8 c;
|
||||
uint8 type;
|
||||
|
||||
tpkt_read_header(s);
|
||||
li = tpdu_read_connection_request(s);
|
||||
if (li != stream_get_left(s) + 6)
|
||||
{
|
||||
printf("Incorrect TPDU length indicator.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (stream_get_left(s) > 8)
|
||||
{
|
||||
/* Optional routingToken or cookie, ending with CR+LF */
|
||||
while (stream_get_left(s) > 0)
|
||||
{
|
||||
stream_read_uint8(s, c);
|
||||
if (c != '\x0D')
|
||||
continue;
|
||||
stream_peek_uint8(s, c);
|
||||
if (c != '\x0A')
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_get_left(s) >= 8)
|
||||
{
|
||||
/* rdpNegData (optional) */
|
||||
|
||||
stream_read_uint8(s, type); /* Type */
|
||||
if (type != TYPE_RDP_NEG_REQ)
|
||||
{
|
||||
printf("Incorrect negotiation request type %d\n", type);
|
||||
return False;
|
||||
}
|
||||
|
||||
nego_process_negotiation_request(nego, s);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send protocol security negotiation message.
|
||||
* @param nego
|
||||
@ -339,6 +393,26 @@ void nego_send_negotiation_request(rdpNego* nego)
|
||||
transport_write(nego->transport, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Negotiation Request from Connection Request message.
|
||||
* @param nego
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void nego_process_negotiation_request(rdpNego* nego, STREAM* s)
|
||||
{
|
||||
uint8 flags;
|
||||
uint16 length;
|
||||
|
||||
DEBUG_NEGO("RDP_NEG_REQ");
|
||||
|
||||
stream_read_uint8(s, flags);
|
||||
stream_read_uint16(s, length);
|
||||
stream_read_uint32(s, nego->requested_protocols);
|
||||
|
||||
nego->state = NEGO_STATE_FINAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Negotiation Response from Connection Confirm message.
|
||||
* @param nego
|
||||
@ -402,6 +476,45 @@ void nego_process_negotiation_failure(rdpNego* nego, STREAM* s)
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send RDP Negotiation Response (RDP_NEG_RSP).\n
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_send_negotiation_response(rdpNego* nego)
|
||||
{
|
||||
STREAM* s;
|
||||
int length;
|
||||
uint8 *bm, *em;
|
||||
|
||||
s = stream_new(64);
|
||||
length = TPDU_CONNECTION_CONFIRM_LENGTH;
|
||||
stream_get_mark(s, bm);
|
||||
stream_seek(s, length);
|
||||
|
||||
if (nego->selected_protocol > PROTOCOL_RDP)
|
||||
{
|
||||
/* RDP_NEG_DATA must be present for TLS and NLA */
|
||||
stream_write_uint8(s, TYPE_RDP_NEG_RSP);
|
||||
stream_write_uint8(s, EXTENDED_CLIENT_DATA_SUPPORTED); /* flags */
|
||||
stream_write_uint16(s, 8); /* RDP_NEG_DATA length (8) */
|
||||
stream_write_uint32(s, nego->selected_protocol); /* selectedProtocol */
|
||||
length += 8;
|
||||
}
|
||||
|
||||
stream_get_mark(s, em);
|
||||
stream_set_mark(s, bm);
|
||||
tpkt_write_header(s, length);
|
||||
tpdu_write_connection_confirm(s, length - 5);
|
||||
stream_set_mark(s, em);
|
||||
|
||||
transport_write(nego->transport, s);
|
||||
|
||||
/* update settings with negotiated protocol security */
|
||||
nego->transport->settings->requested_protocols = nego->requested_protocols;
|
||||
nego->transport->settings->selected_protocol = nego->selected_protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize NEGO state machine.
|
||||
* @param nego
|
||||
|
@ -65,6 +65,8 @@ enum RDP_NEG_MSG
|
||||
TYPE_RDP_NEG_FAILURE = 0x3
|
||||
};
|
||||
|
||||
#define EXTENDED_CLIENT_DATA_SUPPORTED 0x01
|
||||
|
||||
extern char NEGO_STATE_STRINGS[6][25];
|
||||
extern char PROTOCOL_SECURITY_STRINGS[3][4];
|
||||
|
||||
@ -92,10 +94,13 @@ void nego_attempt_rdp(rdpNego* nego);
|
||||
void nego_send(rdpNego* nego);
|
||||
int nego_recv(rdpTransport* transport, STREAM* s, void* extra);
|
||||
void nego_recv_response(rdpNego* nego);
|
||||
boolean nego_recv_request(rdpNego* nego, STREAM* s);
|
||||
|
||||
void nego_send_negotiation_request(rdpNego* nego);
|
||||
void nego_process_negotiation_request(rdpNego* nego, STREAM* s);
|
||||
void nego_process_negotiation_response(rdpNego* nego, STREAM* s);
|
||||
void nego_process_negotiation_failure(rdpNego* nego, STREAM* s);
|
||||
void nego_send_negotiation_response(rdpNego* nego);
|
||||
|
||||
rdpNego* nego_new(struct rdp_transport * transport);
|
||||
void nego_free(rdpNego* nego);
|
||||
|
130
libfreerdp-core/peer.c
Normal file
130
libfreerdp-core/peer.c
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* RDP Server Peer
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* 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 "peer.h"
|
||||
|
||||
static boolean freerdp_peer_initialize(freerdp_peer* client)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
|
||||
peer->rdp->state = CONNECTION_STATE_INITIAL;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static boolean freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
|
||||
rfds[*rcount] = (void*)(long)(peer->rdp->transport->tcp->sockfd);
|
||||
(*rcount)++;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static boolean freerdp_peer_check_fds(freerdp_peer* client)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
rdpRdp* rdp;
|
||||
int status;
|
||||
|
||||
rdp = (rdpRdp*) peer->rdp;
|
||||
|
||||
status = rdp_check_fds(rdp);
|
||||
if (status < 0)
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static int peer_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)extra;
|
||||
|
||||
switch (peer->rdp->state)
|
||||
{
|
||||
case CONNECTION_STATE_INITIAL:
|
||||
if (!rdp_server_accept_nego(peer->rdp, s))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case CONNECTION_STATE_NEGO:
|
||||
if (!rdp_server_accept_mcs_connect_initial(peer->rdp, s))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case CONNECTION_STATE_MCS_CONNECT:
|
||||
if (!rdp_server_accept_mcs_erect_domain_request(peer->rdp, s))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case CONNECTION_STATE_MCS_ERECT_DOMAIN:
|
||||
if (!rdp_server_accept_mcs_attach_user_request(peer->rdp, s))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Invalid state %d\n", peer->rdp->state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void freerdp_peer_disconnect(freerdp_peer* client)
|
||||
{
|
||||
}
|
||||
|
||||
freerdp_peer* freerdp_peer_new(int sockfd)
|
||||
{
|
||||
freerdp_peer* client;
|
||||
rdpPeer* peer;
|
||||
|
||||
client = xnew(freerdp_peer);
|
||||
|
||||
client->Initialize = freerdp_peer_initialize;
|
||||
client->GetFileDescriptor = freerdp_peer_get_fds;
|
||||
client->CheckFileDescriptor = freerdp_peer_check_fds;
|
||||
client->Disconnect = freerdp_peer_disconnect;
|
||||
|
||||
peer = xnew(rdpPeer);
|
||||
peer->client = client;
|
||||
peer->rdp = rdp_new(NULL);
|
||||
|
||||
client->peer = (void*)peer;
|
||||
client->settings = peer->rdp->settings;
|
||||
|
||||
transport_attach(peer->rdp->transport, sockfd);
|
||||
|
||||
peer->rdp->transport->recv_callback = peer_recv_callback;
|
||||
peer->rdp->transport->recv_extra = peer;
|
||||
transport_set_blocking_mode(peer->rdp->transport, False);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
void freerdp_peer_free(freerdp_peer* client)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
|
||||
rdp_free(peer->rdp);
|
||||
xfree(peer);
|
||||
xfree(client);
|
||||
}
|
||||
|
36
libfreerdp-core/peer.h
Normal file
36
libfreerdp-core/peer.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* RDP Server Peer
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __PEER
|
||||
#define __PEER
|
||||
|
||||
typedef struct rdp_peer rdpPeer;
|
||||
|
||||
#include "rdp.h"
|
||||
#include <freerdp/peer.h>
|
||||
|
||||
struct rdp_peer
|
||||
{
|
||||
freerdp_peer* client;
|
||||
|
||||
rdpRdp* rdp;
|
||||
};
|
||||
|
||||
#endif /* __PEER */
|
||||
|
@ -133,6 +133,19 @@ void per_write_number_of_sets(STREAM* s, uint8 number)
|
||||
stream_write_uint8(s, number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER padding with zeros.
|
||||
* @param s stream
|
||||
* @param length
|
||||
*/
|
||||
|
||||
boolean per_read_padding(STREAM* s, int length)
|
||||
{
|
||||
stream_seek(s, length);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER padding with zeros.
|
||||
* @param s stream
|
||||
@ -246,6 +259,19 @@ boolean per_read_enumerated(STREAM* s, uint8* enumerated, uint8 count)
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER ENUMERATED.
|
||||
* @param s stream
|
||||
* @param enumerated enumerated
|
||||
* @param count enumeration count
|
||||
* @return
|
||||
*/
|
||||
|
||||
void per_write_enumerated(STREAM* s, uint8 enumerated, uint8 count)
|
||||
{
|
||||
stream_write_uint8(s, enumerated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER OBJECT_IDENTIFIER (OID).
|
||||
* @param s stream
|
||||
@ -371,6 +397,32 @@ void per_write_octet_string(STREAM* s, uint8* oct_str, int length, int min)
|
||||
stream_write_uint8(s, oct_str[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER NumericString.
|
||||
* @param s stream
|
||||
* @param num_str numeric string
|
||||
* @param length string length
|
||||
* @param min minimum string length
|
||||
*/
|
||||
|
||||
boolean per_read_numeric_string(STREAM* s, int min)
|
||||
{
|
||||
int i;
|
||||
int length;
|
||||
uint16 mlength;
|
||||
|
||||
per_read_length(s, &mlength);
|
||||
|
||||
length = mlength + min;
|
||||
|
||||
for (i = 0; i < length; i += 2)
|
||||
{
|
||||
stream_seek(s, 1);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER NumericString.
|
||||
* @param s stream
|
||||
|
@ -30,18 +30,19 @@ boolean per_read_selection(STREAM* s, uint8* selection);
|
||||
void per_write_selection(STREAM* s, uint8 selection);
|
||||
boolean per_read_number_of_sets(STREAM* s, uint8* number);
|
||||
void per_write_number_of_sets(STREAM* s, uint8 number);
|
||||
boolean per_read_padding(STREAM* s, int length);
|
||||
void per_write_padding(STREAM* s, int length);
|
||||
boolean per_read_integer(STREAM* s, uint32* integer);
|
||||
boolean per_read_integer16(STREAM* s, uint16* integer, uint16 min);
|
||||
void per_write_integer(STREAM* s, uint32 integer);
|
||||
void per_write_integer16(STREAM* s, uint16 integer, uint16 min);
|
||||
boolean per_read_enumerated(STREAM* s, uint8* enumerated, uint8 count);
|
||||
void per_write_enumerated(STREAM* s, uint8 enumerated, uint8 count);
|
||||
void per_write_object_identifier(STREAM* s, uint8 oid[6]);
|
||||
boolean per_read_object_identifier(STREAM* s, uint8 oid[6]);
|
||||
boolean per_read_octet_string(STREAM* s, uint8* oct_str, int length, int min);
|
||||
void per_write_octet_string(STREAM* s, uint8* oct_str, int length, int min);
|
||||
boolean per_read_numeric_string(STREAM* s, int min);
|
||||
void per_write_numeric_string(STREAM* s, uint8* num_str, int length, int min);
|
||||
boolean per_read_integer16(STREAM* s, uint16* integer, uint16 min);
|
||||
void per_write_integer16(STREAM* s, uint16 integer, uint16 min);
|
||||
|
||||
#endif /* __PER_H */
|
||||
|
@ -179,7 +179,7 @@ STREAM* rdp_data_pdu_init(rdpRdp* rdp)
|
||||
|
||||
void rdp_write_header(rdpRdp* rdp, STREAM* s, int length, uint16 channel_id)
|
||||
{
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_SendDataRequest, length);
|
||||
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_SendDataRequest, length, 0);
|
||||
per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator */
|
||||
per_write_integer16(s, channel_id, 0); /* channelId */
|
||||
stream_write_uint8(s, 0x70); /* dataPriority + segmentation */
|
||||
|
@ -115,6 +115,7 @@ struct rdp_rdp
|
||||
{
|
||||
boolean licensed;
|
||||
boolean activated;
|
||||
int state;
|
||||
struct rdp_mcs* mcs;
|
||||
struct rdp_nego* nego;
|
||||
struct rdp_input* input;
|
||||
|
@ -137,6 +137,8 @@ void settings_free(rdpSettings* settings)
|
||||
xfree(settings->shell);
|
||||
xfree(settings->directory);
|
||||
xfree(settings->client_dir);
|
||||
xfree(settings->cert_file);
|
||||
xfree(settings->privatekey_file);
|
||||
xfree(settings);
|
||||
}
|
||||
}
|
||||
|
@ -155,12 +155,14 @@ int tcp_read(rdpTcp* tcp, uint8* data, int length)
|
||||
|
||||
status = recv(tcp->sockfd, data, length, 0);
|
||||
|
||||
if (status < 0)
|
||||
if (status <= 0)
|
||||
{
|
||||
/* No data available */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return 0;
|
||||
|
||||
perror("recv");
|
||||
/* When peer disconnects we get status 0 with no error. */
|
||||
if (status < 0)
|
||||
perror("recv");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,24 @@ boolean tls_connect(rdpTls* tls)
|
||||
{
|
||||
int connection_status;
|
||||
|
||||
tls->ctx = SSL_CTX_new(TLSv1_client_method());
|
||||
|
||||
if (tls->ctx == NULL)
|
||||
{
|
||||
printf("SSL_CTX_new failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is necessary, because the Microsoft TLS implementation is not perfect.
|
||||
* SSL_OP_ALL enables a couple of workarounds for buggy TLS implementations,
|
||||
* but the most important workaround being SSL_OP_TLS_BLOCK_PADDING_BUG.
|
||||
* As the size of the encrypted payload may give hints about its contents,
|
||||
* block padding is normally used, but the Microsoft TLS implementation
|
||||
* won't recognize it and will disconnect you after sending a TLS alert.
|
||||
*/
|
||||
SSL_CTX_set_options(tls->ctx, SSL_OP_ALL);
|
||||
|
||||
tls->ssl = SSL_new(tls->ctx);
|
||||
|
||||
if (tls->ssl == NULL)
|
||||
@ -40,24 +58,9 @@ boolean tls_connect(rdpTls* tls)
|
||||
return False;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
connection_status = SSL_connect(tls->ssl);
|
||||
connection_status = SSL_connect(tls->ssl);
|
||||
|
||||
/*
|
||||
* SSL_WANT_READ and SSL_WANT_WRITE errors are normal,
|
||||
* just try again if it happens
|
||||
*/
|
||||
|
||||
if (connection_status == SSL_ERROR_WANT_READ)
|
||||
continue;
|
||||
else if (connection_status == SSL_ERROR_WANT_WRITE)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (connection_status < 0)
|
||||
if (connection_status <= 0)
|
||||
{
|
||||
if (tls_print_error("SSL_connect", tls->ssl, connection_status))
|
||||
return False;
|
||||
@ -68,6 +71,57 @@ boolean tls_connect(rdpTls* tls)
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file)
|
||||
{
|
||||
int connection_status;
|
||||
|
||||
tls->ctx = SSL_CTX_new(TLSv1_server_method());
|
||||
|
||||
if (tls->ctx == NULL)
|
||||
{
|
||||
printf("SSL_CTX_new failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_RSAPrivateKey_file(tls->ctx, privatekey_file, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
printf("SSL_CTX_use_RSAPrivateKey_file failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
tls->ssl = SSL_new(tls->ctx);
|
||||
|
||||
if (tls->ssl == NULL)
|
||||
{
|
||||
printf("SSL_new failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (SSL_use_certificate_file(tls->ssl, cert_file, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
printf("SSL_use_certificate_file failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
|
||||
{
|
||||
printf("SSL_set_fd failed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
connection_status = SSL_accept(tls->ssl);
|
||||
|
||||
if (connection_status <= 0)
|
||||
{
|
||||
if (tls_print_error("SSL_accept", tls->ssl, connection_status))
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("TLS connection accepted\n");
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean tls_disconnect(rdpTls* tls)
|
||||
{
|
||||
return True;
|
||||
@ -85,10 +139,12 @@ int tls_read(rdpTls* tls, uint8* data, int length)
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
tls_print_error("SSL_read", tls->ssl, status);
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
@ -107,6 +163,7 @@ int tls_write(rdpTls* tls, uint8* data, int length)
|
||||
case SSL_ERROR_NONE:
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
status = 0;
|
||||
break;
|
||||
@ -180,29 +237,11 @@ rdpTls* tls_new()
|
||||
if (tls != NULL)
|
||||
{
|
||||
tls->connect = tls_connect;
|
||||
tls->accept = tls_accept;
|
||||
tls->disconnect = tls_disconnect;
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
tls->ctx = SSL_CTX_new(TLSv1_client_method());
|
||||
|
||||
if (tls->ctx == NULL)
|
||||
{
|
||||
printf("SSL_CTX_new failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is necessary, because the Microsoft TLS implementation is not perfect.
|
||||
* SSL_OP_ALL enables a couple of workarounds for buggy TLS implementations,
|
||||
* but the most important workaround being SSL_OP_TLS_BLOCK_PADDING_BUG.
|
||||
* As the size of the encrypted payload may give hints about its contents,
|
||||
* block padding is normally used, but the Microsoft TLS implementation
|
||||
* won't recognize it and will disconnect you after sending a TLS alert.
|
||||
*/
|
||||
|
||||
SSL_CTX_set_options(tls->ctx, SSL_OP_ALL);
|
||||
}
|
||||
|
||||
return tls;
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
typedef struct rdp_tls rdpTls;
|
||||
typedef boolean (*TlsConnect) (rdpTls* tls);
|
||||
typedef boolean (*TlsAccept) (rdpTls* tls, const char* cert_file, const char* privatekey_file);
|
||||
typedef boolean (*TlsDisconnect) (rdpTls* tls);
|
||||
|
||||
struct rdp_tls
|
||||
@ -38,10 +39,12 @@ struct rdp_tls
|
||||
int sockfd;
|
||||
SSL_CTX* ctx;
|
||||
TlsConnect connect;
|
||||
TlsAccept accept;
|
||||
TlsDisconnect disconnect;
|
||||
};
|
||||
|
||||
boolean tls_connect(rdpTls* tls);
|
||||
boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file);
|
||||
boolean tls_disconnect(rdpTls* tls);
|
||||
int tls_read(rdpTls* tls, uint8* data, int length);
|
||||
int tls_write(rdpTls* tls, uint8* data, int length);
|
||||
|
@ -111,6 +111,28 @@ tpdu_write_header(STREAM* s, uint16 length, uint8 code)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read Connection Request TPDU
|
||||
* @param s stream
|
||||
* @return length indicator (LI)
|
||||
*/
|
||||
|
||||
uint8 tpdu_read_connection_request(STREAM* s)
|
||||
{
|
||||
uint8 li;
|
||||
uint8 code;
|
||||
|
||||
li = tpdu_read_header(s, &code);
|
||||
|
||||
if (code != X224_TPDU_CONNECTION_REQUEST)
|
||||
{
|
||||
printf("Error: expected X224_TPDU_CONNECTION_REQUEST\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Connection Request TPDU.
|
||||
* @param s stream
|
||||
@ -146,6 +168,18 @@ tpdu_read_connection_confirm(STREAM* s)
|
||||
return li;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Connection Confirm TPDU.
|
||||
* @param s stream
|
||||
* @param length TPDU length
|
||||
*/
|
||||
|
||||
void
|
||||
tpdu_write_connection_confirm(STREAM* s, uint16 length)
|
||||
{
|
||||
tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Disconnect Request TPDU.
|
||||
* @param s stream
|
||||
|
@ -43,8 +43,10 @@ enum X224_TPDU_TYPE
|
||||
|
||||
uint8 tpdu_read_header(STREAM* s, uint8* code);
|
||||
void tpdu_write_header(STREAM* s, uint16 length, uint8 code);
|
||||
uint8 tpdu_read_connection_request(STREAM* s);
|
||||
void tpdu_write_connection_request(STREAM* s, uint16 length);
|
||||
uint8 tpdu_read_connection_confirm(STREAM* s);
|
||||
void tpdu_write_connection_confirm(STREAM* s, uint16 length);
|
||||
void tpdu_write_disconnect_request(STREAM* s, uint16 length);
|
||||
uint16 tpdu_read_data(STREAM* s);
|
||||
void tpdu_write_data(STREAM* s);
|
||||
|
@ -63,6 +63,11 @@ boolean transport_connect(rdpTransport* transport, const char* hostname, uint16
|
||||
return transport->tcp->connect(transport->tcp, hostname, port);
|
||||
}
|
||||
|
||||
void transport_attach(rdpTransport* transport, int sockfd)
|
||||
{
|
||||
transport->tcp->sockfd = sockfd;
|
||||
}
|
||||
|
||||
boolean transport_disconnect(rdpTransport* transport)
|
||||
{
|
||||
return transport->tcp->disconnect(transport->tcp);
|
||||
@ -126,6 +131,52 @@ boolean transport_connect_nla(rdpTransport* transport)
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean transport_accept_rdp(rdpTransport* transport)
|
||||
{
|
||||
transport->state = TRANSPORT_STATE_RDP;
|
||||
|
||||
/* RDP encryption */
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean transport_accept_tls(rdpTransport* transport)
|
||||
{
|
||||
if (transport->tls == NULL)
|
||||
transport->tls = tls_new();
|
||||
|
||||
transport->layer = TRANSPORT_LAYER_TLS;
|
||||
transport->state = TRANSPORT_STATE_TLS;
|
||||
transport->tls->sockfd = transport->tcp->sockfd;
|
||||
|
||||
if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) != True)
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean transport_accept_nla(rdpTransport* transport)
|
||||
{
|
||||
if (transport->tls == NULL)
|
||||
transport->tls = tls_new();
|
||||
|
||||
transport->layer = TRANSPORT_LAYER_TLS;
|
||||
transport->state = TRANSPORT_STATE_NLA;
|
||||
transport->tls->sockfd = transport->tcp->sockfd;
|
||||
|
||||
if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) != True)
|
||||
return False;
|
||||
|
||||
/* Network Level Authentication */
|
||||
|
||||
if (transport->settings->authentication != True)
|
||||
return True;
|
||||
|
||||
/* Blocking here until NLA is complete */
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
int transport_read(rdpTransport* transport, STREAM* s)
|
||||
{
|
||||
int status = -1;
|
||||
|
@ -69,10 +69,14 @@ struct rdp_transport
|
||||
STREAM* transport_recv_stream_init(rdpTransport* transport, int size);
|
||||
STREAM* transport_send_stream_init(rdpTransport* transport, int size);
|
||||
boolean transport_connect(rdpTransport* transport, const char* hostname, uint16 port);
|
||||
void transport_attach(rdpTransport* transport, int sockfd);
|
||||
boolean transport_disconnect(rdpTransport* transport);
|
||||
boolean transport_connect_rdp(rdpTransport* transport);
|
||||
boolean transport_connect_tls(rdpTransport* transport);
|
||||
boolean transport_connect_nla(rdpTransport* transport);
|
||||
boolean transport_accept_rdp(rdpTransport* transport);
|
||||
boolean transport_accept_tls(rdpTransport* transport);
|
||||
boolean transport_accept_nla(rdpTransport* transport);
|
||||
int transport_read(rdpTransport* transport, STREAM* s);
|
||||
int transport_write(rdpTransport* transport, STREAM* s);
|
||||
int transport_check_fds(rdpTransport* transport);
|
||||
|
27
server/CMakeLists.txt
Normal file
27
server/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Client
|
||||
# FreeRDP Servers
|
||||
#
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 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.
|
||||
|
||||
# Servers
|
||||
|
||||
if(NOT WIN32)
|
||||
|
||||
# Build Test Server
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
25
server/test/CMakeLists.txt
Normal file
25
server/test/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Client
|
||||
# FreeRDP Test Server cmake build script
|
||||
#
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 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.
|
||||
|
||||
add_executable(freerdp-server-test
|
||||
freerdp_server.c)
|
||||
|
||||
target_link_libraries(freerdp-server-test freerdp-core)
|
||||
target_link_libraries(freerdp-server-test freerdp-utils)
|
||||
target_link_libraries(freerdp-server-test freerdp-rfx)
|
186
server/test/freerdp_server.c
Normal file
186
server/test/freerdp_server.c
Normal file
@ -0,0 +1,186 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Test Server
|
||||
*
|
||||
* Copyright 2011 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/thread.h>
|
||||
#include <freerdp/listener.h>
|
||||
|
||||
static void* test_peer_mainloop(void* arg)
|
||||
{
|
||||
freerdp_peer* client = (freerdp_peer*)arg;
|
||||
int i;
|
||||
int fds;
|
||||
int max_fds;
|
||||
int rcount;
|
||||
void* rfds[32];
|
||||
fd_set rfds_set;
|
||||
|
||||
memset(rfds, 0, sizeof(rfds));
|
||||
|
||||
printf("We've got a client %s\n", client->settings->hostname);
|
||||
|
||||
client->settings->cert_file = xstrdup("server.crt");
|
||||
client->settings->privatekey_file = xstrdup("server.key");
|
||||
client->settings->nla_security = False;
|
||||
client->Initialize(client);
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
|
||||
if (client->GetFileDescriptor(client, 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 (client->CheckFileDescriptor(client) != True)
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Client %s disconnected.\n", client->settings->hostname);
|
||||
|
||||
client->Disconnect(client);
|
||||
freerdp_peer_free(client);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
|
||||
{
|
||||
pthread_t th;
|
||||
|
||||
pthread_create(&th, 0, test_peer_mainloop, client);
|
||||
pthread_detach(th);
|
||||
}
|
||||
|
||||
static void test_server_mainloop(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;
|
||||
|
||||
instance = freerdp_listener_new();
|
||||
|
||||
instance->PeerAccepted = test_peer_accepted;
|
||||
|
||||
/* Open the server socket and start listening. */
|
||||
if (instance->Open(instance, (argc > 1 ? argv[1] : NULL), 3389))
|
||||
{
|
||||
/* Entering the server main loop. In a real server the listener can be run in its own thread. */
|
||||
test_server_mainloop(instance);
|
||||
}
|
||||
|
||||
freerdp_listener_free(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
17
server/test/server.crt
Normal file
17
server/test/server.crt
Normal file
@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICyzCCAbOgAwIBAgIJANbqtAWwlQZuMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
|
||||
BAMTB0ZyZWVSRFAwHhcNMDkxMDI5MDA0MTQ5WhcNMDkxMTI4MDA0MTQ5WjASMRAw
|
||||
DgYDVQQDEwdGcmVlUkRQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
q7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1TptzXTcmfDrDslTGwcEY
|
||||
hTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2SXvTiaV26VPPxddGb
|
||||
o6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJLd2SU4ItWHj8zjz1f
|
||||
eGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsjgvz4yP7I3TL8+GsN
|
||||
MjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdymrulJSIhoOVfKkwi
|
||||
ptTe43FgwxVRIygJP9HjHQIDAQABoyQwIjATBgNVHSUEDDAKBggrBgEFBQcDATAL
|
||||
BgNVHQ8EBAMCBDAwDQYJKoZIhvcNAQEFBQADggEBAIOdEDhOX2kbl02znltd9hCr
|
||||
nV4kRPKm979RKwBNkrEuwYSlcsjAHg5MZ5itH3wFOUo2s5pjt7/vMOAg+6rOBbIa
|
||||
nqr22/gKBtOmuaJLG1yjxDC2vfez7f3B26pKgxa/krM8oxiFdT9n8QbdxdkN7/D9
|
||||
3RLU/aCfgrMzXxRus7eq3kR00jnSs6ggnAfE1E9gric3vFgr1wCzdcriRXmXDfUb
|
||||
hRq+4VG+ZWk16TwCofV5GVU39XWCv5HNO2swAdjkNXgI5e3tQbV3wWLZLqqYzBco
|
||||
iWulAXtoCGmE81+u1Ms7hLLzpXitLZSGPu1r+sDdkKPLCmOvkAaljDQ4nBz7fIA=
|
||||
-----END CERTIFICATE-----
|
27
server/test/server.key
Normal file
27
server/test/server.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAq7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1Tptz
|
||||
XTcmfDrDslTGwcEYhTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2S
|
||||
XvTiaV26VPPxddGbo6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJL
|
||||
d2SU4ItWHj8zjz1feGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsj
|
||||
gvz4yP7I3TL8+GsNMjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdy
|
||||
mrulJSIhoOVfKkwiptTe43FgwxVRIygJP9HjHQIDAQABAoIBAAVv5K54xtc1JtBR
|
||||
1lfdPbSqDlnjx8aOnVIPg5TnqMp3sR8jBt0NsPc/+RA9ZOmfjoIxFAEJaZ9zSDJC
|
||||
5BqmnxC5R1mfCQkSd2haQ+4pdFvWyrv4Bblh8YU6hXrJGn0LfO0KlIcywtAvKpsi
|
||||
LtTyZkWmaW2HeF/+pO32jYygw38R1wd8Tl6GwjOXwTF6lFACJXOT4YAzcfp3FKSB
|
||||
AiKBIGuMzozoSND7KPFNRrhGhNumJpdS5A8Fb8D2c/ZMv6Cq5IbwOgTfKun+Bz+s
|
||||
mFbnzeb1uWRqQbsVXOBBW/zHfuG3SU5qeZsaAyuu4DTy+LE1oAHF9uhBSHuT5C6i
|
||||
vCJ8A8ECgYEA1iaOmiEJYBrs25iAc4SjCKqhY0mwR3wtu3I06vmgUoML5fhPMv36
|
||||
SvYQIqDyNw3p7TE6mZtw9+G+kK3PqhuJhogwSwg0a6o51RdKnhXH3/68oNWtKCLC
|
||||
1AmR8q/Gd3FwAR3b49CuOIZ9uOiJrc/ejzKdFEJTDR1/TX1frWfZznECgYEAzUiz
|
||||
XxFf7YrGel7JgmfRD2eZRYngOoteFlg5Tee42UjeAY2Pt2aiDLk+2TqQEdI9+Xg7
|
||||
LcFdBqcSNd8bh33xSzgNthIkX+lTDzx0SmKGfyxfFBJcY8nzsLvvnNt3YeuMeaJQ
|
||||
CPszwoZ0jcD46jTCjbrKhaLyEWmUkDp1O71NTW0CgYAXKF49Xpsz8FVyvcAOPeaf
|
||||
dkwzf3F3mX8ciRId4taqdY9g1AREgGCDoK5IAF2RBIkqZCtxFvUVaS0BWjpdq9Ko
|
||||
YKvQQVfh2KueVoF0LOjLWTGutsydzXyCD3Lf6pAstHCnPkJcFWHxrOGFkGfrCtKH
|
||||
a7K+0RlIDsuIZqllCBjukQKBgA31+MTpYJW+D1t5IMkumEgs6n6RLt+sZLyuSU9k
|
||||
B+03CGogn3qAj1rAKmcJlYywuKhDpfqpoNL3/8QMJUokpYlRCZWtTC39pzltCheY
|
||||
9b6mXNz3lrLupBUL4vLO9iKBq28GO90wgEelbz3ItuTuq6CJ6IYIG+BVRtY8M4bZ
|
||||
i+1NAoGANXZjYnJYDnh8Je9SDxDSc5byzK7ddkQoId64RCIfNHqNKH63P81vjgnH
|
||||
YBIPtagY75ZVVNxujCF7m8Rety+d8tEFwfQKDin2EVI7PD2rOJra385/izp7HuBR
|
||||
vqxvLzG9Xv3cNOU2l7PttVw4Pa2i5E37atKi3V3Zp2kMW+KaKPQ=
|
||||
-----END RSA PRIVATE KEY-----
|
Loading…
Reference in New Issue
Block a user