SocketServerAccept,
#[strum_discriminants(strum(props(Arity = "1", Name = "$socket_server_close")))]
SocketServerClose,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$copy_stream")))]
+ CopyStream,
#[strum_discriminants(strum(props(Arity = "4", Name = "$tls_accept_client")))]
TLSAcceptClient,
#[strum_discriminants(strum(props(Arity = "3", Name = "$tls_client_connect")))]
| &Instruction::CallSocketServerOpen
| &Instruction::CallSocketServerAccept
| &Instruction::CallSocketServerClose
+ | &Instruction::CallCopyStream
| &Instruction::CallTLSAcceptClient
| &Instruction::CallTLSClientConnect
| &Instruction::CallSucceed
| &Instruction::ExecuteSocketServerOpen
| &Instruction::ExecuteSocketServerAccept
| &Instruction::ExecuteSocketServerClose
+ | &Instruction::ExecuteCopyStream
| &Instruction::ExecuteTLSAcceptClient
| &Instruction::ExecuteTLSClientConnect
| &Instruction::ExecuteSucceed
socket_server_open/2,
socket_server_accept/4,
socket_server_close/1,
+ copy_stream/2,
current_hostname/1]).
:- use_module(library(error)).
% Returns the current hostname of the computer in which Scryer Prolog is executing right now
current_hostname(HostName) :-
'$current_hostname'(HostName).
+
+%% copy_stream(+InputStream, +OutputStream).
+%
+% Copies all remaining bytes from InputStream to OutputStream in a single
+% native call, without materialising the contents on the Prolog heap.
+% Intended for streaming binary content (e.g. file -> TLS socket).
+copy_stream(In, Out) :-
+ '$copy_stream'(In, Out).
try_or_throw!(self.machine_st, self.socket_server_close(), continue);
self.machine_st.p = self.machine_st.cp;
}
+ &Instruction::CallCopyStream => {
+ try_or_throw!(self.machine_st, self.copy_stream(), continue);
+ step_or_fail!(self.machine_st, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCopyStream => {
+ try_or_throw!(self.machine_st, self.copy_stream(), continue);
+ step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
+ }
&Instruction::CallTLSAcceptClient => {
#[cfg(feature = "tls")]
try_or_throw!(self.machine_st, self.tls_accept_client(), continue);
Ok(())
}
+ #[inline(always)]
+ pub(crate) fn copy_stream(&mut self) -> CallResult {
+ let mut input = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices,
+ atom!("$copy_stream"),
+ 2,
+ )?;
+ let mut output = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[2],
+ &self.indices,
+ atom!("$copy_stream"),
+ 2,
+ )?;
+
+ let stub_gen = || functor_stub(atom!("$copy_stream"), 2);
+ let mut buf = [0u8; 65536];
+
+ loop {
+ let n = match input.read(&mut buf) {
+ Ok(0) => break,
+ Ok(n) => n,
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(_) => {
+ let err = self
+ .machine_st
+ .existence_error(ExistenceError::Stream(input.into()));
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ };
+ if output.write_all(&buf[..n]).is_err() {
+ let err = self
+ .machine_st
+ .existence_error(ExistenceError::Stream(output.into()));
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ }
+
+ Ok(())
+ }
+
#[inline(always)]
pub(crate) fn socket_server_close(&mut self) -> CallResult {
let culprit = self.deref_register(1);