summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtyom Poptsov <poptsov.artyom@gmail.com>2014-01-02 23:14:41 +0400
committerArtyom Poptsov <poptsov.artyom@gmail.com>2014-01-02 23:14:41 +0400
commite0171febf8cb240a8defdabeeed51dcd6ac2eefe (patch)
tree8df32d2d3ec00d57d1fb9ea3f8ae2470b2b0105f
parentconfigure.ac, NEWS: Bump version to 0.4.0 (diff)
downloadguile-ssh-e0171febf8cb240a8defdabeeed51dcd6ac2eefe.tar.gz
Use Guile port API to implement Guile-SSH channels.
* src/channel-func.c (guile_ssh_channel_read) (guile_ssh_channel_write): Remove. * src/channel-func.h (guile_ssh_channel_read): Remove. * src/channel-type.c (ptob_fill_input, ptob_write, ptob_flush) (ptob_input_waiting, _ssh_channel_to_scm): New procedures. (guile_ssh_make_channel): Use `_ssh_channel_to_scm'. (_scm_to_ssh_channel): Use `SCM_STREAM' macro. (init_channel_type): Register Guile port callbacks. * src/channel-type.h (_ssh_channel_to_scm): Export. * src/channel.scm (channel-read, channel-write): Remove. * src/message-func.c (guile_ssh_message_channel_request_open_reply_accept): Use `_ssh_channel_to_scm'. * examples/echo: Add to the repository. * examples/Makefile.am: Add echo server/client example. * examples/README: Update. * examples/sssh.scm: Update. * README: Update.
-rw-r--r--ChangeLog22
-rw-r--r--README8
-rw-r--r--examples/Makefile.am4
-rw-r--r--examples/README18
-rwxr-xr-xexamples/echo/client.scm144
-rwxr-xr-xexamples/echo/server.scm145
-rwxr-xr-xexamples/sssh.scm11
-rw-r--r--src/channel-func.c68
-rw-r--r--src/channel-func.h3
-rw-r--r--src/channel-type.c136
-rw-r--r--src/channel-type.h6
-rw-r--r--src/channel.scm4
-rw-r--r--src/message-func.c17
13 files changed, 460 insertions, 126 deletions
diff --git a/ChangeLog b/ChangeLog
index de7b504..f604a65 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2014-01-02 Artyom Poptsov <poptsov.artyom@gmail.com>
+
+ Use Guile port API to implement Guile-SSH channels.
+ * src/channel-func.c (guile_ssh_channel_read)
+ (guile_ssh_channel_write): Remove.
+ * src/channel-func.h (guile_ssh_channel_read): Remove.
+ * src/channel-type.c (ptob_fill_input, ptob_write, ptob_flush)
+ (ptob_input_waiting, _ssh_channel_to_scm): New procedures.
+ (guile_ssh_make_channel): Use `_ssh_channel_to_scm'.
+ (_scm_to_ssh_channel): Use `SCM_STREAM' macro.
+ (init_channel_type): Register Guile port callbacks.
+ * src/channel-type.h (_ssh_channel_to_scm): Export.
+ * src/channel.scm (channel-read, channel-write): Remove.
+ * src/message-func.c
+ (guile_ssh_message_channel_request_open_reply_accept): Use
+ `_ssh_channel_to_scm'.
+ * examples/echo: Add to the repository.
+ * examples/Makefile.am: Add echo server/client example.
+ * examples/README: Update.
+ * examples/sssh.scm: Update.
+ * README: Update.
+
2013-11-26 Artyom Poptsov <poptsov.artyom@gmail.com>
* configure.ac, NEWS: Bump version to 0.4.0
diff --git a/README b/README
index d51115a..11e09da 100644
--- a/README
+++ b/README
@@ -45,9 +45,11 @@ Guile modules, in ${GUILE_SITE}/ssh:
- version.scm -- Information about versions.
Examples, in ${prefix}/share/libguile-ssh/examples
- - ssshd.scm -- SSH server example.
- - sssh.scm -- SSH client example.
-
+ - ssshd.scm -- SSH server example.
+ - sssh.scm -- SSH client example.
+ + echo/
+ - client.scm -- Echo client example.
+ - server.scm -- Echo server example.
* Installation
For a basic explanation of the installation of the package, see the
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 2679423..77bbcde 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,4 +1,4 @@
-## Copyright (C) 2013 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+## Copyright (C) 2013, 2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
##
## This file is part of libguile-ssh.
##
@@ -17,4 +17,6 @@
## <http://www.gnu.org/licenses/>.
examplesdir = $(pkgdatadir)/examples
+examples_echodir = $(pkgdatadir)/examples/echo
dist_examples_DATA = README sssh.scm ssshd.scm
+dist_examples_echo_DATA = echo/*.scm
diff --git a/examples/README b/examples/README
index 3e2917c..f83ecb2 100644
--- a/examples/README
+++ b/examples/README
@@ -1,31 +1,29 @@
-# -*- mode: outline; -*-
+# -*- mode: org; -*-
* Overview
-
This directory includes an examples of programs that use Guile-SSH
library to access SSH protocol
* Scheme Secure Shell (SSSH)
-
SSSH uses Guile-SSH API to implement basic SSH client functionality.
-
** Usage
-
Please see
-
./sssh.scm --help
for information about program usage.
** Examples
-
./sssh.scm --identity=~/.ssh/id_rsa --user=avp localhost "uname -a"
* Scheme Secure Shell Daemon (SSSHD)
-
SSSHD uses Guile-SSH API to implement basic SSH server functionality.
-
** Usage
-
./ssshd.scm
+* Echo server and client
+Implementation of an SSH based echo protocol ([[https://tools.ietf.org/html/rfc862][RFC862]]) with Guile-SSH.
+Please find sources in `echo/' directory:
+ - echo/client.scm
+ - echo/server.scm
+
+
diff --git a/examples/echo/client.scm b/examples/echo/client.scm
new file mode 100755
index 0000000..478aa67
--- /dev/null
+++ b/examples/echo/client.scm
@@ -0,0 +1,144 @@
+#!/usr/bin/guile \
+--debug -e main
+!#
+
+;;; client.scm -- Echo client example.
+
+;; Copyright (C) 2013-2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see
+;; <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+
+;;; Code:
+
+(use-modules (ice-9 getopt-long)
+ (ice-9 rdelim)
+ (ssh channel)
+ (ssh session)
+ (ssh auth)
+ (ssh key))
+
+(define *program-name* "echo-client")
+(define *default-identity-file*
+ (string-append (getenv "HOME") "/.ssh/id_rsa"))
+
+
+;; Command line options
+(define *option-spec*
+ '((user (single-char #\u) (value #t))
+ (port (single-char #\p) (value #t))
+ (identity-file (single-char #\i) (value #t))
+ (help (single-char #\h) (value #f))))
+
+
+(define (print-help)
+ "Print information about program usage."
+ (display
+ (string-append
+ *program-name* " -- Echo client example.\n"
+ "Copyright (C) Artyom Poptsov <poptsov.artyom@gmail.com>\n"
+ "Licensed under GNU GPLv3+\n"
+ "\n"
+ "Usage: " *program-name* " [ -upidv ] <host> <string>\n"
+ "\n"
+ "Options:\n"
+ " --user=<user>, -u <user> User name\n"
+ " --port=<port-number>, -p <port-number> Port number\n"
+ " --identity-file=<file>, -i <file> Path to private key\n")))
+
+
+(define (handle-error session)
+ "Handle a SSH error."
+ (display (get-error session))
+ (newline)
+ (exit 1))
+
+(define (get-prvkey session identity-file)
+ (let ((prvkey (private-key-from-file session identity-file)))
+ (if (not prvkey)
+ (handle-error session))
+ prvkey))
+
+(define (get-pubkey session prvkey)
+ (let ((pubkey (private-key->public-key prvkey)))
+ (if (not pubkey)
+ (handle-error session))
+ pubkey))
+
+
+(define (main args)
+ "Entry point of the program."
+ (if (null? (cdr args))
+ (begin
+ (print-help)
+ (exit 0)))
+
+ (let* ((options (getopt-long args *option-spec*))
+ (user (option-ref options 'user (getenv "USER")))
+ (port (string->number (option-ref options 'port "22")))
+ (identity-file (option-ref options 'identity-file
+ *default-identity-file*))
+ (help-needed? (option-ref options 'help #f))
+ (args (option-ref options '() #f)))
+
+
+
+ (if help-needed?
+ (begin
+ (print-help)
+ (exit 0)))
+
+ (if (or (null? args) (null? (cdr args)))
+ (begin
+ (print-help)
+ (exit 0)))
+
+ (let* ((host (car args))
+ (str (cadr args))
+ (session (make-session #:user user
+ #:host host
+ #:port port
+ #:log-verbosity 0))) ;Be quiet
+
+ (connect! session)
+ (case (authenticate-server session)
+ ((not-known) (display " The server is unknown. Please check MD5.\n")))
+
+ (let* ((private-key (get-prvkey session identity-file))
+ (public-key (get-pubkey session private-key)))
+
+ (if (eqv? (userauth-pubkey! session #f public-key private-key) 'error)
+ (handle-error session))
+
+ (let ((channel (make-channel session)))
+
+ (if (not channel)
+ (handle-error session))
+
+ (channel-open-session channel)
+
+ (display str channel)
+
+ (let poll ((count #f))
+ (if (or (not count) (zero? count))
+ (poll (channel-poll channel #f))
+ (begin
+ (display (read-line channel))
+ (newline)))))))))
+
+;;; echo.scm ends here.
diff --git a/examples/echo/server.scm b/examples/echo/server.scm
new file mode 100755
index 0000000..29b1376
--- /dev/null
+++ b/examples/echo/server.scm
@@ -0,0 +1,145 @@
+#!/usr/bin/guile \
+--debug -e main -s
+!#
+
+(use-modules (ice-9 rdelim)
+ (ice-9 popen)
+ (ssh server)
+ (ssh message)
+ (ssh session)
+ (ssh channel)
+ (ssh key)
+ (ssh auth)) ; userauth-*
+
+(define *default-bindport* 12345)
+(define *default-log-verbosity* 0)
+(define *default-rsakey* (string-append (getenv "HOME")
+ "/.ssh/id_rsa"))
+
+(define (handle-req-auth session msg msg-type)
+ (let ((subtype (cadr msg-type)))
+
+ (format #t " subtype: ~a~%" subtype)
+
+ ;; Allowed authentication methods
+ (message-auth-set-methods! msg '(public-key))
+
+ (case subtype
+ ((auth-method-publickey)
+ (let* ((req (message-get-req msg))
+ (user (auth-req:user req))
+ (pubkey (auth-req:pubkey req))
+ (pubkey-state (auth-req:pubkey-state req)))
+ (format #t
+ (string-append " User ~a wants to authenticate with a public key (~a)~%"
+ " Public key state: ~a~%")
+ user (get-key-type pubkey) pubkey-state)
+
+ (case pubkey-state
+ ((none)
+ (message-auth-reply-public-key-ok msg))
+
+ ((valid)
+ (message-reply-success msg))
+
+ (else
+ (format #t " Bad public key state: ~a~%" pubkey-state)
+ (message-reply-default msg)))))
+
+ (else
+ (message-reply-default msg)))))
+
+(define (handle-req-channel-open msg msg-type)
+ (let ((subtype (cadr msg-type)))
+ (format #t " subtype: ~a~%" subtype)
+ (case subtype
+ ((channel-session)
+ (message-channel-request-open-reply-accept msg))
+ (else
+ (message-reply-default msg)
+ #f))))
+
+(define (handle-req-channel msg msg-type channel)
+ (let ((subtype (cadr msg-type)))
+
+ (format #t " subtype: ~a~%" subtype)
+
+ (case subtype
+
+ ((channel-request-env)
+ (let* ((env-req (message-get-req msg))
+ (name (env-req:name env-req))
+ (value (env-req:value env-req)))
+ (format #t
+ (string-append " env requested:~%"
+ " name: ~a~%"
+ " value: ~a~%")
+ name value)
+ (setenv name value)
+ (message-reply-success msg)))
+
+ (else
+ (message-reply-success msg)))))
+
+(define (main args)
+ (let ((server (make-server #:bindport *default-bindport*
+ #:rsakey *default-rsakey*
+ #:log-verbosity *default-log-verbosity*
+ #:banner "Scheme Secure Shell Daemon"))
+ (channel #f))
+
+ (format #t (string-append
+ "Using private key ~a~%"
+ "Listening on port ~a~%")
+ *default-rsakey*
+ *default-bindport*)
+
+ ;; Start listen to incoming connections.
+ (server-listen server)
+
+ ;; Accept new connections from clients. Every connection is
+ ;; handled in its own SSH session.
+ (let main-loop ((session (server-accept server)))
+ (display "Client accepted.\n")
+ (server-handle-key-exchange session)
+ ;; Handle messages from the connected SSH client.
+ (let session-loop ((msg (server-message-get session)))
+ (if msg
+ (let ((msg-type (message-get-type msg)))
+ (format #t "Message: ~a~%" msg-type)
+ ;; Check the type of the message
+ (case (car msg-type)
+ ((request-service)
+ (let ((srv-req (message-get-req msg)))
+ (format #t " Service requested: ~a~%"
+ (service-req:service srv-req))
+ (message-reply-success msg)))
+
+ ((request-auth)
+ (handle-req-auth session msg msg-type))
+
+ ((request-channel-open)
+ (set! channel (handle-req-channel-open msg msg-type))
+ (let poll ((count #f))
+ (if (or (not count) (zero? count))
+ (poll (channel-poll channel #f))
+ (let ((str (read-line channel)))
+ (format #t "Received message: ~a~%" str)
+ (display "Echoing back...\n")
+ (display str channel)))))
+
+ ((request-channel)
+ (handle-req-channel msg msg-type channel))
+
+ (else
+ (display "Reply default\n")
+ (message-reply-default msg)))))
+ ;; (if channel
+ ;; (let ((str (read-line channel)))
+ ;; (display str))))
+ (if (connected? session)
+ (session-loop (server-message-get session))))
+ (disconnect! session)
+ (main-loop (server-accept server)))))
+
+;;; server.scm ends here.
diff --git a/examples/sssh.scm b/examples/sssh.scm
index 27be506..f49c825 100755
--- a/examples/sssh.scm
+++ b/examples/sssh.scm
@@ -4,7 +4,7 @@
;;; sssh.scm -- Scheme Secure Shell.
-;; Copyright (C) 2013 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+;; Copyright (C) 2013, 2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
@@ -30,6 +30,7 @@
;;; Code:
(use-modules (ice-9 getopt-long)
+ (ice-9 rdelim)
(ssh channel)
(ssh session)
(ssh auth)
@@ -200,11 +201,7 @@
(poll (channel-poll channel #f))
(begin
(print-debug "10. channel-read (ssh_channel_read)\n")
- (let ((result (channel-read channel count #f)))
- (if (not result)
- (handle-error session)
- (begin
- (display result)
- (newline))))))))))))
+ (display (read-line channel))
+ (newline)))))))))
;;; sssh.scm ends here
diff --git a/src/channel-func.c b/src/channel-func.c
index 6da8b69..429aab7 100644
--- a/src/channel-func.c
+++ b/src/channel-func.c
@@ -1,6 +1,6 @@
/* channel-func.c -- SSH channel manipulation functions.
*
- * Copyright (C) 2013 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+ * Copyright (C) 2013, 2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
*
* This file is part of libguile-ssh
*
@@ -184,72 +184,6 @@ SCM_DEFINE (guile_ssh_channel_pool, "channel-poll", 2, 0, 0,
}
#undef FUNC_NAME
-/* Read data from the channel.
-
- Return #f if no data is available. Throw guile-ssh-error on
- error. */
-SCM_DEFINE (guile_ssh_channel_read, "channel-read", 3, 0, 0,
- (SCM channel, SCM count, SCM is_stderr),
- "Read data from the channel CHANNEL.")
-#define FUNC_NAME s_guile_ssh_channel_read
-{
- struct channel_data *data = _scm_to_ssh_channel (channel);
- int res;
- char *buffer; /* Buffer for data. */
- uint32_t c_count; /* Size of buffer. */
- SCM obtained_data = SCM_BOOL_F; /* Obtained data from the channel. */
-
- SCM_ASSERT (scm_is_unsigned_integer (count, 0, UINT32_MAX), count,
- SCM_ARG2, FUNC_NAME);
- SCM_ASSERT (scm_is_bool (is_stderr), is_stderr, SCM_ARG3, FUNC_NAME);
-
- c_count = scm_to_unsigned_integer (count, 0, UINT32_MAX);
- buffer = scm_gc_calloc (sizeof (char) * c_count + 1, "data buffer");
- res = ssh_channel_read (data->ssh_channel, buffer, c_count + 1,
- scm_is_true (is_stderr));
-
- if (res > 0)
- {
- buffer[res] = 0; /* Avoid getting garbage in a SCM string */
- obtained_data = scm_from_locale_string (buffer);
- }
-
- scm_gc_free (buffer, sizeof (char) + c_count + 1, "data buffer");
-
- if (res < 0)
- {
- /* Throw the exception only if an error is occured (res < 0).
- Return #t if res == 0 (no data is available). */
- guile_ssh_error1 (FUNC_NAME, "Couldn't read data from a channel.",
- SCM_BOOL_F);
- }
-
- return obtained_data;
-}
-#undef FUNC_NAME
-
-SCM_DEFINE (guile_ssh_channel_write, "channel-write", 3, 0, 0,
- (SCM channel, SCM len, SCM data),
- "Write data DATA of the length LEN to the channel CHANNEL")
-#define FUNC_NAME s_guile_ssh_channel_write
-{
- struct channel_data *channel_data = _scm_to_ssh_channel (channel);
- int res;
- uint32_t c_len;
- char *c_data;
-
- SCM_ASSERT (scm_is_unsigned_integer (len, 0, UINT32_MAX), len,
- SCM_ARG2, FUNC_NAME);
-
- c_len = scm_to_uint32 (len);
- c_data = scm_to_locale_string (data);
-
- res = ssh_channel_write (channel_data->ssh_channel, c_data, c_len);
-
- return (res != SSH_ERROR) ? scm_from_int (res) : SCM_BOOL_F;
-}
-#undef FUNC_NAME
-
/* Close a channel. */
SCM_DEFINE (guile_ssh_channel_close, "close-channel!", 1, 0, 0,
(SCM channel),
diff --git a/src/channel-func.h b/src/channel-func.h
index 94390dd..fbc9716 100644
--- a/src/channel-func.h
+++ b/src/channel-func.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+/* Copyright (C) 2013, 2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
*
* This file is part of libguile-ssh
*
@@ -22,7 +22,6 @@
extern SCM guile_ssh_channel_open_session (SCM arg1);
extern SCM guile_ssh_channel_request_exec (SCM arg1, SCM arg2);
extern SCM guile_ssh_channel_pool (SCM arg1, SCM arg2);
-extern SCM guile_ssh_channel_read (SCM arg1, SCM arg2, SCM arg3);
extern SCM guile_ssh_channel_close (SCM arg1);
extern SCM guile_ssh_channel_is_open_p (SCM arg1);
diff --git a/src/channel-type.c b/src/channel-type.c
index 7084f52..b4dba66 100644
--- a/src/channel-type.c
+++ b/src/channel-type.c
@@ -1,6 +1,6 @@
/* channel-type.c -- SSH channel smob.
*
- * Copyright (C) 2013 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+ * Copyright (C) 2013, 2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
*
* This file is part of libguile-ssh
*
@@ -20,6 +20,7 @@
#include <libguile.h>
#include <libssh/libssh.h>
+#include <assert.h>
#include "session-type.h"
#include "channel-type.h"
@@ -27,8 +28,64 @@
scm_t_bits channel_tag; /* Smob tag. */
+enum { PORT_BUFSZ = 256 }; /* Size of the port's buffer */
+
-/* Smob specific procedures */
+/* Ptob specific procedures */
+
+/* Read data from the channel.
+
+ Return EOF if no data is available or an error occured */
+static int
+ptob_fill_input (SCM port)
+{
+ /* DEBUG */
+ scm_puts ("fill_input: Called.\n", scm_current_output_port ());
+
+ struct channel_data *cd = _scm_to_ssh_channel (port);
+ scm_port *pt = SCM_PTAB_ENTRY (port);
+ int res;
+
+ res = ssh_channel_read (cd->ssh_channel,
+ pt->read_buf, PORT_BUFSZ,
+ cd->is_stderr);
+
+ if (res >= 0)
+ pt->read_end = pt->read_buf + res;
+
+ return (res > 0) ? 0 : EOF;
+}
+
+static void
+ptob_write (SCM channel, const void *data, size_t sz)
+{
+ /* DEBUG */
+ scm_puts ("write: Called.\n", scm_current_output_port ());
+
+ struct channel_data *channel_data = _scm_to_ssh_channel (channel);
+ int res = ssh_channel_write (channel_data->ssh_channel, data, sz);
+ if (res == SSH_ERROR)
+ {
+ ssh_session session = ssh_channel_get_session (channel_data->ssh_channel);
+ guile_ssh_error1 ("write", ssh_get_error (session), channel);
+ }
+}
+
+static void
+ptob_flush (SCM channel)
+{
+ /* DEBUG */
+ scm_puts ("flush: Called.\n", scm_current_output_port ());
+ scm_port *pt = SCM_PTAB_ENTRY (channel);
+ pt->read_end = pt->read_buf;
+}
+
+static int
+ptob_input_waiting (SCM channel)
+{
+ /* DEBUG */
+ scm_puts ("input_waiting: Called.\n", scm_current_output_port ());
+}
SCM
mark_channel (SCM channel_smob)
@@ -48,7 +105,12 @@ static int
print_channel (SCM smob, SCM port, scm_print_state *pstate)
{
struct channel_data *ch = _scm_to_ssh_channel (smob);
+
+ assert (ch);
+ assert (ch->ssh_channel);
+
int is_open = ssh_channel_is_open (ch->ssh_channel);
+
scm_puts ("#<", port);
scm_puts (is_open ? "open" : "closed", port);
scm_puts (" ssh channel>", port);
@@ -56,24 +118,58 @@ print_channel (SCM smob, SCM port, scm_print_state *pstate)
return 1;
}
+/* Pack the SSH channel CH to a Scheme port and return newly created
+ port. */
+SCM
+_ssh_channel_to_scm (ssh_channel ch)
+{
+ struct channel_data *channel_data;
+ SCM ptob;
+ scm_port *pt;
+
+ channel_data = scm_gc_malloc (sizeof (struct channel_data), "channel");
+
+ channel_data->ssh_channel = ch;
+ channel_data->is_stderr = 0; /* Reading from stderr disabled by default */
+
+ ptob = scm_new_port_table_entry (channel_tag);
+ pt = SCM_PTAB_ENTRY (ptob);
+
+ pt->rw_random = 0;
+
+ /* Output init */
+ pt->write_buf = scm_gc_malloc (PORT_BUFSZ, "port write buffer");
+ pt->write_buf_size = PORT_BUFSZ;
+ pt->write_pos = pt->write_buf;
+ pt->write_end = pt->write_buf;
+
+ /* Input init */
+ pt->read_buf = scm_gc_malloc (PORT_BUFSZ, "port read buffer");
+ pt->read_buf_size = PORT_BUFSZ;
+ pt->read_pos = pt->read_buf;
+ pt->read_end = pt->read_buf;
+
+ SCM_SET_CELL_TYPE (ptob,
+ (channel_tag | SCM_OPN
+ | SCM_RDNG | SCM_WRTNG
+ | SCM_BUFLINE));
+ SCM_SETSTREAM (ptob, channel_data);
+
+ return ptob;
+}
+
/* Allocate a new SSH channel. */
SCM_DEFINE (guile_ssh_make_channel, "make-channel", 1, 0, 0,
(SCM arg1),
"Allocate a new SSH channel.")
{
- SCM smob;
-
struct session_data *session_data = _scm_to_ssh_session (arg1);
- struct channel_data *channel_data
- = (struct channel_data *) scm_gc_malloc (sizeof (struct channel_data),
- "channel");
- channel_data->ssh_channel = ssh_channel_new (session_data->ssh_session);
- if (channel_data->ssh_channel == NULL)
- return SCM_BOOL_F;
+ ssh_channel ch = ssh_channel_new (session_data->ssh_session);
- SCM_NEWSMOB (smob, channel_tag, channel_data);
+ if (! ch)
+ return SCM_BOOL_F;
- return smob;
+ return _ssh_channel_to_scm (ch);
}
@@ -108,7 +204,7 @@ struct channel_data *
_scm_to_ssh_channel (SCM x)
{
scm_assert_smob_type (channel_tag, x);
- return (struct channel_data *) SCM_SMOB_DATA (x);
+ return (struct channel_data *) SCM_STREAM (x);
}
@@ -116,12 +212,14 @@ _scm_to_ssh_channel (SCM x)
void
init_channel_type (void)
{
- channel_tag = scm_make_smob_type ("channel",
- sizeof (struct channel_data));
- scm_set_smob_mark (channel_tag, mark_channel);
- scm_set_smob_free (channel_tag, free_channel);
- scm_set_smob_print (channel_tag, print_channel);
- scm_set_smob_equalp (channel_tag, equalp_channel);
+ channel_tag = scm_make_port_type ("channel",
+ &ptob_fill_input,
+ &ptob_write);
+ scm_set_port_flush (channel_tag, ptob_flush);
+ scm_set_port_mark (channel_tag, mark_channel);
+ scm_set_port_free (channel_tag, free_channel);
+ scm_set_port_print (channel_tag, print_channel);
+ scm_set_port_equalp (channel_tag, equalp_channel);
#include "channel-type.x"
}
diff --git a/src/channel-type.h b/src/channel-type.h
index 8a79a7e..56816a2 100644
--- a/src/channel-type.h
+++ b/src/channel-type.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+/* Copyright (C) 2013, 2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
*
* This file is part of libguile-ssh
*
@@ -28,6 +28,7 @@ extern scm_t_bits channel_tag;
/* Smob data. */
struct channel_data {
ssh_channel ssh_channel;
+ uint8_t is_stderr;
};
@@ -40,6 +41,7 @@ extern void init_channel_type (void);
/* Helper procedures */
-struct channel_data *_scm_to_ssh_channel (SCM x);
+extern struct channel_data *_scm_to_ssh_channel (SCM x);
+extern SCM _ssh_channel_to_scm (ssh_channel ch);
#endif /* ifndef __CHANNEL_TYPE_H__ */
diff --git a/src/channel.scm b/src/channel.scm
index 008ac64..5b58e1c 100644
--- a/src/channel.scm
+++ b/src/channel.scm
@@ -37,8 +37,6 @@
;; channel-request-shell
;; channel-set-pty-size!
;; channel-poll
-;; channel-read
-;; channel-write
;; channel-open?
;; channel-eof?
@@ -59,8 +57,6 @@
channel-request-shell
channel-set-pty-size!
channel-poll
- channel-read
- channel-write
channel-open?
channel-eof?))
diff --git a/src/message-func.c b/src/message-func.c
index 5968a48..5c7123b 100644
--- a/src/message-func.c
+++ b/src/message-func.c
@@ -1,6 +1,6 @@
/* message-func.c -- Functions for working with SSH messages.
*
- * Copyright (C) 2013 Artyom V. Poptsov <poptsov.artyom@gmail.com>
+ * Copyright (C) 2013, 2014 Artyom V. Poptsov <poptsov.artyom@gmail.com>
*
* This file is part of libguile-ssh
*
@@ -119,19 +119,14 @@ SCM_DEFINE (guile_ssh_message_channel_request_open_reply_accept,
"Accept open-channel request.\n"
"Return a new SSH channel.")
{
- SCM smob;
struct message_data *msg_data = _scm_to_ssh_message (msg);
- struct channel_data *channel_data
- = (struct channel_data *) scm_gc_malloc (sizeof (struct channel_data),
- "channel");
- channel_data->ssh_channel
- = ssh_message_channel_request_open_reply_accept (msg_data->message);
- if (channel_data->ssh_channel == NULL)
- return SCM_BOOL_F;
+ ssh_channel *ch;
- SCM_NEWSMOB (smob, channel_tag, channel_data);
+ ch = ssh_message_channel_request_open_reply_accept (msg_data->message);
+ if (! ch)
+ return SCM_BOOL_F;
- return smob;
+ return _ssh_channel_to_scm (ch);
}