20#include <winpr/assert.h>
21#include <freerdp/config.h>
22#include <freerdp/log.h>
26#include "multitransport.h"
28struct rdp_multitransport
32 MultiTransportRequestCb MtRequest;
33 MultiTransportResponseCb MtResponse;
38 BYTE reliableCookie[RDPUDP_COOKIE_LEN];
39 BYTE reliableCookieHash[RDPUDP_COOKIE_HASHLEN];
44 RDPTUNNEL_ACTION_CREATEREQUEST = 0x00,
45 RDPTUNNEL_ACTION_CREATERESPONSE = 0x01,
46 RDPTUNNEL_ACTION_DATA = 0x02
49#define TAG FREERDP_TAG("core.multitransport")
51state_run_t multitransport_recv_request(rdpMultitransport* multi,
wStream* s)
54 rdpSettings* settings = multi->rdp->settings;
56 if (settings->ServerMode)
58 WLog_ERR(TAG,
"not expecting a multi-transport request in server mode");
59 return STATE_RUN_FAILED;
62 if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
63 return STATE_RUN_FAILED;
66 UINT16 requestedProto = 0;
68 const BYTE* cookie =
nullptr;
70 Stream_Read_UINT32(s, requestId);
71 Stream_Read_UINT16(s, requestedProto);
72 Stream_Read_UINT16(s, reserved);
73 cookie = Stream_ConstPointer(s);
74 Stream_Seek(s, RDPUDP_COOKIE_LEN);
86 "reserved is %" PRIu16
" instead of 0, skipping %" PRIuz
"bytes of unknown data",
87 reserved, Stream_GetRemainingLength(s));
88 (void)Stream_SafeSeek(s, Stream_GetRemainingLength(s));
91 WINPR_ASSERT(multi->MtRequest);
92 return multi->MtRequest(multi, requestId, requestedProto, cookie);
95static BOOL multitransport_request_send(rdpMultitransport* multi, UINT32 reqId, UINT16 reqProto,
100 wStream* s = rdp_message_channel_pdu_init(multi->rdp, &sec_flags);
104 if (!Stream_EnsureRemainingCapacity(s, 24))
110 Stream_Write_UINT32(s, reqId);
111 Stream_Write_UINT16(s, reqProto);
113 Stream_Write(s, cookie, RDPUDP_COOKIE_LEN);
115 return rdp_send_message_channel_pdu(multi->rdp, s, sec_flags | SEC_TRANSPORT_REQ);
118state_run_t multitransport_server_request(rdpMultitransport* multi, UINT16 reqProto)
123 static UINT32 reqId = 0;
125 if (reqProto == INITIATE_REQUEST_PROTOCOL_UDPFECR)
127 multi->reliableReqId = reqId++;
128 if (winpr_RAND(multi->reliableCookie,
sizeof(multi->reliableCookie)) < 0)
129 return STATE_RUN_FAILED;
131 return multitransport_request_send(multi, multi->reliableReqId, reqProto,
132 multi->reliableCookie)
137 WLog_ERR(TAG,
"only reliable transport is supported");
138 return STATE_RUN_CONTINUE;
141BOOL multitransport_client_send_response(rdpMultitransport* multi, UINT32 reqId, HRESULT hr)
145 UINT16 sec_flags = 0;
146 wStream* s = rdp_message_channel_pdu_init(multi->rdp, &sec_flags);
150 if (!Stream_EnsureRemainingCapacity(s, 28))
156 Stream_Write_UINT32(s, reqId);
161 Stream_Write_INT32(s, hr);
162 return rdp_send_message_channel_pdu(multi->rdp, s, sec_flags | SEC_TRANSPORT_RSP);
165state_run_t multitransport_recv_response(rdpMultitransport* multi,
wStream* s)
167 WINPR_ASSERT(multi && multi->rdp);
170 rdpSettings* settings = multi->rdp->settings;
171 WINPR_ASSERT(settings);
173 if (!settings->ServerMode)
175 WLog_ERR(TAG,
"client is not expecting a multi-transport resp packet");
176 return STATE_RUN_FAILED;
179 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
180 return STATE_RUN_FAILED;
182 UINT32 requestId = 0;
185 Stream_Read_UINT32(s, requestId);
186 Stream_Read_UINT32(s, hr);
188 state_run_t res = STATE_RUN_SUCCESS;
189 IFCALLRET(multi->MtResponse, res, multi, requestId, hr);
193static state_run_t multitransport_no_udp(rdpMultitransport* multi, UINT32 reqId,
194 WINPR_ATTR_UNUSED UINT16 reqProto,
195 WINPR_ATTR_UNUSED
const BYTE* cookie)
197 return multitransport_client_send_response(multi, reqId, E_ABORT) ? STATE_RUN_SUCCESS
201static state_run_t multitransport_server_handle_response(rdpMultitransport* multi,
202 WINPR_ATTR_UNUSED UINT32 reqId,
203 WINPR_ATTR_UNUSED UINT32 hrResponse)
205 rdpRdp* rdp = multi->rdp;
207 if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE))
208 return STATE_RUN_FAILED;
210 return STATE_RUN_CONTINUE;
213rdpMultitransport* multitransport_new(rdpRdp* rdp, WINPR_ATTR_UNUSED UINT16 protocol)
217 rdpSettings* settings = rdp->settings;
218 WINPR_ASSERT(settings);
220 rdpMultitransport* multi = calloc(1,
sizeof(rdpMultitransport));
224 if (settings->ServerMode)
226 multi->MtResponse = multitransport_server_handle_response;
230 multi->MtRequest = multitransport_no_udp;
237void multitransport_free(rdpMultitransport* multitransport)
239 free(multitransport);