main.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "log"
  7. "math/rand"
  8. "net"
  9. "os"
  10. "strings"
  11. "time"
  12. "github.com/cryptix/go/logging"
  13. "github.com/ftrvxmtrx/fd"
  14. "github.com/pkg/errors"
  15. )
  16. const path = "/tmp/unixsockmux.sock"
  17. func main() {
  18. rand.Seed(time.Now().Unix())
  19. os.Remove(path)
  20. addr, err := net.ResolveUnixAddr("unix", path)
  21. check(err)
  22. l, err := net.ListenUnix("unix", addr)
  23. check(err)
  24. log.Println("Accepting unix sockets")
  25. done := make(chan struct{})
  26. errc := make(chan error)
  27. go func() {
  28. for {
  29. select {
  30. case e := <-errc:
  31. if e != nil {
  32. log.Printf("Error from errChan:\n%s\n", e)
  33. break
  34. }
  35. default:
  36. clientConn, err := l.AcceptUnix()
  37. if err != nil {
  38. log.Printf("AcceptUnix() error:%s\n", err)
  39. break
  40. }
  41. go handleConn(clientConn, errc)
  42. }
  43. }
  44. close(done)
  45. }()
  46. <-done
  47. log.Println("Accept loop closed.")
  48. }
  49. var check = logging.CheckFatal
  50. func handleConn(c *net.UnixConn, errc chan error) {
  51. var session = "unset"
  52. f, err := c.File()
  53. if err == nil {
  54. session = fmt.Sprint(f.Fd())
  55. }
  56. log.Println("Accepted Connection", session)
  57. sc := bufio.NewScanner(c)
  58. for sc.Scan() {
  59. txt := sc.Text()
  60. parts := strings.Split(txt, ":")
  61. if len(parts) < 2 {
  62. continue
  63. }
  64. ir, iw, err := os.Pipe()
  65. if err != nil {
  66. errc <- errors.Wrap(err, "failed to make pipe 1 for echo")
  67. return
  68. }
  69. defer iw.Close()
  70. or, ow, err := os.Pipe()
  71. if err != nil {
  72. errc <- errors.Wrap(err, "failed to make pipe 2 for echo")
  73. return
  74. }
  75. defer ow.Close()
  76. switch parts[1] {
  77. case "ping":
  78. go startPing(session, ow, ir)
  79. case "echo":
  80. go startEcho(session, ow, ir)
  81. default:
  82. fmt.Fprintln(c, session,": unknown command:", parts)
  83. break
  84. }
  85. fd.Put(c, or, iw) // we need to put single file descriptors across this (cant squash them into a single pipe)
  86. log.Println(txt)
  87. // handle response
  88. }
  89. if err := sc.Err(); err != nil {
  90. log.Println("scanerr:", err)
  91. }
  92. err=c.Close()
  93. log.Println(session,"connection closed",err)
  94. return
  95. }
  96. func startPing(s string, w io.WriteCloser, r io.Reader) {
  97. go func() {
  98. sc := bufio.NewScanner(r)
  99. for sc.Scan() {
  100. txt := sc.Text()
  101. log.Println(s,"from ping:", txt)
  102. }
  103. log.Println(s,"ping read closed")
  104. }()
  105. for i := 5; i > 0; i-- {
  106. time.Sleep(1 * time.Second)
  107. fmt.Fprintln(w, "ping:", time.Now().Unix())
  108. }
  109. w.Close()
  110. log.Println(s,"ping write closed")
  111. }
  112. func startEcho(s string, w io.WriteCloser, r io.Reader) {
  113. sc := bufio.NewScanner(r)
  114. for sc.Scan() {
  115. txt := sc.Text()
  116. log.Println(s,"from echo:", txt)
  117. // handle response
  118. fmt.Fprintln(w, txt)
  119. }
  120. w.Close()
  121. log.Println(s,"echo closed")
  122. }