1 /** 2 * FreeRDP: A Remote Desktop Protocol Implementation 3 * FreeRDP Interface 4 * 5 * Copyright 2009-2011 Jay Sorg 6 * Copyright 2015 Thincast Technologies GmbH 7 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com> 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 #ifndef FREERDP_H 23 #define FREERDP_H 24 25 typedef struct rdp_rdp rdpRdp; 26 typedef struct rdp_gdi rdpGdi; 27 typedef struct rdp_rail rdpRail; 28 typedef struct rdp_cache rdpCache; 29 typedef struct rdp_channels rdpChannels; 30 typedef struct rdp_graphics rdpGraphics; 31 typedef struct rdp_metrics rdpMetrics; 32 typedef struct rdp_codecs rdpCodecs; 33 34 typedef struct rdp_freerdp freerdp; 35 typedef struct rdp_context rdpContext; 36 typedef struct rdp_freerdp_peer freerdp_peer; 37 38 typedef struct rdp_client_context rdpClientContext; 39 typedef struct rdp_client_entry_points_v1 RDP_CLIENT_ENTRY_POINTS_V1; 40 typedef RDP_CLIENT_ENTRY_POINTS_V1 RDP_CLIENT_ENTRY_POINTS; 41 42 #include <freerdp/api.h> 43 #include <freerdp/types.h> 44 #include <freerdp/error.h> 45 #include <freerdp/event.h> 46 #include <freerdp/codecs.h> 47 #include <freerdp/metrics.h> 48 #include <freerdp/settings.h> 49 #include <freerdp/extension.h> 50 51 #include <winpr/stream.h> 52 53 #include <freerdp/input.h> 54 #include <freerdp/update.h> 55 #include <freerdp/message.h> 56 #include <freerdp/autodetect.h> 57 #include <freerdp/heartbeat.h> 58 59 #ifdef __cplusplus 60 extern "C" 61 { 62 #endif 63 64 /* Flags used by certificate callbacks */ 65 #define VERIFY_CERT_FLAG_NONE 0x00 66 #define VERIFY_CERT_FLAG_LEGACY 0x02 67 #define VERIFY_CERT_FLAG_REDIRECT 0x10 68 #define VERIFY_CERT_FLAG_GATEWAY 0x20 69 #define VERIFY_CERT_FLAG_CHANGED 0x40 70 #define VERIFY_CERT_FLAG_MISMATCH 0x80 71 #define VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1 0x100 72 73 /* Message types used by gateway messaging callback */ 74 #define GATEWAY_MESSAGE_CONSENT 1 75 #define GATEWAY_MESSAGE_SERVICE 2 76 77 typedef BOOL (*pContextNew)(freerdp* instance, rdpContext* context); 78 typedef void (*pContextFree)(freerdp* instance, rdpContext* context); 79 80 typedef BOOL (*pPreConnect)(freerdp* instance); 81 typedef BOOL (*pPostConnect)(freerdp* instance); 82 typedef void (*pPostDisconnect)(freerdp* instance); 83 typedef BOOL (*pAuthenticate)(freerdp* instance, char** username, char** password, 84 char** domain); 85 86 #if !defined(DEFINE_NO_DEPRECATED) 87 /** @brief Callback used if user interaction is required to accept 88 * an unknown certificate. 89 * 90 * @deprecated Use pVerifyCertificateEx 91 * @param common_name The certificate registered hostname. 92 * @param subject The common name of the certificate. 93 * @param issuer The issuer of the certificate. 94 * @param fingerprint The fingerprint of the certificate. 95 * @param host_mismatch A flag indicating the certificate 96 * subject does not match the host connecting to. 97 * 98 * @return 1 to accept and store a certificate, 2 to accept 99 * a certificate only for this session, 0 otherwise. 100 */ 101 typedef DWORD (*pVerifyCertificate)(freerdp* instance, const char* common_name, 102 const char* subject, const char* issuer, 103 const char* fingerprint, BOOL host_mismatch); 104 #endif 105 /** @brief Callback used if user interaction is required to accept 106 * an unknown certificate. 107 * 108 * @param host The hostname connecting to. 109 * @param port The port connecting to. 110 * @param common_name The certificate registered hostname. 111 * @param subject The common name of the certificate. 112 * @param issuer The issuer of the certificate. 113 * @param fingerprint The fingerprint of the certificate. 114 * @param flags Flags of type VERIFY_CERT_FLAG* 115 * 116 * @return 1 to accept and store a certificate, 2 to accept 117 * a certificate only for this session, 0 otherwise. 118 */ 119 typedef DWORD (*pVerifyCertificateEx)(freerdp* instance, const char* host, UINT16 port, 120 const char* common_name, const char* subject, 121 const char* issuer, const char* fingerprint, DWORD flags); 122 123 #if !defined(DEFINE_NO_DEPRECATED) 124 /** @brief Callback used if user interaction is required to accept 125 * a changed certificate. 126 * 127 * @deprecated Use pVerifyChangedCertificateEx 128 * @param common_name The certificate registered hostname. 129 * @param subject The common name of the new certificate. 130 * @param issuer The issuer of the new certificate. 131 * @param fingerprint The fingerprint of the new certificate. 132 * @param old_subject The common name of the old certificate. 133 * @param old_issuer The issuer of the new certificate. 134 * @param old_fingerprint The fingerprint of the old certificate. 135 * 136 * @return 1 to accept and store a certificate, 2 to accept 137 * a certificate only for this session, 0 otherwise. 138 */ 139 140 typedef DWORD (*pVerifyChangedCertificate)(freerdp* instance, const char* common_name, 141 const char* subject, const char* issuer, 142 const char* new_fingerprint, const char* old_subject, 143 const char* old_issuer, const char* old_fingerprint); 144 #endif 145 146 /** @brief Callback used if user interaction is required to accept 147 * a changed certificate. 148 * 149 * @param host The hostname connecting to. 150 * @param port The port connecting to. 151 * @param common_name The certificate registered hostname. 152 * @param subject The common name of the new certificate. 153 * @param issuer The issuer of the new certificate. 154 * @param fingerprint The fingerprint of the new certificate. 155 * @param old_subject The common name of the old certificate. 156 * @param old_issuer The issuer of the new certificate. 157 * @param old_fingerprint The fingerprint of the old certificate. 158 * @param flags Flags of type VERIFY_CERT_FLAG* 159 * 160 * @return 1 to accept and store a certificate, 2 to accept 161 * a certificate only for this session, 0 otherwise. 162 */ 163 164 typedef DWORD (*pVerifyChangedCertificateEx)(freerdp* instance, const char* host, UINT16 port, 165 const char* common_name, const char* subject, 166 const char* issuer, const char* new_fingerprint, 167 const char* old_subject, const char* old_issuer, 168 const char* old_fingerprint, DWORD flags); 169 170 /** @brief Callback used if user interaction is required to accept 171 * a certificate. 172 * 173 * @param instance Pointer to the freerdp instance. 174 * @param data Pointer to certificate data in PEM format. 175 * @param length The length of the certificate data. 176 * @param hostname The hostname connecting to. 177 * @param port The port connecting to. 178 * @param flags Flags of type VERIFY_CERT_FLAG* 179 * 180 * @return 1 to accept and store a certificate, 2 to accept 181 * a certificate only for this session, 0 otherwise. 182 */ 183 typedef int (*pVerifyX509Certificate)(freerdp* instance, const BYTE* data, size_t length, 184 const char* hostname, UINT16 port, DWORD flags); 185 186 typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type); 187 188 typedef BOOL (*pSendChannelData)(freerdp* instance, UINT16 channelId, const BYTE* data, 189 size_t size); 190 typedef BOOL (*pReceiveChannelData)(freerdp* instance, UINT16 channelId, const BYTE* data, 191 size_t size, UINT32 flags, size_t totalSize); 192 193 /* type can be one of the GATEWAY_MESSAGE_ type defines */ 194 typedef BOOL (*pPresentGatewayMessage)(freerdp* instance, UINT32 type, BOOL isDisplayMandatory, 195 BOOL isConsentMandatory, size_t length, 196 const WCHAR* message); 197 198 /** 199 * Defines the context for a given instance of RDP connection. 200 * It is embedded in the rdp_freerdp structure, and allocated by a call to 201 * freerdp_context_new(). It is deallocated by a call to freerdp_context_free(). 202 */ 203 struct rdp_context 204 { 205 ALIGN64 freerdp* instance; /**< (offset 0) 206 Pointer to a rdp_freerdp structure. 207 This is a back-link to retrieve the freerdp instance from the context. 208 It is set by the freerdp_context_new() function */ 209 ALIGN64 freerdp_peer* peer; /**< (offset 1) 210 Pointer to the client peer. 211 This is set by a call to freerdp_peer_context_new() during peer 212 initialization. This field is used only on the server side. */ 213 ALIGN64 BOOL ServerMode; /**< (offset 2) true when context is in server mode */ 214 215 ALIGN64 UINT32 LastError; /* 3 */ 216 217 UINT64 paddingA[16 - 4]; /* 4 */ 218 219 ALIGN64 int argc; /**< (offset 16) 220 Number of arguments given to the program at launch time. 221 Used to keep this data available and used later on, typically just before 222 connection initialization. 223 @see freerdp_parse_args() */ 224 ALIGN64 char** argv; /**< (offset 17) 225 List of arguments given to the program at launch time. 226 Used to keep this data available and used later on, typically just before 227 connection initialization. 228 @see freerdp_parse_args() */ 229 230 ALIGN64 wPubSub* pubSub; /* (offset 18) */ 231 232 ALIGN64 HANDLE channelErrorEvent; /* (offset 19)*/ 233 ALIGN64 UINT channelErrorNum; /*(offset 20)*/ 234 ALIGN64 char* errorDescription; /*(offset 21)*/ 235 236 UINT64 paddingB[32 - 22]; /* 22 */ 237 238 ALIGN64 rdpRdp* 239 rdp; /**< (offset 32) 240 Pointer to a rdp_rdp structure used to keep the connection's parameters. 241 It is allocated by freerdp_context_new() and deallocated by 242 freerdp_context_free(), at the same time that this rdp_context 243 structure - there is no need to specifically allocate/deallocate this. */ 244 ALIGN64 rdpGdi* gdi; /**< (offset 33) 245 Pointer to a rdp_gdi structure used to keep the gdi settings. 246 It is allocated by gdi_init() and deallocated by gdi_free(). 247 It must be deallocated before deallocating this rdp_context structure. */ 248 ALIGN64 rdpRail* rail; /* 34 */ 249 ALIGN64 rdpCache* cache; /* 35 */ 250 ALIGN64 rdpChannels* channels; /* 36 */ 251 ALIGN64 rdpGraphics* graphics; /* 37 */ 252 ALIGN64 rdpInput* input; /* 38 */ 253 ALIGN64 rdpUpdate* update; /* 39 */ 254 ALIGN64 rdpSettings* settings; /* 40 */ 255 ALIGN64 rdpMetrics* metrics; /* 41 */ 256 ALIGN64 rdpCodecs* codecs; /* 42 */ 257 ALIGN64 rdpAutoDetect* autodetect; /* 43 */ 258 ALIGN64 HANDLE abortEvent; /* 44 */ 259 ALIGN64 int disconnectUltimatum; /* 45 */ 260 UINT64 paddingC[64 - 46]; /* 46 */ 261 262 UINT64 paddingD[96 - 64]; /* 64 */ 263 UINT64 paddingE[128 - 96]; /* 96 */ 264 }; 265 266 /** 267 * Defines the possible disconnect reasons in the MCS Disconnect Provider 268 * Ultimatum PDU 269 */ 270 271 enum Disconnect_Ultimatum 272 { 273 Disconnect_Ultimatum_domain_disconnected = 0, 274 Disconnect_Ultimatum_provider_initiated = 1, 275 Disconnect_Ultimatum_token_purged = 2, 276 Disconnect_Ultimatum_user_requested = 3, 277 Disconnect_Ultimatum_channel_purged = 4 278 }; 279 280 #include <freerdp/client.h> 281 282 /** Defines the options for a given instance of RDP connection. 283 * This is built by the client and given to the FreeRDP library to create the connection 284 * with the expected options. 285 * It is allocated by a call to freerdp_new() and deallocated by a call to freerdp_free(). 286 * Some of its content need specific allocation/deallocation - see field description for 287 * details. 288 */ 289 struct rdp_freerdp 290 { 291 ALIGN64 292 rdpContext* context; /**< (offset 0) 293 Pointer to a rdpContext structure. 294 Client applications can use the ContextSize field to register a 295 context bigger than the rdpContext structure. This allow clients to 296 use additional context information. When using this capability, client 297 application should ALWAYS declare their structure with the rdpContext 298 field first, and any additional content following it. Can be allocated 299 by a call to freerdp_context_new(). Must be deallocated by a call to 300 freerdp_context_free() before deallocating the current instance. */ 301 302 ALIGN64 RDP_CLIENT_ENTRY_POINTS* pClientEntryPoints; 303 304 UINT64 paddingA[16 - 2]; /* 2 */ 305 306 ALIGN64 rdpInput* input; /* (offset 16) 307 Input handle for the connection. 308 Will be initialized by a call to freerdp_context_new() */ 309 ALIGN64 rdpUpdate* 310 update; /* (offset 17) 311 Update display parameters. Used to register display events callbacks and settings. 312 Will be initialized by a call to freerdp_context_new() */ 313 ALIGN64 rdpSettings* settings; /**< (offset 18) 314 Pointer to a rdpSettings structure. Will be used to maintain the 315 required RDP settings. Will be 316 initialized by a call to freerdp_context_new() 317 */ 318 ALIGN64 rdpAutoDetect* autodetect; /* (offset 19) 319 Auto-Detect handle for the connection. 320 Will be initialized by a call to freerdp_context_new() */ 321 ALIGN64 rdpHeartbeat* heartbeat; /* (offset 21) */ 322 323 UINT64 paddingB[32 - 21]; /* 21 */ 324 325 ALIGN64 size_t 326 ContextSize; /* (offset 32) 327 Specifies the size of the 'context' field. freerdp_context_new() will use this 328 size to allocate the context buffer. freerdp_new() sets it to 329 sizeof(rdpContext). If modifying it, there should always be a minimum of 330 sizeof(rdpContext), as the freerdp library will assume it can use the 'context' 331 field to set the required informations in it. Clients will typically make it 332 bigger, and use a context structure embedding the rdpContext, and adding 333 additional information after that. 334 */ 335 336 ALIGN64 pContextNew 337 ContextNew; /**< (offset 33) 338 Callback for context allocation 339 Can be set before calling freerdp_context_new() to have it executed after 340 allocation and initialization. Must be set to NULL if not needed. */ 341 342 ALIGN64 pContextFree 343 ContextFree; /**< (offset 34) 344 Callback for context deallocation 345 Can be set before calling freerdp_context_free() to have it executed before 346 deallocation. Must be set to NULL if not needed. */ 347 UINT64 paddingC[47 - 35]; /* 35 */ 348 349 ALIGN64 UINT ConnectionCallbackState; /* 47 */ 350 351 ALIGN64 pPreConnect 352 PreConnect; /**< (offset 48) 353 Callback for pre-connect operations. 354 Can be set before calling freerdp_connect() to have it executed before the 355 actual connection happens. Must be set to NULL if not needed. */ 356 357 ALIGN64 pPostConnect 358 PostConnect; /**< (offset 49) 359 Callback for post-connect operations. 360 Can be set before calling freerdp_connect() to have it executed after the 361 actual connection has succeeded. Must be set to NULL if not needed. */ 362 363 ALIGN64 pAuthenticate Authenticate; /**< (offset 50) 364 Callback for authentication. 365 It is used to get the username/password when it was not 366 provided at connection time. */ 367 #if !defined(DEFINE_NO_DEPRECATED) 368 WINPR_DEPRECATED(ALIGN64 pVerifyCertificate VerifyCertificate); /**< (offset 51) 369 Callback for certificate validation. 370 Used to verify that an unknown certificate is 371 trusted. DEPRECATED: Use VerifyChangedCertificateEx*/ 372 WINPR_DEPRECATED( 373 ALIGN64 pVerifyChangedCertificate VerifyChangedCertificate); /**< (offset 52) 374 Callback for changed certificate 375 validation. Used when a certificate differs from stored fingerprint. 376 DEPRECATED: Use VerifyChangedCertificateEx */ 377 #endif 378 379 ALIGN64 pVerifyX509Certificate 380 VerifyX509Certificate; /**< (offset 53) Callback for X509 certificate verification (PEM 381 format) */ 382 383 ALIGN64 pLogonErrorInfo 384 LogonErrorInfo; /**< (offset 54) Callback for logon error info, important for logon 385 system messages with RemoteApp */ 386 387 ALIGN64 pPostDisconnect 388 PostDisconnect; /**< (offset 55) 389 Callback for cleaning up 390 resources allocated by connect callbacks. */ 391 392 ALIGN64 pAuthenticate GatewayAuthenticate; /**< (offset 56) 393 Callback for gateway authentication. 394 It is used to get the username/password when it was not 395 provided at connection time. */ 396 397 ALIGN64 pPresentGatewayMessage PresentGatewayMessage; /**< (offset 57) 398 Callback for gateway consent messages. 399 It is used to present consent messages to the user. */ 400 401 UINT64 paddingD[64 - 58]; /* 58 */ 402 403 ALIGN64 pSendChannelData 404 SendChannelData; /* (offset 64) 405 Callback for sending data to a channel. 406 By default, it is set by freerdp_new() to freerdp_send_channel_data(), which 407 eventually calls freerdp_channel_send() */ 408 ALIGN64 pReceiveChannelData 409 ReceiveChannelData; /* (offset 65) 410 Callback for receiving data from a channel. 411 This is called by freerdp_channel_process() (if not NULL). 412 Clients will typically use a function that calls freerdp_channels_data() 413 to perform the needed tasks. */ 414 415 ALIGN64 pVerifyCertificateEx 416 VerifyCertificateEx; /**< (offset 66) 417 Callback for certificate validation. 418 Used to verify that an unknown certificate is trusted. */ 419 ALIGN64 pVerifyChangedCertificateEx 420 VerifyChangedCertificateEx; /**< (offset 67) 421 Callback for changed certificate validation. 422 Used when a certificate differs from stored fingerprint. */ 423 UINT64 paddingE[80 - 68]; /* 68 */ 424 }; 425 426 struct rdp_channel_handles 427 { 428 wListDictionary* init; 429 wListDictionary* open; 430 }; 431 typedef struct rdp_channel_handles rdpChannelHandles; 432 433 FREERDP_API BOOL freerdp_context_new(freerdp* instance); 434 FREERDP_API void freerdp_context_free(freerdp* instance); 435 436 FREERDP_API BOOL freerdp_connect(freerdp* instance); 437 FREERDP_API BOOL freerdp_abort_connect(freerdp* instance); 438 FREERDP_API BOOL freerdp_shall_disconnect(freerdp* instance); 439 FREERDP_API BOOL freerdp_disconnect(freerdp* instance); 440 441 FREERDP_API BOOL freerdp_disconnect_before_reconnect(freerdp* instance); 442 FREERDP_API BOOL freerdp_reconnect(freerdp* instance); 443 444 FREERDP_API UINT freerdp_channel_add_init_handle_data(rdpChannelHandles* handles, 445 void* pInitHandle, void* pUserData); 446 FREERDP_API void* freerdp_channel_get_init_handle_data(rdpChannelHandles* handles, 447 void* pInitHandle); 448 FREERDP_API void freerdp_channel_remove_init_handle_data(rdpChannelHandles* handles, 449 void* pInitHandle); 450 451 FREERDP_API UINT freerdp_channel_add_open_handle_data(rdpChannelHandles* handles, 452 DWORD openHandle, void* pUserData); 453 FREERDP_API void* freerdp_channel_get_open_handle_data(rdpChannelHandles* handles, 454 DWORD openHandle); 455 FREERDP_API void freerdp_channel_remove_open_handle_data(rdpChannelHandles* handles, 456 DWORD openHandle); 457 458 FREERDP_API UINT freerdp_channels_attach(freerdp* instance); 459 FREERDP_API UINT freerdp_channels_detach(freerdp* instance); 460 461 FREERDP_API BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, 462 int* wcount); 463 FREERDP_API BOOL freerdp_check_fds(freerdp* instance); 464 465 FREERDP_API DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events, DWORD count); 466 FREERDP_API BOOL freerdp_check_event_handles(rdpContext* context); 467 468 FREERDP_API wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id); 469 FREERDP_API HANDLE freerdp_get_message_queue_event_handle(freerdp* instance, DWORD id); 470 FREERDP_API int freerdp_message_queue_process_message(freerdp* instance, DWORD id, 471 wMessage* message); 472 FREERDP_API int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id); 473 474 FREERDP_API UINT32 freerdp_error_info(freerdp* instance); 475 FREERDP_API void freerdp_set_error_info(rdpRdp* rdp, UINT32 error); 476 FREERDP_API BOOL freerdp_send_error_info(rdpRdp* rdp); 477 FREERDP_API BOOL freerdp_get_stats(rdpRdp* rdp, UINT64* inBytes, UINT64* outBytes, 478 UINT64* inPackets, UINT64* outPackets); 479 480 FREERDP_API void freerdp_get_version(int* major, int* minor, int* revision); 481 FREERDP_API const char* freerdp_get_version_string(void); 482 FREERDP_API const char* freerdp_get_build_date(void); 483 FREERDP_API const char* freerdp_get_build_revision(void); 484 FREERDP_API const char* freerdp_get_build_config(void); 485 486 FREERDP_API freerdp* freerdp_new(void); 487 FREERDP_API void freerdp_free(freerdp* instance); 488 489 FREERDP_API BOOL freerdp_focus_required(freerdp* instance); 490 FREERDP_API void freerdp_set_focus(freerdp* instance); 491 492 FREERDP_API int freerdp_get_disconnect_ultimatum(rdpContext* context); 493 494 FREERDP_API UINT32 freerdp_get_last_error(rdpContext* context); 495 FREERDP_API const char* freerdp_get_last_error_name(UINT32 error); 496 FREERDP_API const char* freerdp_get_last_error_string(UINT32 error); 497 FREERDP_API const char* freerdp_get_last_error_category(UINT32 error); 498 499 FREERDP_API void freerdp_set_last_error(rdpContext* context, UINT32 lastError); 500 501 #define freerdp_set_last_error_if_not(context, lastError) \ 502 do \ 503 { \ 504 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS) \ 505 freerdp_set_last_error_log(context, lastError); \ 506 } while (0) 507 508 #define freerdp_set_last_error_log(context, lastError) \ 509 freerdp_set_last_error_ex((context), (lastError), __FUNCTION__, __FILE__, __LINE__) 510 FREERDP_API void freerdp_set_last_error_ex(rdpContext* context, UINT32 lastError, 511 const char* fkt, const char* file, int line); 512 513 FREERDP_API const char* freerdp_get_logon_error_info_type(UINT32 type); 514 FREERDP_API const char* freerdp_get_logon_error_info_data(UINT32 data); 515 516 FREERDP_API ULONG freerdp_get_transport_sent(rdpContext* context, BOOL resetCount); 517 518 FREERDP_API BOOL freerdp_nla_impersonate(rdpContext* context); 519 FREERDP_API BOOL freerdp_nla_revert_to_self(rdpContext* context); 520 521 FREERDP_API void clearChannelError(rdpContext* context); 522 FREERDP_API HANDLE getChannelErrorEventHandle(rdpContext* context); 523 FREERDP_API UINT getChannelError(rdpContext* context); 524 FREERDP_API const char* getChannelErrorDescription(rdpContext* context); 525 FREERDP_API void setChannelError(rdpContext* context, UINT errorNum, char* description); 526 FREERDP_API BOOL checkChannelErrorEvent(rdpContext* context); 527 528 FREERDP_API const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length); 529 530 #ifdef __cplusplus 531 } 532 #endif 533 534 #endif /* FREERDP_H */ 535