telebit/listener.go

197 lines
4.8 KiB
Go
Raw Normal View History

2020-05-22 10:41:24 +00:00
package telebit
2020-05-16 09:09:47 +00:00
import (
"context"
"fmt"
"io"
"net"
"net/http"
2020-07-21 06:35:45 +00:00
"os"
2020-06-09 10:41:38 +00:00
"strings"
2020-07-21 06:35:45 +00:00
"git.rootprojects.org/root/telebit/dbg"
2020-05-16 09:09:47 +00:00
)
2020-05-22 10:41:24 +00:00
// A Listener transforms a multiplexed websocket connection into individual net.Conn-like connections.
2020-05-16 09:09:47 +00:00
type Listener struct {
2020-05-22 10:41:24 +00:00
//wsconn *websocket.Conn
tun net.Conn
incoming chan *Conn
close chan struct{}
encoder *Encoder
chunksParsed int
bytesRead int
conns map[string]net.Conn
//conns map[string]*Conn
2020-05-16 09:09:47 +00:00
}
2020-05-22 10:41:24 +00:00
// Listen creates a new Listener and sets it up to receive and distribute connections.
func Listen(tun net.Conn) *Listener {
ctx := context.TODO()
2020-05-16 09:09:47 +00:00
2020-05-22 10:41:24 +00:00
// Feed the socket into the Encoder and Decoder
listener := &Listener{
tun: tun,
incoming: make(chan *Conn, 1), // buffer ever so slightly
close: make(chan struct{}),
encoder: NewEncoder(ctx, tun),
conns: map[string]net.Conn{},
//conns: map[string]*Conn{},
2020-05-16 09:09:47 +00:00
}
2020-05-18 08:43:06 +00:00
2020-05-22 10:41:24 +00:00
// TODO perhaps the wrapper should have a mutex
// rather than having a goroutine in the encoder
go func() {
err := listener.encoder.Run()
fmt.Printf("encoder stopped entirely: %q", err)
2020-05-27 08:53:26 +00:00
listener.Close()
2020-05-22 10:41:24 +00:00
}()
2020-05-18 08:43:06 +00:00
2020-05-22 10:41:24 +00:00
// Decode the stream as it comes in
decoder := NewDecoder(tun)
go func() {
// TODO pass error to Accept()
2020-06-22 06:34:42 +00:00
// (this listener is also a telebit.Router)
2020-05-22 10:41:24 +00:00
err := decoder.Decode(listener)
// The listener itself must be closed explicitly because
// there's an encoder with a callback between the websocket
// and the multiplexer, so it doesn't know to stop listening otherwise
2020-06-22 06:34:42 +00:00
_ = listener.Close()
2020-05-22 10:41:24 +00:00
fmt.Printf("the main stream is done: %q\n", err)
}()
2020-05-16 09:09:47 +00:00
2020-05-22 10:41:24 +00:00
return listener
2020-05-18 08:43:06 +00:00
}
2020-05-22 10:41:24 +00:00
// ListenAndServe listens on a websocket and handles the incomming net.Conn-like connections with a Handler
func ListenAndServe(tun net.Conn, mux Handler) error {
listener := Listen(tun)
return Serve(listener, mux)
2020-05-18 08:43:06 +00:00
}
2020-05-22 10:41:24 +00:00
// Serve Accept()s connections which have already been unwrapped and serves them with the given Handler
2020-06-09 00:58:52 +00:00
func Serve(listener net.Listener, mux Handler) error {
2020-05-22 10:41:24 +00:00
for {
client, err := listener.Accept()
if nil != err {
return err
2020-05-18 08:43:06 +00:00
}
2020-05-22 10:41:24 +00:00
go func() {
2020-07-08 10:28:32 +00:00
// nil means being handled
// non-nil means handled
// io.EOF means handled with success
if err := mux.Serve(client); nil != err {
2020-06-09 10:41:38 +00:00
if io.EOF != err && io.ErrClosedPipe != err && !strings.Contains(err.Error(), errNetClosing) {
2020-05-22 10:41:24 +00:00
fmt.Printf("client could not be served: %q\n", err.Error())
2020-05-18 08:43:06 +00:00
}
2020-07-21 06:35:45 +00:00
fmt.Printf("closing original client: %s\n", err)
2020-07-08 10:28:32 +00:00
client.Close()
2020-05-18 08:43:06 +00:00
}
2020-05-22 10:41:24 +00:00
}()
2020-05-18 08:43:06 +00:00
}
2020-05-16 09:09:47 +00:00
}
2020-05-22 10:41:24 +00:00
// Accept returns a tunneled network connection
func (l *Listener) Accept() (net.Conn, error) {
2020-05-18 08:43:06 +00:00
select {
2020-05-22 10:41:24 +00:00
case rconn, ok := <-l.incoming:
2020-05-18 08:43:06 +00:00
if ok {
2020-05-22 10:41:24 +00:00
return rconn, nil
2020-05-18 08:43:06 +00:00
}
return nil, io.EOF
2020-05-22 10:41:24 +00:00
case <-l.close:
return nil, http.ErrServerClosed
2020-05-16 09:09:47 +00:00
}
2020-05-18 08:43:06 +00:00
}
2020-05-22 10:41:24 +00:00
// Close stops accepting new connections and closes the underlying websocket.
// TODO return errors.
func (l *Listener) Close() error {
l.tun.Close()
close(l.incoming)
l.close <- struct{}{}
return nil
2020-05-16 09:09:47 +00:00
}
2020-06-09 00:58:52 +00:00
func (l *Listener) Addr() net.Addr {
return l.tun.LocalAddr()
}
2020-05-22 10:41:24 +00:00
// RouteBytes receives address information and a buffer and creates or re-uses a pipe that can be Accept()ed.
func (l *Listener) RouteBytes(srcAddr, dstAddr Addr, b []byte) {
// TODO use context to be able to cancel many at once?
l.chunksParsed++
src := &srcAddr
dst := &dstAddr
pipe := l.getPipe(src, dst, len(b))
//fmt.Printf("%s\n", b)
// handle errors before data writes because I don't
// remember where the error message goes
if "error" == string(dst.scheme) {
pipe.Close()
delete(l.conns, src.String())
2020-05-22 10:41:24 +00:00
fmt.Printf("a stream errored remotely: %v\n", src)
}
// write data, if any
if len(b) > 0 {
l.bytesRead += len(b)
pipe.Write(b)
}
// EOF, if needed
if "end" == string(dst.scheme) {
2020-07-21 06:35:45 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] end\n")
}
2020-05-22 10:41:24 +00:00
pipe.Close()
delete(l.conns, src.String())
2020-05-22 10:41:24 +00:00
}
2020-05-16 09:09:47 +00:00
}
2020-05-22 10:41:24 +00:00
func (l *Listener) getPipe(src, dst *Addr, count int) net.Conn {
connID := src.String()
2020-05-22 10:41:24 +00:00
pipe, ok := l.conns[connID]
// Pipe exists
if ok {
return pipe
}
fmt.Printf("New client (%d byte hello)\n\tfrom %#v\n\tto %#v:\n", count, src, dst)
// Create pipe
rawPipe, pipe := net.Pipe()
newconn := &Conn{
//updated: time.Now(),
2020-07-21 06:36:03 +00:00
relaySourceAddr: *src,
relayTargetAddr: *dst,
2020-05-22 10:41:24 +00:00
relay: rawPipe,
}
l.conns[connID] = pipe
l.incoming <- newconn
// Handle encoding
go func() {
// TODO handle err
err := l.encoder.Encode(pipe, *src, *dst)
// the error may be EOF or ErrServerClosed or ErrGoingAwawy or some such
// or it might be an actual error
// In any case, we'll just close it all
newconn.Close()
pipe.Close()
if nil != err {
2020-07-21 06:36:03 +00:00
fmt.Fprintf(os.Stderr, "[ln-pipe] encode stream ended:\n%+v\n%+v\n%q\n", *src, *dst, err)
} else {
2020-07-21 06:36:03 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] [ln-pipe] encode stream ended gracefully:\n%+v\n%+v\n", *src, *dst)
}
}
2020-05-22 10:41:24 +00:00
}()
return pipe
2020-05-16 09:09:47 +00:00
}