Files

95 lines
2.1 KiB
Go

package simplesocks
import (
"context"
"fmt"
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/log"
"github.com/p4gefau1t/trojan-go/tunnel"
"github.com/p4gefau1t/trojan-go/tunnel/trojan"
)
// Server is a simplesocks server
type Server struct {
underlay tunnel.Server
connChan chan tunnel.Conn
packetChan chan tunnel.PacketConn
ctx context.Context
cancel context.CancelFunc
}
func (s *Server) Close() error {
s.cancel()
return s.underlay.Close()
}
func (s *Server) acceptLoop() {
for {
conn, err := s.underlay.AcceptConn(&Tunnel{})
if err != nil {
log.Error(common.NewError("simplesocks failed to accept connection from underlying tunnel").Base(err))
select {
case <-s.ctx.Done():
return
default:
}
continue
}
metadata := new(tunnel.Metadata)
if err := metadata.ReadFrom(conn); err != nil {
log.Error(common.NewError("simplesocks server faield to read header").Base(err))
conn.Close()
continue
}
switch metadata.Command {
case Connect:
s.connChan <- &Conn{
metadata: metadata,
Conn: conn,
}
case Associate:
s.packetChan <- &PacketConn{
PacketConn: trojan.PacketConn{
Conn: conn,
},
}
default:
log.Error(common.NewError(fmt.Sprintf("simplesocks unknown command %d", metadata.Command)))
conn.Close()
}
}
}
func (s *Server) AcceptConn(tunnel.Tunnel) (tunnel.Conn, error) {
select {
case conn := <-s.connChan:
return conn, nil
case <-s.ctx.Done():
return nil, common.NewError("simplesocks server closed")
}
}
func (s *Server) AcceptPacket(tunnel.Tunnel) (tunnel.PacketConn, error) {
select {
case packetConn := <-s.packetChan:
return packetConn, nil
case <-s.ctx.Done():
return nil, common.NewError("simplesocks server closed")
}
}
func NewServer(ctx context.Context, underlay tunnel.Server) (*Server, error) {
ctx, cancel := context.WithCancel(ctx)
server := &Server{
underlay: underlay,
ctx: ctx,
connChan: make(chan tunnel.Conn, 32),
packetChan: make(chan tunnel.PacketConn, 32),
cancel: cancel,
}
go server.acceptLoop()
log.Debug("simplesocks server created")
return server, nil
}