diff options
Diffstat (limited to 'pkg/server/hook/tee.go')
| -rw-r--r-- | pkg/server/hook/tee.go | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/pkg/server/hook/tee.go b/pkg/server/hook/tee.go new file mode 100644 index 0000000..6591e33 --- /dev/null +++ b/pkg/server/hook/tee.go @@ -0,0 +1,120 @@ +package hook + +import ( + "bytes" + "encoding/hex" + "fmt" + "os" + "path" + "sync" + "tunnel/pkg/server/env" + "tunnel/pkg/server/opts" + "tunnel/pkg/server/queue" +) + +const teeDefaultFile = "/tmp/tunnel/dump" + +type tee struct { + f *os.File + mu sync.Mutex + wg sync.WaitGroup +} + +type teeHook struct { + file string +} + +func (t *tee) dump(s string, p []byte) error { + var out bytes.Buffer + + fmt.Fprintln(&out, s, len(p)) + + w := hex.Dumper(&out) + w.Write(p) + w.Close() + + if _, err := t.f.Write(out.Bytes()); err != nil { + return err + } + + return nil +} + +func (t *tee) Send(rq, wq queue.Q) error { + defer t.wg.Done() + + for b := range rq { + t.dump(">", b) + wq <- b + } + + return nil +} + +func (t *tee) Recv(rq, wq queue.Q) error { + defer t.wg.Done() + + for b := range rq { + t.dump("<", b) + wq <- b + } + + return nil +} + +func (h *teeHook) where(env env.Env) string { + if h.file != "" { + return h.file + } + + if v := env.Eval("@{tunnel.@{tunnel}.tee.file}"); v != "" { + return v + } + + if v, ok := env.Find("hook.tee.file"); ok { + return v + } + + return teeDefaultFile +} + +func (h *teeHook) Open(env env.Env) (interface{}, error) { + file := h.where(env) + dir := path.Dir(file) + + if err := os.MkdirAll(dir, 0755); err != nil { + return nil, err + } + + tid, sid := env.Get("tunnel"), env.Get("stream") + name := fmt.Sprintf("%s.%s.%s", file, tid, sid) + + var t tee + + if f, err := os.Create(name); err != nil { + return nil, err + } else { + t.f = f + } + + t.wg.Add(2) + + go func() { + t.wg.Wait() + t.f.Close() + }() + + return &t, nil +} + +func newTeeHook(opts opts.Opts, env env.Env) (hook, error) { + h := &teeHook{} + if file, ok := opts["file"]; ok { + h.file = file + } + return h, nil +} + +func init() { + register("tee", newTeeHook) +} |
