diff --git a/src/runtime2/component/component_internet.rs b/src/runtime2/component/component_internet.rs index f57eb821a93f58b66d8c991e5add2d4b4bbf1540..4cd9fce6c2e84daa3058cee36774c70eba424b43 100644 --- a/src/runtime2/component/component_internet.rs +++ b/src/runtime2/component/component_internet.rs @@ -299,14 +299,30 @@ impl Component for ComponentTcpClient { impl ComponentTcpClient { pub(crate) fn new(arguments: ValueGroup) -> Self { - debug_assert_eq!(arguments.values.len(), 4); + // Two possible cases here: if the number of arguments is 3, then we + // get: (socket_handle, input_port, output_port). If the number of + // arguments is 4, then we get: (ip, port, input_port, output_port). + assert!(arguments.values.len() == 3 || arguments.values.len() == 4); // Parsing arguments - let (ip_address, port) = ip_addr_and_port_from_args(&arguments, 0, 1); - let input_port = component::port_id_from_eval(arguments.values[2].as_input()); - let output_port = component::port_id_from_eval(arguments.values[3].as_output()); + let (socket, input_port, output_port) = if arguments.values.len() == 3 { + let socket_handle = arguments.values[0].as_sint32(); + let socket = SocketTcpClient::new_from_handle(socket_handle); + + let input_port = component::port_id_from_eval(arguments.values[1].as_input()); + let output_port = component::port_id_from_eval(arguments.values[2].as_output()); + + (socket, input_port, output_port) + } else { + let (ip_address, port) = ip_addr_and_port_from_args(&arguments, 0, 1); + let socket = SocketTcpClient::new(ip_address, port); + + let input_port = component::port_id_from_eval(arguments.values[2].as_input()); + let output_port = component::port_id_from_eval(arguments.values[3].as_output()); + + (socket, input_port, output_port) + }; - let socket = SocketTcpClient::new(ip_address, port); if let Err(socket) = socket { todo!("friendly error reporting: failed to open socket (reason: {:?})", socket); } @@ -416,7 +432,7 @@ impl ListenerSocketState { } struct PendingComponent { - client: SocketTcpClient, + client: i32, // OS socket handle cmd_rx: PortId, data_tx: PortId, } @@ -456,6 +472,9 @@ impl Component for ComponentTcpListener { // Retrieve type information for the message with ports we're going to send let pd = &sched_ctx.runtime.protocol; + self.tcp_client_definition = sched_ctx.runtime.protocol.find_procedure(b"std.internet", b"tcp_client") + .expect("'tcp_client' component in the 'std.internet' module"); + let cmd_type = pd.find_type(b"std.internet", b"ListenerCmd") .expect("'ListenerCmd' type in the 'std.internet' module"); let cmd_type = cmd_type.as_union(); @@ -541,15 +560,19 @@ impl Component for ComponentTcpListener { // Now that we're outside the sync round, create the tcp client // component let pending = self.pending_component.take().unwrap(); - let socket_component: Box = Box::new(ComponentTcpClient::new_with_existing_connection( - pending.client, pending.cmd_rx, pending.data_tx - )); - component::special_create_component( + + let arguments = ValueGroup::new_stack(vec![ + Value::SInt32(pending.client), + Value::Input(port_id_to_eval(pending.cmd_rx)), + Value::Output(port_id_to_eval(pending.data_tx)), + ]); + component::default_start_create_component( &mut self.exec_state, sched_ctx, comp_ctx, &mut self.control, - &mut self.inbox_main, &mut self.inbox_backup, socket_component, - vec![pending.cmd_rx, pending.data_tx] + &mut self.inbox_main, &mut self.inbox_backup, + self.tcp_client_definition.0, self.tcp_client_definition.1, + arguments ); - self.sync_state = ListenerSyncState::AwaitingCmd; // superfluous, see ListenerSyncState.take() + self.sync_state = ListenerSyncState::AwaitingCmd; }, ListenerSyncState::FinishSyncThenQuit => { self.exec_state.set_as_start_exit(ExitReason::Termination); @@ -596,10 +619,9 @@ impl Component for ComponentTcpListener { ListenerSyncState::AcceptCommandReceived => { let socket = self.socket_state.get_socket(); match socket.accept() { - Ok(client) => { + Ok(client_handle) => { // Create the channels (and the inbox entries, to stay consistent // with the expectations from the `component` module's functions) - let client = client.unwrap(); let cmd_channel = comp_ctx.create_channel(); let data_channel = comp_ctx.create_channel(); @@ -635,7 +657,7 @@ impl Component for ComponentTcpListener { self.sync_state = ListenerSyncState::AcceptChannelGenerated; debug_assert!(self.pending_component.is_none()); self.pending_component = Some(PendingComponent{ - client, + client: client_handle, cmd_rx: cmd_channel.getter_id, data_tx: data_channel.putter_id }); @@ -701,6 +723,7 @@ impl ComponentTcpListener { inbox_backup: InboxBackup::new(), pdl_input_port_id: input_port, pdl_output_port_id: output_port, + tcp_client_definition: (ProcedureDefinitionId::new_invalid(), TypeId::new_invalid()), input_union_accept_tag: -1, input_union_shutdown_tag: -1, output_struct_tx_index: 0,