1use core::mem;
2
3use ironrdp_connector::{
4 encode_x224_packet, general_err, reason_err, ConnectorError, ConnectorErrorExt as _, ConnectorResult, DesktopSize,
5 Sequence, State, Written,
6};
7use ironrdp_core::{decode, WriteBuf};
8use ironrdp_pdu as pdu;
9use ironrdp_pdu::nego::SecurityProtocol;
10use ironrdp_pdu::x224::X224;
11use ironrdp_svc::{StaticChannelSet, SvcServerProcessor};
12use pdu::rdp::capability_sets::CapabilitySet;
13use pdu::rdp::client_info::Credentials;
14use pdu::rdp::headers::ShareControlPdu;
15use pdu::rdp::server_error_info::{ErrorInfo, ProtocolIndependentCode, ServerSetErrorInfoPdu};
16use pdu::rdp::server_license::{LicensePdu, LicensingErrorMessage};
17use pdu::{gcc, mcs, nego, rdp};
18use tracing::{debug, warn};
19
20use super::channel_connection::ChannelConnectionSequence;
21use super::finalization::FinalizationSequence;
22use crate::util::{self, wrap_share_data};
23
24const IO_CHANNEL_ID: u16 = 1003;
25const USER_CHANNEL_ID: u16 = 1002;
26
27pub struct Acceptor {
28 pub(crate) state: AcceptorState,
29 security: SecurityProtocol,
30 io_channel_id: u16,
31 user_channel_id: u16,
32 desktop_size: DesktopSize,
33 server_capabilities: Vec<CapabilitySet>,
34 static_channels: StaticChannelSet,
35 saved_for_reactivation: AcceptorState,
36 pub(crate) creds: Option<Credentials>,
37 reactivation: bool,
38}
39
40#[derive(Debug)]
41pub struct AcceptorResult {
42 pub static_channels: StaticChannelSet,
43 pub capabilities: Vec<CapabilitySet>,
44 pub input_events: Vec<Vec<u8>>,
45 pub user_channel_id: u16,
46 pub io_channel_id: u16,
47 pub reactivation: bool,
48}
49
50impl Acceptor {
51 pub fn new(
52 security: SecurityProtocol,
53 desktop_size: DesktopSize,
54 capabilities: Vec<CapabilitySet>,
55 creds: Option<Credentials>,
56 ) -> Self {
57 Self {
58 security,
59 state: AcceptorState::InitiationWaitRequest,
60 user_channel_id: USER_CHANNEL_ID,
61 io_channel_id: IO_CHANNEL_ID,
62 desktop_size,
63 server_capabilities: capabilities,
64 static_channels: StaticChannelSet::new(),
65 saved_for_reactivation: Default::default(),
66 creds,
67 reactivation: false,
68 }
69 }
70
71 pub fn new_deactivation_reactivation(
72 mut consumed: Acceptor,
73 static_channels: StaticChannelSet,
74 desktop_size: DesktopSize,
75 ) -> ConnectorResult<Self> {
76 let AcceptorState::CapabilitiesSendServer {
77 early_capability,
78 channels,
79 } = consumed.saved_for_reactivation
80 else {
81 return Err(general_err!("invalid acceptor state"));
82 };
83
84 for cap in consumed.server_capabilities.iter_mut() {
85 if let CapabilitySet::Bitmap(cap) = cap {
86 cap.desktop_width = desktop_size.width;
87 cap.desktop_height = desktop_size.height;
88 }
89 }
90 let state = AcceptorState::CapabilitiesSendServer {
91 early_capability,
92 channels: channels.clone(),
93 };
94 let saved_for_reactivation = AcceptorState::CapabilitiesSendServer {
95 early_capability,
96 channels,
97 };
98 Ok(Self {
99 security: consumed.security,
100 state,
101 user_channel_id: consumed.user_channel_id,
102 io_channel_id: consumed.io_channel_id,
103 desktop_size,
104 server_capabilities: consumed.server_capabilities,
105 static_channels,
106 saved_for_reactivation,
107 creds: consumed.creds,
108 reactivation: true,
109 })
110 }
111
112 pub fn attach_static_channel<T>(&mut self, channel: T)
113 where
114 T: SvcServerProcessor + 'static,
115 {
116 self.static_channels.insert(channel);
117 }
118
119 pub fn reached_security_upgrade(&self) -> Option<SecurityProtocol> {
120 match self.state {
121 AcceptorState::SecurityUpgrade { .. } => Some(self.security),
122 _ => None,
123 }
124 }
125
126 pub fn mark_security_upgrade_as_done(&mut self) {
127 assert!(self.reached_security_upgrade().is_some());
128 self.step(&[], &mut WriteBuf::new()).expect("transition to next state");
129 debug_assert!(self.reached_security_upgrade().is_none());
130 }
131
132 pub fn should_perform_credssp(&self) -> bool {
133 matches!(self.state, AcceptorState::Credssp { .. })
134 }
135
136 pub fn mark_credssp_as_done(&mut self) {
137 assert!(self.should_perform_credssp());
138 let res = self.step(&[], &mut WriteBuf::new()).expect("transition to next state");
139 debug_assert!(!self.should_perform_credssp());
140 assert_eq!(res, Written::Nothing);
141 }
142
143 pub fn get_result(&mut self) -> Option<AcceptorResult> {
144 match mem::take(&mut self.state) {
145 AcceptorState::Accepted {
146 channels: _channels, client_capabilities,
148 input_events,
149 } => Some(AcceptorResult {
150 static_channels: mem::take(&mut self.static_channels),
151 capabilities: client_capabilities,
152 input_events,
153 user_channel_id: self.user_channel_id,
154 io_channel_id: self.io_channel_id,
155 reactivation: self.reactivation,
156 }),
157 previous_state => {
158 self.state = previous_state;
159 None
160 }
161 }
162 }
163}
164
165#[derive(Default, Debug)]
166pub enum AcceptorState {
167 #[default]
168 Consumed,
169
170 InitiationWaitRequest,
171 InitiationSendConfirm {
172 requested_protocol: SecurityProtocol,
173 },
174 SecurityUpgrade {
175 requested_protocol: SecurityProtocol,
176 protocol: SecurityProtocol,
177 },
178 Credssp {
179 requested_protocol: SecurityProtocol,
180 protocol: SecurityProtocol,
181 },
182 BasicSettingsWaitInitial {
183 requested_protocol: SecurityProtocol,
184 protocol: SecurityProtocol,
185 },
186 BasicSettingsSendResponse {
187 requested_protocol: SecurityProtocol,
188 protocol: SecurityProtocol,
189 early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
190 channels: Vec<(u16, Option<gcc::ChannelDef>)>,
191 },
192 ChannelConnection {
193 protocol: SecurityProtocol,
194 early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
195 channels: Vec<(u16, gcc::ChannelDef)>,
196 connection: ChannelConnectionSequence,
197 },
198 RdpSecurityCommencement {
199 protocol: SecurityProtocol,
200 early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
201 channels: Vec<(u16, gcc::ChannelDef)>,
202 },
203 SecureSettingsExchange {
204 protocol: SecurityProtocol,
205 early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
206 channels: Vec<(u16, gcc::ChannelDef)>,
207 },
208 LicensingExchange {
209 early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
210 channels: Vec<(u16, gcc::ChannelDef)>,
211 },
212 CapabilitiesSendServer {
213 early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
214 channels: Vec<(u16, gcc::ChannelDef)>,
215 },
216 MonitorLayoutSend {
217 channels: Vec<(u16, gcc::ChannelDef)>,
218 },
219 CapabilitiesWaitConfirm {
220 channels: Vec<(u16, gcc::ChannelDef)>,
221 },
222 ConnectionFinalization {
223 finalization: FinalizationSequence,
224 channels: Vec<(u16, gcc::ChannelDef)>,
225 client_capabilities: Vec<CapabilitySet>,
226 },
227 Accepted {
228 channels: Vec<(u16, gcc::ChannelDef)>,
229 client_capabilities: Vec<CapabilitySet>,
230 input_events: Vec<Vec<u8>>,
231 },
232}
233
234impl State for AcceptorState {
235 fn name(&self) -> &'static str {
236 match self {
237 Self::Consumed => "Consumed",
238 Self::InitiationWaitRequest => "InitiationWaitRequest",
239 Self::InitiationSendConfirm { .. } => "InitiationSendConfirm",
240 Self::SecurityUpgrade { .. } => "SecurityUpgrade",
241 Self::Credssp { .. } => "Credssp",
242 Self::BasicSettingsWaitInitial { .. } => "BasicSettingsWaitInitial",
243 Self::BasicSettingsSendResponse { .. } => "BasicSettingsSendResponse",
244 Self::ChannelConnection { .. } => "ChannelConnection",
245 Self::RdpSecurityCommencement { .. } => "RdpSecurityCommencement",
246 Self::SecureSettingsExchange { .. } => "SecureSettingsExchange",
247 Self::LicensingExchange { .. } => "LicensingExchange",
248 Self::CapabilitiesSendServer { .. } => "CapabilitiesSendServer",
249 Self::MonitorLayoutSend { .. } => "MonitorLayoutSend",
250 Self::CapabilitiesWaitConfirm { .. } => "CapabilitiesWaitConfirm",
251 Self::ConnectionFinalization { .. } => "ConnectionFinalization",
252 Self::Accepted { .. } => "Connected",
253 }
254 }
255
256 fn is_terminal(&self) -> bool {
257 matches!(self, Self::Accepted { .. })
258 }
259
260 fn as_any(&self) -> &dyn core::any::Any {
261 self
262 }
263}
264
265impl Sequence for Acceptor {
266 fn next_pdu_hint(&self) -> Option<&dyn pdu::PduHint> {
267 match &self.state {
268 AcceptorState::Consumed => None,
269 AcceptorState::InitiationWaitRequest => Some(&pdu::X224_HINT),
270 AcceptorState::InitiationSendConfirm { .. } => None,
271 AcceptorState::SecurityUpgrade { .. } => None,
272 AcceptorState::Credssp { .. } => None,
273 AcceptorState::BasicSettingsWaitInitial { .. } => Some(&pdu::X224_HINT),
274 AcceptorState::BasicSettingsSendResponse { .. } => None,
275 AcceptorState::ChannelConnection { connection, .. } => connection.next_pdu_hint(),
276 AcceptorState::RdpSecurityCommencement { .. } => None,
277 AcceptorState::SecureSettingsExchange { .. } => Some(&pdu::X224_HINT),
278 AcceptorState::LicensingExchange { .. } => None,
279 AcceptorState::CapabilitiesSendServer { .. } => None,
280 AcceptorState::MonitorLayoutSend { .. } => None,
281 AcceptorState::CapabilitiesWaitConfirm { .. } => Some(&pdu::X224_HINT),
282 AcceptorState::ConnectionFinalization { finalization, .. } => finalization.next_pdu_hint(),
283 AcceptorState::Accepted { .. } => None,
284 }
285 }
286
287 fn state(&self) -> &dyn State {
288 &self.state
289 }
290
291 fn step(&mut self, input: &[u8], output: &mut WriteBuf) -> ConnectorResult<Written> {
292 let prev_state = mem::take(&mut self.state);
293
294 let (written, next_state) = match prev_state {
295 AcceptorState::InitiationWaitRequest => {
296 let connection_request = decode::<X224<nego::ConnectionRequest>>(input)
297 .map_err(ConnectorError::decode)
298 .map(|p| p.0)?;
299
300 debug!(message = ?connection_request, "Received");
301
302 (
303 Written::Nothing,
304 AcceptorState::InitiationSendConfirm {
305 requested_protocol: connection_request.protocol,
306 },
307 )
308 }
309
310 AcceptorState::InitiationSendConfirm { requested_protocol } => {
311 let protocols = requested_protocol & self.security;
312 let protocol = if protocols.intersects(SecurityProtocol::HYBRID_EX) {
313 SecurityProtocol::HYBRID_EX
314 } else if protocols.intersects(SecurityProtocol::HYBRID) {
315 SecurityProtocol::HYBRID
316 } else if protocols.intersects(SecurityProtocol::SSL) {
317 SecurityProtocol::SSL
318 } else if self.security.is_empty() {
319 SecurityProtocol::empty()
320 } else {
321 return Err(ConnectorError::general("failed to negotiate security protocol"));
322 };
323 let connection_confirm = nego::ConnectionConfirm::Response {
324 flags: nego::ResponseFlags::empty(),
325 protocol,
326 };
327
328 debug!(message = ?connection_confirm, "Send");
329
330 let written =
331 ironrdp_core::encode_buf(&X224(connection_confirm), output).map_err(ConnectorError::encode)?;
332
333 (
334 Written::from_size(written)?,
335 AcceptorState::SecurityUpgrade {
336 requested_protocol,
337 protocol,
338 },
339 )
340 }
341
342 AcceptorState::SecurityUpgrade {
343 requested_protocol,
344 protocol,
345 } => {
346 debug!(?requested_protocol);
347 let next_state = if protocol.intersects(SecurityProtocol::HYBRID | SecurityProtocol::HYBRID_EX) {
348 AcceptorState::Credssp {
349 requested_protocol,
350 protocol,
351 }
352 } else {
353 AcceptorState::BasicSettingsWaitInitial {
354 requested_protocol,
355 protocol,
356 }
357 };
358 (Written::Nothing, next_state)
359 }
360
361 AcceptorState::Credssp {
362 requested_protocol,
363 protocol,
364 } => (
365 Written::Nothing,
366 AcceptorState::BasicSettingsWaitInitial {
367 requested_protocol,
368 protocol,
369 },
370 ),
371
372 AcceptorState::BasicSettingsWaitInitial {
373 requested_protocol,
374 protocol,
375 } => {
376 let x224_payload = decode::<X224<pdu::x224::X224Data<'_>>>(input)
377 .map_err(ConnectorError::decode)
378 .map(|p| p.0)?;
379 let settings_initial =
380 decode::<mcs::ConnectInitial>(x224_payload.data.as_ref()).map_err(ConnectorError::decode)?;
381
382 debug!(message = ?settings_initial, "Received");
383
384 let early_capability = settings_initial
385 .conference_create_request
386 .gcc_blocks
387 .core
388 .optional_data
389 .early_capability_flags;
390
391 let joined: Vec<_> = settings_initial
392 .conference_create_request
393 .gcc_blocks
394 .network
395 .map(|network| {
396 network
397 .channels
398 .into_iter()
399 .map(|c| {
400 self.static_channels
401 .get_by_channel_name(&c.name)
402 .map(|(type_id, _)| (type_id, c))
403 })
404 .collect()
405 })
406 .unwrap_or_default();
407
408 #[expect(clippy::arithmetic_side_effects)] let channels = joined
410 .into_iter()
411 .enumerate()
412 .map(|(i, channel)| {
413 let channel_id = u16::try_from(i).unwrap() + self.io_channel_id + 1;
414 if let Some((type_id, c)) = channel {
415 self.static_channels.attach_channel_id(type_id, channel_id);
416 (channel_id, Some(c))
417 } else {
418 (channel_id, None)
419 }
420 })
421 .collect();
422
423 (
424 Written::Nothing,
425 AcceptorState::BasicSettingsSendResponse {
426 requested_protocol,
427 protocol,
428 early_capability,
429 channels,
430 },
431 )
432 }
433
434 AcceptorState::BasicSettingsSendResponse {
435 requested_protocol,
436 protocol,
437 early_capability,
438 channels,
439 } => {
440 let channel_ids: Vec<u16> = channels.iter().map(|&(i, _)| i).collect();
441
442 let skip_channel_join = early_capability
443 .is_some_and(|client| client.contains(gcc::ClientEarlyCapabilityFlags::SUPPORT_SKIP_CHANNELJOIN));
444
445 let server_blocks = create_gcc_blocks(
446 self.io_channel_id,
447 channel_ids.clone(),
448 requested_protocol,
449 skip_channel_join,
450 );
451
452 let settings_response = mcs::ConnectResponse {
453 conference_create_response: gcc::ConferenceCreateResponse {
454 user_id: self.user_channel_id,
455 gcc_blocks: server_blocks,
456 },
457 called_connect_id: 1,
458 domain_parameters: mcs::DomainParameters::target(),
459 };
460
461 debug!(message = ?settings_response, "Send");
462
463 let written = encode_x224_packet(&settings_response, output)?;
464 let channels = channels.into_iter().filter_map(|(i, c)| c.map(|c| (i, c))).collect();
465
466 (
467 Written::from_size(written)?,
468 AcceptorState::ChannelConnection {
469 protocol,
470 early_capability,
471 channels,
472 connection: if skip_channel_join {
473 ChannelConnectionSequence::skip_channel_join(self.user_channel_id)
474 } else {
475 ChannelConnectionSequence::new(self.user_channel_id, self.io_channel_id, channel_ids)
476 },
477 },
478 )
479 }
480
481 AcceptorState::ChannelConnection {
482 protocol,
483 early_capability,
484 channels,
485 mut connection,
486 } => {
487 let written = connection.step(input, output)?;
488 let state = if connection.is_done() {
489 AcceptorState::RdpSecurityCommencement {
490 protocol,
491 early_capability,
492 channels,
493 }
494 } else {
495 AcceptorState::ChannelConnection {
496 protocol,
497 early_capability,
498 channels,
499 connection,
500 }
501 };
502
503 (written, state)
504 }
505
506 AcceptorState::RdpSecurityCommencement {
507 protocol,
508 early_capability,
509 channels,
510 ..
511 } => (
512 Written::Nothing,
513 AcceptorState::SecureSettingsExchange {
514 protocol,
515 early_capability,
516 channels,
517 },
518 ),
519
520 AcceptorState::SecureSettingsExchange {
521 protocol,
522 early_capability,
523 channels,
524 } => {
525 let data: X224<mcs::SendDataRequest<'_>> = decode(input).map_err(ConnectorError::decode)?;
526 let data = data.0;
527 let client_info: rdp::ClientInfoPdu =
528 decode(data.user_data.as_ref()).map_err(ConnectorError::decode)?;
529
530 debug!(message = ?client_info, "Received");
531
532 if !protocol.intersects(SecurityProtocol::HYBRID | SecurityProtocol::HYBRID_EX) {
533 let creds = client_info.client_info.credentials;
534
535 if self.creds.as_ref() != Some(&creds) {
536 let info = ServerSetErrorInfoPdu(ErrorInfo::ProtocolIndependentCode(
539 ProtocolIndependentCode::ServerDeniedConnection,
540 ));
541
542 debug!(message = ?info, "Send");
543
544 util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &info, output)?;
545
546 return Err(ConnectorError::general("invalid credentials"));
547 }
548 }
549
550 (
551 Written::Nothing,
552 AcceptorState::LicensingExchange {
553 early_capability,
554 channels,
555 },
556 )
557 }
558
559 AcceptorState::LicensingExchange {
560 early_capability,
561 channels,
562 } => {
563 let license: LicensePdu = LicensingErrorMessage::new_valid_client()
564 .map_err(ConnectorError::encode)?
565 .into();
566
567 debug!(message = ?license, "Send");
568
569 let written =
570 util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &license, output)?;
571
572 self.saved_for_reactivation = AcceptorState::CapabilitiesSendServer {
573 early_capability,
574 channels: channels.clone(),
575 };
576
577 (
578 Written::from_size(written)?,
579 AcceptorState::CapabilitiesSendServer {
580 early_capability,
581 channels,
582 },
583 )
584 }
585
586 AcceptorState::CapabilitiesSendServer {
587 early_capability,
588 channels,
589 } => {
590 let demand_active = rdp::headers::ShareControlHeader {
591 share_id: 0,
592 pdu_source: self.io_channel_id,
593 share_control_pdu: ShareControlPdu::ServerDemandActive(rdp::capability_sets::ServerDemandActive {
594 pdu: rdp::capability_sets::DemandActive {
595 source_descriptor: "".into(),
596 capability_sets: self.server_capabilities.clone(),
597 },
598 }),
599 };
600
601 debug!(message = ?demand_active, "Send");
602
603 let written = util::encode_send_data_indication(
604 self.user_channel_id,
605 self.io_channel_id,
606 &demand_active,
607 output,
608 )?;
609
610 let layout_flag = gcc::ClientEarlyCapabilityFlags::SUPPORT_MONITOR_LAYOUT_PDU;
611 let next_state = if early_capability.is_some_and(|c| c.contains(layout_flag)) {
612 AcceptorState::MonitorLayoutSend { channels }
613 } else {
614 AcceptorState::CapabilitiesWaitConfirm { channels }
615 };
616
617 (Written::from_size(written)?, next_state)
618 }
619
620 AcceptorState::MonitorLayoutSend { channels } => {
621 let monitor_layout =
622 rdp::headers::ShareDataPdu::MonitorLayout(rdp::finalization_messages::MonitorLayoutPdu {
623 monitors: vec![gcc::Monitor {
624 left: 0,
625 top: 0,
626 right: i32::from(self.desktop_size.width),
627 bottom: i32::from(self.desktop_size.height),
628 flags: gcc::MonitorFlags::PRIMARY,
629 }],
630 });
631
632 debug!(message = ?monitor_layout, "Send");
633
634 let share_data = wrap_share_data(monitor_layout, self.io_channel_id);
635
636 let written =
637 util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &share_data, output)?;
638
639 (
640 Written::from_size(written)?,
641 AcceptorState::CapabilitiesWaitConfirm { channels },
642 )
643 }
644
645 AcceptorState::CapabilitiesWaitConfirm { ref channels } => {
646 let message = decode::<X224<mcs::McsMessage<'_>>>(input)
647 .map_err(ConnectorError::decode)
648 .map(|p| p.0);
649 let message = match message {
650 Ok(msg) => msg,
651 Err(e) => {
652 if self.reactivation {
653 debug!("Dropping unexpected PDU during reactivation");
654 self.state = prev_state;
655 return Ok(Written::Nothing);
656 } else {
657 return Err(e);
658 }
659 }
660 };
661 match message {
662 mcs::McsMessage::SendDataRequest(data) => {
663 let capabilities_confirm = decode::<rdp::headers::ShareControlHeader>(data.user_data.as_ref())
664 .map_err(ConnectorError::decode);
665 let capabilities_confirm = match capabilities_confirm {
666 Ok(capabilities_confirm) => capabilities_confirm,
667 Err(e) => {
668 if self.reactivation {
669 debug!("Dropping unexpected PDU during reactivation");
670 self.state = prev_state;
671 return Ok(Written::Nothing);
672 } else {
673 return Err(e);
674 }
675 }
676 };
677
678 debug!(message = ?capabilities_confirm, "Received");
679
680 let ShareControlPdu::ClientConfirmActive(confirm) = capabilities_confirm.share_control_pdu
681 else {
682 return Err(ConnectorError::general("expected client confirm active"));
683 };
684
685 (
686 Written::Nothing,
687 AcceptorState::ConnectionFinalization {
688 channels: channels.clone(),
689 finalization: FinalizationSequence::new(self.user_channel_id, self.io_channel_id),
690 client_capabilities: confirm.pdu.capability_sets,
691 },
692 )
693 }
694
695 mcs::McsMessage::DisconnectProviderUltimatum(ultimatum) => {
696 return Err(reason_err!("received disconnect ultimatum", "{:?}", ultimatum.reason))
697 }
698
699 _ => {
700 warn!(?message, "Unexpected MCS message received");
701
702 (Written::Nothing, prev_state)
703 }
704 }
705 }
706
707 AcceptorState::ConnectionFinalization {
708 mut finalization,
709 channels,
710 client_capabilities,
711 } => {
712 let written = finalization.step(input, output)?;
713
714 let state = if finalization.is_done() {
715 AcceptorState::Accepted {
716 channels,
717 client_capabilities,
718 input_events: finalization.input_events,
719 }
720 } else {
721 AcceptorState::ConnectionFinalization {
722 finalization,
723 channels,
724 client_capabilities,
725 }
726 };
727
728 (written, state)
729 }
730
731 _ => unreachable!(),
732 };
733
734 self.state = next_state;
735 Ok(written)
736 }
737}
738
739fn create_gcc_blocks(
740 io_channel: u16,
741 channel_ids: Vec<u16>,
742 requested: SecurityProtocol,
743 skip_channel_join: bool,
744) -> gcc::ServerGccBlocks {
745 gcc::ServerGccBlocks {
746 core: gcc::ServerCoreData {
747 version: gcc::RdpVersion::V5_PLUS,
748 optional_data: gcc::ServerCoreOptionalData {
749 client_requested_protocols: Some(requested),
750 early_capability_flags: skip_channel_join
751 .then_some(gcc::ServerEarlyCapabilityFlags::SKIP_CHANNELJOIN_SUPPORTED),
752 },
753 },
754 security: gcc::ServerSecurityData::no_security(),
755 network: gcc::ServerNetworkData {
756 channel_ids,
757 io_channel,
758 },
759 message_channel: None,
760 multi_transport_channel: None,
761 }
762}