]> Cypherpunks.ru repositories - nncp.git/commitdiff
Ability to dial through pipes
authorSergey Matveev <stargrave@stargrave.org>
Thu, 14 Nov 2019 15:13:10 +0000 (18:13 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Fri, 15 Nov 2019 16:12:39 +0000 (19:12 +0300)
doc/cfg.texi
doc/cmds.texi
doc/news.ru.texi
doc/news.texi
src/call.go
src/cmd/nncp-daemon/main.go
src/pipe.go [new file with mode: 0644]
src/sp.go

index 2004073c98245043e085194be51f211399b17d1f..5a01b7d95095267be4a3dd38ea8c5d5e111b83c1 100644 (file)
@@ -46,6 +46,7 @@ Example @url{https://hjson.org/, Hjson} configuration file:
       addrs: {
         lan: "[fe80::1234%igb0]:5400"
         internet: alice.com:3389
+        proxied: "|ssh remote.host nncp-daemon -inetd"
       }
       calls: [
         {
@@ -152,9 +153,12 @@ omitted if direct connection exists and no relaying is required.
 @anchor{CfgAddrs}
 @item addrs
 Dictionary containing known network addresses of the node. Each key is
-human-readable name of the link/address. Values are @verb{|addr:port|}
-pairs pointing to @ref{nncp-daemon}'s listening instance. May be omitted
-if either no direct connection exists, or @ref{nncp-call} is used with
+human-readable name of the address. For direct TCP connections use
+@verb{|host:port|} format, pointing to @ref{nncp-daemon}'s listening
+instance. Also you can pipe connection through the external command
+using @verb{#|some command#} format. @code{/bin/sh -c "some command"}
+will start and its stdin/stdout used as a connection. May be omitted if
+either no direct connection exists, or @ref{nncp-call} is used with
 forced address specifying.
 
 @anchor{CfgXxRate}
index d5395238b7f58fe3f4c205005ea1da3d3175fbba..4247054b10a4c0b73f21fac3e583d52c05b5c125 100644 (file)
@@ -121,6 +121,21 @@ packets of remote node, without any transmission.
 You can specify what packets your want to download, by specifying
 @option{-pkts} option with comma-separated list of packets identifiers.
 
+Each @option{NODE} can contain several uniquely identified
+@option{ADDR}esses in @ref{CfgAddrs, configuration} file. If you do
+not specify the exact one, then all will be tried until the first
+success. Optionally you can force @option{FORCEADDR} address usage,
+instead of addresses taken from configuration file. You can specify both
+@verb{|host:port|} and @verb{#|some command#} formats.
+
+Pay attention that this command runs integrity check for each completely
+received packet in the background. This can be time consuming.
+Connection could be lost during that check and remote node won't be
+notified that file is done. But after successful integrity check that
+file is renamed from @file{.part} one and when you rerun
+@command{nncp-call} again, remote node will receive completion
+notification.
+
 @node nncp-caller
 @section nncp-caller
 
@@ -135,22 +150,7 @@ Optional number of @option{NODE}s tells to ignore other ones.
 Otherwise all nodes with specified @emph{calls} configuration
 field will be called.
 
-@option{-onlinedeadline} overrides @ref{CfgOnlineDeadline,
-@emph{onlinedeadline}} configuration option.
-
-Each @option{NODE} can contain several uniquely identified
-@option{ADDR}esses in @ref{CfgAddrs, configuration} file. If you do
-not specify the exact one, then all will be tried until the first
-success. Optionally you can force @option{FORCEADDR} address usage,
-instead of addresses taken from configuration file.
-
-Pay attention that this command runs integrity check for each completely
-received packet in the background. This can be time consuming.
-Connection could be lost during that check and remote node won't be
-notified that file is done. But after successful integrity check that
-file is renamed from @file{.part} one and when you rerun
-@command{nncp-call} again, remote node will receive completion
-notification.
+Look @ref{nncp-call} for more information.
 
 @node nncp-cfgenc
 @section nncp-cfgenc
index 7411c8e444fa73a4a065a5b919cce4c544467028..2b09a72069252f4f4ea55eafbb7723f776e4b24e 100644 (file)
@@ -16,6 +16,10 @@ YAML заменён на Hjson, из-за его гораздо большей 
 @code{Zstandard}, так как оно значительно быстрее и эффективнее, не
 смотря на то, что версия библиотеки ещё не проверена временем.
 
+@item
+Возможность соединяться с удалёнными нодами не только по TCP, но и через
+pipe вызов сторонней команды.
+
 @item
 @command{nncp-cfgnew} генерирует конфигурационный файл с множеством
 комментариев. Можно использовать @option{-nocomments} опцию для старого
index f4d7dc485109681cd9cc9e260bd569b1972005f6..5cc2e6f04f2908fda4beba61c35116156cb87d2a 100644 (file)
@@ -18,6 +18,10 @@ not supported. @code{zlib} compression is replaced with
 @code{Zstandard}, due to its speed and efficiency, despite library
 version is not mature enough.
 
+@item
+Ability to call remote nodes via pipe call of external command, not only
+through TCP.
+
 @item
 @command{nncp-cfgnew} generates configuration file with many
 comments. @option{-nocomments} option can be used for an old
index 3f150652bd915f5d1a65d58cf85b8ed9821de549..fd57bd1f283eaca0985adfc0e1bb8c4b9ff4ef01 100644 (file)
@@ -48,7 +48,13 @@ func (ctx *Ctx) CallNode(
        for _, addr := range addrs {
                sds := SDS{"node": node.Id, "addr": addr}
                ctx.LogD("call", sds, "dialing")
-               conn, err := net.Dial("tcp", addr)
+               var conn ConnDeadlined
+               var err error
+               if addr[0] == '|' {
+                       conn, err = NewPipeConn(addr[1:])
+               } else {
+                       conn, err = net.Dial("tcp", addr)
+               }
                if err != nil {
                        ctx.LogD("call", SdsAdd(sds, SDS{"err": err}), "dialing")
                        continue
index 318c3e450d9a190877cbc28554be5b1c904c9bda..0f7e460e401016165956c50987fcac6dd70026dc 100644 (file)
@@ -43,20 +43,24 @@ type InetdConn struct {
        w *os.File
 }
 
-func (ic *InetdConn) Read(p []byte) (n int, err error) {
-       return ic.r.Read(p)
+func (InetdConn) Read(p []byte) (n int, err error) {
+       return c.r.Read(p)
 }
 
-func (ic *InetdConn) Write(p []byte) (n int, err error) {
-       return ic.w.Write(p)
+func (InetdConn) Write(p []byte) (n int, err error) {
+       return c.w.Write(p)
 }
 
-func (ic *InetdConn) SetReadDeadline(t time.Time) error {
-       return ic.r.SetReadDeadline(t)
+func (InetdConn) SetReadDeadline(t time.Time) error {
+       return c.r.SetReadDeadline(t)
 }
 
-func (ic *InetdConn) SetWriteDeadline(t time.Time) error {
-       return ic.w.SetWriteDeadline(t)
+func (c InetdConn) SetWriteDeadline(t time.Time) error {
+       return c.w.SetWriteDeadline(t)
+}
+
+func (c InetdConn) Close() error {
+       return c.w.Close()
 }
 
 func performSP(ctx *nncp.Ctx, conn nncp.ConnDeadlined, nice uint8) {
diff --git a/src/pipe.go b/src/pipe.go
new file mode 100644 (file)
index 0000000..a5d8610
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+NNCP -- Node to Node copy, utilities for store-and-forward data exchange
+Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+
+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, version 3 of the License.
+
+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/>.
+*/
+
+package nncp
+
+import (
+       "os"
+       "os/exec"
+       "time"
+)
+
+type PipeConn struct {
+       cmd *exec.Cmd
+       r   *os.File
+       w   *os.File
+}
+
+func NewPipeConn(command string) (ConnDeadlined, error) {
+       cmd := exec.Command("/bin/sh", "-c", command)
+       stdinR, stdinW, err := os.Pipe()
+       if err != nil {
+               return nil, err
+       }
+       cmd.Stdin = stdinR
+       stdoutR, stdoutW, err := os.Pipe()
+       if err != nil {
+               return nil, err
+       }
+       cmd.Stdout = stdoutW
+       err = cmd.Start()
+       if err != nil {
+               return nil, err
+       }
+       return &PipeConn{cmd, stdoutR, stdinW}, nil
+}
+
+func (c PipeConn) Read(p []byte) (n int, err error) {
+       return c.r.Read(p)
+}
+
+func (c PipeConn) Write(p []byte) (n int, err error) {
+       return c.w.Write(p)
+}
+
+func (c PipeConn) SetReadDeadline(t time.Time) error {
+       return c.r.SetReadDeadline(t)
+}
+
+func (c PipeConn) SetWriteDeadline(t time.Time) error {
+       return c.w.SetWriteDeadline(t)
+}
+
+func (c PipeConn) Close() (err error) {
+       err = c.w.Close()
+       go c.cmd.Wait()
+       time.AfterFunc(time.Duration(10*time.Second), func() { c.cmd.Process.Kill() })
+       return
+}
index 5590b022d6d199b72e1420e43816d02026baf677..6dd724a59807b744b404763d03f8991f4cdc556f 100644 (file)
--- a/src/sp.go
+++ b/src/sp.go
@@ -104,7 +104,7 @@ type FreqWithNice struct {
 }
 
 type ConnDeadlined interface {
-       io.ReadWriter
+       io.ReadWriteCloser
        SetReadDeadline(t time.Time) error
        SetWriteDeadline(t time.Time) error
 }