@c -*-texinfo-*- @c This file is part of Guile-SSH Reference Manual. @c Copyright (C) 2014 Artyom V. Poptsov @c See the file guile-ssh.texi for copying conditions. @node Channels @section Channels @menu * Channel Management:: * Port Forwarding:: @end menu @node Channel Management @subsection Channel Management @cindex data transferring @tindex channel The @code{(ssh channel)} module provides facilities to create Guile-SSH channels and manipulating of them. Channels are implemented as GNU Guile ports. Therefore they can be used with regular I/O procedures such as @code{display}, @code{write}, @code{read-line} and friends (@pxref{Input and Output,,, guile, The GNU Guile Reference Manual}). This section describes operations that are specific for the channels. @deffn {Scheme Procedure} channel? x Return @code{#t} if @var{x} is a Guile-SSH channel, @code{#f} otherwise. @end deffn @deffn {Scheme Procedure} make-channel session [mode] Allocate a new Guile-SSH channel for the @var{session} (@pxref{Sessions}). @var{flags} are determine what kind of a channel should be created. Possible modes are: @code{OPEN_READ}, @code{OPEN_WRITE}, @code{OPEN_BOTH}. They allow to create either an input channel, output channel or input/output channel respectively. @end deffn @deffn {Scheme Procedure} channel-open-session channel Open a session channel. This procedure actually turn the @var{channel} into an open port available for I/O operations. Throw @code{guile-ssh-error} on error. Return value is undefined. @end deffn @deffn {Scheme Procedure} channel-request-exec channel command @cindex non-interactive SSH session @cindex command execution Run a shell @var{command} without an interactive shell. The @var{channel} must be open. Throw @code{guile-ssh-error} on error. Return value is undefined. This procedure is a low-level one and you should use remote pipes instead (@pxref{Remote Pipes}). @strong{Note} that the procedure only can be used to execute a single command on the remote host, so you should close the channel after @code{channel-request-exec}. If you want to execute another command then you must open a new channel and use it. Example: @lisp (let ((channel (make-channel session))) (channel-open-session channel) (channel-request-exec channel "uname") (read-line channel)) @result{} "Linux" @end lisp @end deffn @deffn {Scheme Procedure} channel-request-pty channel Request a @acronym{PTY} (pseudo terminal). Throw @code{guile-ssh-error} on error. The @var{channel} must be open. Return value is undefined. @end deffn @deffn {Scheme Procedure} channel-request-shell channel Request a shell. The @var{channel} must be open. Throw @code{guile-ssh-error} on error. Return value is undefined. @end deffn @deffn {Scheme Procedure} channel-request-env channel variable value @cindex setting of environment variables Set an environment @var{variable} to @var{value}. Throw @code{guile-ssh-error} on error. The @var{channel} must be open. Return value is undefined. @end deffn @deffn {Scheme Procedure} channel-request-send-exit-status channel exit-status Send an @var{exit-status} to the remote process (as described in RFC 4254, section 6.10). Only SSH-v2 is supported. Return value is undefined. The @var{channel} needs to be closed with after this message. @end deffn @deffn {Scheme Procedure} channel-set-pty-size! channel columns rows Change size of the @acronym{PTY} to @var{columns} and @var{rows}. The @var{channel} must be open. Return value is undefined. @end deffn @deffn {Scheme Procedure} channel-set-stream! channel stream Set default @var{stream} for @var{channel}. @var{stream} must be one of the following symbols: @code{stdout} (default), @code{stderr}. The @var{channel} must be open. Throw @code{guile-ssh-error} on error. Return value is undefined. Example: @lisp (channel-set-stream! channel 'stderr) @end lisp @end deffn @deffn {Scheme Procedure} channel-get-stream channel Get current stream name from @var{channel}. The @var{channel} must be open. Throw @code{guile-ssh-error} on error. Return one of the following symbols: @code{stdout}, @code{stderr}. Example: @lisp (channel-get-stream channel) @result{} 'stderr @end lisp @end deffn @deffn {Scheme Procedure} channel-get-session channel Get the session to which belongs the @var{channel}. Throw @code{guile-ssh-error} on an error. Return the session. @end deffn @deffn {Scheme Procedure} channel-send-eof channel Send an end of file (EOF) on the @var{channel}. This action doesn't close the @var{channel}; you may still read from it but not write. Throw @code{guile-ssh-error} on an error. Return value is undefined. Example: @lisp (use-modules (ice-9 rdelim) ;; Guile-SSH modules. (ssh auth) (ssh popen) (ssh session) (ssh channel)) ;; Make a session (define s (make-session #:host "example.org")) ;; Connect to the server (connect! s) ;; Authenticate (userauth-agent! s) ;; Open a remote pipe to 'wc' command running on ;; the server. (let ((p (open-remote-pipe s "wc" OPEN_BOTH))) ;; Send data to 'wc' command using the remote pipe. (display "Hello Scheme World!" p) ;; 'wc' reads data until EOF and writes its result ;; afterwards. (channel-send-eof p) ;; Read the 'wc' output. (read-line p)) @result{} " 0 3 19" @end lisp @end deffn @deffn {Scheme Procedure} channel-eof? channel Return @code{#t} if remote has sent @acronym{EOF}, @code{#f} otherwise. Throw @code{guile-ssh-error} if the channel has been closed and freed. @end deffn @deffn {Scheme Procedure} channel-get-exit-status channel Get the exit status of the @var{channel} (error code from the executed instruction). The @var{channel} must be open. Return the exist status, or @code{#f} if no exit status has been returned (yet). Throw @code{guile-ssh-error} on error. @end deffn @node Port Forwarding @subsection Port Forwarding @cindex Port forwarding Low-level API from @code{(ssh channel)} module to manage SSH port forwarding. These procedures @strong{do not} bind the ports and do not automatically forward the content of a socket to the channel. You should either implement binding and data forwarding in your application or use the tunnel API (@pxref{Tunnels, Guile-SSH tunnel API}) @deffn {Scheme Procedure} channel-open-forward channel [#:source-host=''localhost''] #:local-port #:remote-host [#:remote-port=local-port] Open a (local) TCP/IP forwarding @var{channel}. Connect to a @var{remote-host} and @var{remote-port}, and use @var{source-host} and @var{local-port} as origination of connections. The procedure returns one of the following symbols: @table @samp @item ok Success. @item again We are in the nonblocking mode and the call to be done again. @item error An error occured. @end table The local port forwarding works as follows: @example local-host remote-host ,..............., ,................. : : : : : [a browser] : : [a web server] : : | : : A : : | : : | : : port 8080 : : port 80 : : | : : | : : V : : | : : [SSH client]===========>[SSH server] : : : : : '...............' '................' @end example Where port 8080 is an arbitrary @var{local-port} and port 80 is a @var{remote-port}. Also in our case, ``SSH client'' is an application that uses Guile-SSH and calls @code{channel-open-forward}. Example: @lisp (channel-open-forward channel #:local-port 8080 #:remote-host "www.example.org" #:remote-port 80) @end lisp @end deffn @deffn {Scheme Procedure} channel-listen-forward session [#:address=#f] [#:port=0] Start a TCP/IP reverse (remote) port forwarding. Send the ``tcpip-forward'' global request using @var{session} to ask the server to begin listening for inbound connections on the specified @var{address} and @var{port}. If @var{address} is not specified (or set to @code{#f}) then the server binds all addresses on all protocol families supported by the server. When 0 is passed as a @var{port} then server allocates the next unprivileged port. The procedure returns two values: the first value is the result of the operation, and the second value is the bound port number; if @var{port} was set to 0 then the procedure returns the chosen port number. The result of the operation can be one of the following symbols: @table @samp @item ok Success. @item again We are in the nonblocking mode and the call to be done again. @item error An error occured. @end table Reverse port forwarding looks as follows: @example local-host remote-host ,................, ,................. : : : : : [a web server] : : [a browser] : : A : : | : : | : : | : : port 80 : : port 8080 : : | : : | : : | : : V : : [SSH client]<===========[SSH server] : : : : : '................' '................' @end example @end deffn @deffn {Scheme Procedure} channel-accept-forward session [timeout=0] Accept an incoming TCP/IP forwarding channel and get information about incoming connection. Return two values: the first value is the incoming channel, and the second value is a port number on which the connection was issued. @end deffn @deffn {Scheme Procedure} channel-cancel-forward session address port Send ``cancel-tcpip-forward'' global request to @var{session} to ask the server to cancel a ``tcpip-forward'' request on the bound @var{address} and @var{port}. The result of the operation can be one of the following symbols: @table @samp @item ok Success. @item again We are in the nonblocking mode and the call to be done again. @item error An error occured. @end table Here's an example Guile program that uses @code{channel-cancel-forward} to cancel reverse port forwarding on a server: @lisp #!/usr/bin/guile \ -e main !# (use-modules (ssh session) (ssh auth) (ssh channel)) (define (main args) (let ((session (make-session #:user "alice" #:host "127.0.0.1" #:port 22 #:log-verbosity 'rare))) (connect! session) (userauth-agent! session) ;; Send "tcpip-forward" request to an SSH server (channel-listen-forward session #:address "localhost" #:port 12345) ;; Accept incoming reverse port forwarding requests with ;; 'channel-accept-forward' in some kind of loop... ;; Cancel the issued "tcpip-forward" request with ;; "cancel-tcpip-forward" request (channel-cancel-forward session "localhost" 12345))) @end lisp @end deffn @c Local Variables: @c TeX-master: "guile-ssh.texi" @c End: