summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorMikhail Osipov <mike.osipov@gmail.com>2020-01-20 04:20:48 +0300
committerMikhail Osipov <mike.osipov@gmail.com>2020-01-20 04:20:48 +0300
commit6fc33abdea2e0a09adf5cf1811fe1ee2fd36f0c9 (patch)
tree23fcefa80b13ed62f733e9855deb66948c473e80 /pkg
initial
Diffstat (limited to 'pkg')
-rw-r--r--pkg/client/client.go57
-rw-r--r--pkg/config/config.go8
-rw-r--r--pkg/config/log.go7
-rw-r--r--pkg/server/echo.go15
-rw-r--r--pkg/server/exit.go13
-rw-r--r--pkg/server/server.go121
-rw-r--r--pkg/server/status.go15
7 files changed, 236 insertions, 0 deletions
diff --git a/pkg/client/client.go b/pkg/client/client.go
new file mode 100644
index 0000000..d94b5a3
--- /dev/null
+++ b/pkg/client/client.go
@@ -0,0 +1,57 @@
+package client
+
+import (
+ "tunnel/pkg/config"
+ "strings"
+ "errors"
+ "time"
+ "net"
+ "io"
+)
+
+var errClosed = errors.New("server closed connection")
+
+type Client struct {
+ conn net.Conn
+}
+
+func New() (*Client, error) {
+ conn, err := net.Dial(config.SockType, config.SockPath)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Client{conn: conn}, nil
+}
+
+func (c *Client) Send(args []string) (string, error) {
+ c.conn.SetDeadline(time.Now().Add(time.Second));
+
+ defer func () {
+ var t time.Time
+ c.conn.SetDeadline(t)
+ }()
+
+ msg := strings.Join(args, " ")
+ buf := make([]byte, config.BufSize)
+
+ _, ew := c.conn.Write([]byte(msg))
+ if ew != nil {
+ return "", ew
+ }
+
+ nr, er := c.conn.Read(buf)
+ if er != nil {
+ if er == io.EOF {
+ return "", errClosed
+ }
+
+ return "", er
+ }
+
+ return string(buf[:nr]), nil
+}
+
+func (c *Client) Close() {
+ c.conn.Close()
+}
diff --git a/pkg/config/config.go b/pkg/config/config.go
new file mode 100644
index 0000000..c620e4a
--- /dev/null
+++ b/pkg/config/config.go
@@ -0,0 +1,8 @@
+package config
+
+const SockType = "unixpacket"
+const SockPath = "/tmp/tunnel.sock"
+
+const TimeFormat = "2006-01-02 15:04:05"
+
+const BufSize = 1024
diff --git a/pkg/config/log.go b/pkg/config/log.go
new file mode 100644
index 0000000..9aa24b6
--- /dev/null
+++ b/pkg/config/log.go
@@ -0,0 +1,7 @@
+package config
+
+import "log"
+
+func init() {
+ log.SetFlags(log.Lshortfile)
+}
diff --git a/pkg/server/echo.go b/pkg/server/echo.go
new file mode 100644
index 0000000..74c0450
--- /dev/null
+++ b/pkg/server/echo.go
@@ -0,0 +1,15 @@
+package server
+
+import (
+ "strings"
+ "fmt"
+ "io"
+)
+
+func init() {
+ setHandler("echo", echo)
+}
+
+func echo(s *Server, args []string, out io.Writer) {
+ fmt.Fprint(out, strings.Join(args[1:], " "))
+}
diff --git a/pkg/server/exit.go b/pkg/server/exit.go
new file mode 100644
index 0000000..504c7d1
--- /dev/null
+++ b/pkg/server/exit.go
@@ -0,0 +1,13 @@
+package server
+
+import (
+ "io"
+)
+
+func init() {
+ setHandler("exit", exit)
+}
+
+func exit(s *Server, args []string, out io.Writer) {
+ s.Stop()
+}
diff --git a/pkg/server/server.go b/pkg/server/server.go
new file mode 100644
index 0000000..ed0106b
--- /dev/null
+++ b/pkg/server/server.go
@@ -0,0 +1,121 @@
+package server
+
+import (
+ "tunnel/pkg/config"
+ "strings"
+ "bytes"
+ "sync"
+ "time"
+ "fmt"
+ "log"
+ "net"
+ "io"
+)
+
+type handler func (*Server, []string, io.Writer)
+
+var handlers = map[string]handler{}
+
+type Server struct {
+ listen net.Listener
+ since time.Time
+
+ wg sync.WaitGroup
+ m sync.Mutex
+
+ done bool
+}
+
+func setHandler(cmd string, h handler) {
+ if _, ok := handlers[cmd]; ok {
+ panic(fmt.Sprintf("handler %s already registered", cmd))
+ }
+
+ handlers[cmd] = h
+}
+
+func (s *Server) isDone() bool {
+ s.m.Lock()
+ defer s.m.Unlock()
+ return s.done
+}
+
+func New() (*Server, error) {
+ listen, err := net.Listen(config.SockType, config.SockPath)
+ if err != nil {
+ return nil, err
+ }
+
+ s := &Server{
+ listen: listen,
+ since: time.Now(),
+ }
+
+ return s, nil
+}
+
+func (s *Server) Run() {
+ for {
+ conn, err := s.listen.Accept()
+ if err != nil {
+ if s.isDone() {
+ break
+ }
+
+ log.Print(err)
+ continue
+ }
+
+ log.Print("new client")
+
+ s.wg.Add(1)
+
+ go s.handle(conn)
+ }
+
+ s.wg.Wait()
+}
+
+func (s *Server) Stop() {
+ s.m.Lock()
+ s.done = true
+ s.m.Unlock()
+
+ s.listen.Close()
+}
+
+func (s *Server) handle(c net.Conn) {
+ defer c.Close()
+ defer s.wg.Done()
+
+ buf := make([]byte, config.BufSize)
+
+ nr, er := c.Read(buf)
+ if er != nil {
+ if er != io.EOF {
+ log.Print("handle: ", er)
+ }
+ return
+ }
+
+ data := string(buf[:nr])
+ args := strings.Split(data, " ")
+ out := bytes.NewBuffer(nil)
+
+ if h, ok := handlers[args[0]]; ok {
+ log.Printf("handle: run: %s", data)
+ h(s, args, out)
+ } else {
+ fmt.Fprint(out, "unknown command")
+ }
+
+ if out.Len() == 0 {
+ out.Write([]byte("\n"))
+ }
+
+ _, ew := c.Write(out.Bytes())
+ if ew != nil {
+ log.Print("handle: ", ew)
+ return
+ }
+}
diff --git a/pkg/server/status.go b/pkg/server/status.go
new file mode 100644
index 0000000..6fb2a2a
--- /dev/null
+++ b/pkg/server/status.go
@@ -0,0 +1,15 @@
+package server
+
+import (
+ "tunnel/pkg/config"
+ "fmt"
+ "io"
+)
+
+func init() {
+ setHandler("status", status)
+}
+
+func status(s *Server, args []string, out io.Writer) {
+ fmt.Fprintf(out, "since %s", s.since.Format(config.TimeFormat))
+}