]> Cypherpunks.ru repositories - ucspi.git/blob - conn.go
Initial commit
[ucspi.git] / conn.go
1 /*
2 ucspi -- UCSPI-related utilities
3 Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package ucspi
19
20 import (
21         "io"
22         "net"
23         "os"
24         "time"
25 )
26
27 var aLongTimeAgo = time.Unix(1, 0)
28
29 type UCSPIAddr struct {
30         ip   string
31         port string
32 }
33
34 func (addr *UCSPIAddr) Network() string { return "tcp" }
35
36 func (addr *UCSPIAddr) String() string { return addr.ip + ":" + addr.port }
37
38 type Conn struct {
39         R   *os.File
40         W   *os.File
41         eof chan struct{}
42 }
43
44 type ReadResult struct {
45         n   int
46         err error
47 }
48
49 func (conn *Conn) Read(b []byte) (int, error) {
50         c := make(chan ReadResult)
51         go func() {
52                 n, err := conn.R.Read(b)
53                 c <- ReadResult{n, err}
54         }()
55         select {
56         case res := <-c:
57                 return res.n, res.err
58         case <-conn.eof:
59                 return 0, io.EOF
60         }
61 }
62
63 func (conn *Conn) Write(b []byte) (int, error) { return conn.W.Write(b) }
64
65 func (conn *Conn) Close() error {
66         if err := conn.R.Close(); err != nil {
67                 return err
68         }
69         return os.Stdin.Close()
70 }
71
72 func (conn *Conn) LocalAddr() net.Addr {
73         return &UCSPIAddr{ip: os.Getenv("TCPLOCALIP"), port: os.Getenv("TCPLOCALPORT")}
74 }
75
76 func (conn *Conn) RemoteAddr() net.Addr {
77         return &UCSPIAddr{ip: os.Getenv("TCPREMOTEIP"), port: os.Getenv("TCPREMOTEPORT")}
78 }
79
80 func (conn *Conn) SetDeadline(t time.Time) error {
81         if err := conn.R.SetReadDeadline(t); err != nil {
82                 return err
83         }
84         return conn.W.SetWriteDeadline(t)
85 }
86
87 func (conn *Conn) SetReadDeadline(t time.Time) error {
88         // An ugly hack to forcefully terminate pending read.
89         // net/http calls SetReadDeadline(aLongTimeAgo), but file
90         // descriptors are not capable to exit immediately that way.
91         if t.Equal(aLongTimeAgo) {
92                 conn.eof <- struct{}{}
93         }
94         return conn.R.SetReadDeadline(t)
95 }
96
97 func (conn *Conn) SetWriteDeadline(t time.Time) error {
98         return conn.W.SetWriteDeadline(t)
99 }