Skip to content

Instantly share code, notes, and snippets.

@artyom-poptsov
Created December 3, 2015 21:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save artyom-poptsov/bb25d5a7518e889f0ccb to your computer and use it in GitHub Desktop.
Save artyom-poptsov/bb25d5a7518e889f0ccb to your computer and use it in GitHub Desktop.
Forwarding of data to a remote Unix socket using 'with-ssh' from (ssh dist) module.
#!/usr/bin/guile \
-e main -s
!#
;;; forwarding-to-unix-socket.scm
;; Copyright (C) 2015 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:
;; The program uses 'with-ssh' to start a remote process that forwards
;; data to a Unix socket. This is aimed to model a situation when
;; it's needed to communicate with a remote application that listens
;; to a Unix socket.
;;
;; *Note* that "remote" REPL servers will be started automatically;
;; they won't be stopped when the program stops.
;;
;; The program is known to work on the Guile-SSH 'master' branch,
;; commit '1673d06'.
;;
;; Here's the diagram that shows how it should work:
;;
;; This program Guile REPL Guile REPL
;; server 1 server 2
;; (port: 37147) (port: 37148)
;; ................ .............. ....................
;; : "Hello" : : : : :
;; : | : : : : :
;; : V : : : : :
;; : [local-0] : : : : [/tmp/hello.txt] :
;; : | : : : : A :
;; : V : : : : | :
;; : [local-1] : : [local-2] : : [local-3] :
;; : | : : A | : : A :
;; : | SSH tunnel | | Unix socket | :
;; : ` `----------------'` `-----------------' :
;; : : : : : :
;; '..............: :............: :..................:
;;
;; As can be seen above, there are 4 processes named [local-0],
;; [local-1], [local-2], [local-3].
;;
;; [local-0] is the main thread of this application. [local-1] is a
;; thread will be spawned by the application in order to transfer data
;; through an SSH tunnel.
;;
;; [local-2] will run in the 1st REPL server and will listen to
;; incoming connection on a local TCP socket.
;;
;; [local-3] will listen to a local Unix socket and in therefore
;; imitate a remote application (for example, GuixSD.)
;;; Code:
(use-modules (ice-9 rdelim)
;; Guile-SSH
(ssh session)
(ssh auth)
(ssh dist)
(ssh tunnel))
(define %tunnel-port-number 12400)
;; [local-3]
;;
;; This process will listen a Unix socket.
(define (start-local-3)
(display "Starting [local-3] ... ")
(let ((thread
(call-with-new-thread
(lambda ()
(let ((session (make-session #:host "localhost")))
(connect! session)
(authenticate-server session)
(userauth-agent! session)
(with-ssh (make-node session 37148)
(use-modules (ice-9 rdelim))
(let ((sock (socket PF_UNIX SOCK_STREAM 0)))
(setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
;; Bind the Unix socket and listen it.
(bind sock AF_UNIX "/tmp/start-remote-process")
(listen sock 5)
(while #t
(let ((client (car (accept sock)))
(output-file (open-file "/tmp/hello.txt" "a+")))
(write-line (read-line client) output-file)
(close output-file)
(close client))))))))))
(sleep 2)
(display "Done.\n")
thread))
;; [local-2]
;;
;; This process will listen a TCP socket and forward the data to the
;; Unix socket listened by [local-3] process, defined above.
(define (start-local-2)
(display "Starting [local-2] ... ")
(let ((thread
(call-with-new-thread
(lambda ()
(let ((session (make-session #:host "localhost")))
(connect! session)
(authenticate-server session)
(userauth-agent! session)
(with-ssh (make-node session 37147)
(use-modules (ice-9 rdelim))
(let ((tcp-sock (socket PF_INET SOCK_STREAM 0))
(unix-sock (socket PF_UNIX SOCK_STREAM 0)))
(setlocale LC_ALL "")
;; Bind the TCP socket and listen it.
(setsockopt tcp-sock SOL_SOCKET SO_REUSEADDR 1)
(bind tcp-sock AF_INET (inet-pton AF_INET "127.0.0.1")
12300)
(listen tcp-sock 5)
;; Connect to the Unix socket.
(connect unix-sock AF_UNIX "/tmp/start-remote-process")
;; Handle incoming connections.
(while #t
(let ((client (car (accept tcp-sock))))
(write-line (read-line client) unix-sock)
(close client))))))))))
(sleep 2)
(display "Done.\n")
thread))
(define (main args)
(let ((session (make-session #:host "localhost"))
(thread-local-3 (start-local-3))
(thread-local-2 (start-local-2)))
(connect! session)
(authenticate-server session)
(userauth-agent! session)
(display "Starting an SSH tunnel ... ")
(let* ((tunnel (make-tunnel session
#:port %tunnel-port-number
#:host "localhost"
#:host-port 12300))
(thread (call-with-new-thread
(lambda ()
;; [local-1]
;;
;; Start an SSH tunnel.
(display "Starting [local-1] ...\n")
(start-forward tunnel)))))
(sleep 2)
(display "Done.\n")
;; [local-0]
;;
;; Send "Hello".
(let ((sock (socket AF_INET SOCK_STREAM 0)))
(connect sock AF_INET INADDR_LOOPBACK %tunnel-port-number)
(write-line "Hello" sock)
(sleep 1)
(cancel-thread thread-local-3)
(cancel-thread thread-local-2)
(close sock)
(delete-file "/tmp/start-remote-process")))))
;;;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment