main.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. package client
  2. import (
  3. log "code.google.com/p/log4go"
  4. "fmt"
  5. "io/ioutil"
  6. "net"
  7. "ngrok/client/ui"
  8. "ngrok/client/views/term"
  9. "ngrok/client/views/web"
  10. "ngrok/conn"
  11. nlog "ngrok/log"
  12. "ngrok/msg"
  13. "ngrok/proto"
  14. "ngrok/util"
  15. "runtime"
  16. "time"
  17. )
  18. /**
  19. * Connect to the ngrok server
  20. */
  21. func connect(addr string, typ string) (c conn.Conn, err error) {
  22. var (
  23. tcpAddr *net.TCPAddr
  24. tcpConn *net.TCPConn
  25. )
  26. if tcpAddr, err = net.ResolveTCPAddr("tcp", addr); err != nil {
  27. return
  28. }
  29. log.Debug("Dialing %v", addr)
  30. if tcpConn, err = net.DialTCP("tcp", nil, tcpAddr); err != nil {
  31. return
  32. }
  33. c = conn.NewTCP(tcpConn, typ)
  34. c.Debug("Connected to: %v", tcpAddr)
  35. return c, nil
  36. }
  37. /**
  38. * Establishes and manages a tunnel proxy connection with the server
  39. */
  40. func proxy(proxyAddr string, s *State, ctl *ui.Controller) {
  41. start := time.Now()
  42. remoteConn, err := connect(proxyAddr, "pxy")
  43. if err != nil {
  44. panic(err)
  45. }
  46. defer remoteConn.Close()
  47. err = msg.WriteMsg(remoteConn, &msg.RegProxyMsg{Url: s.publicUrl})
  48. if err != nil {
  49. panic(err)
  50. }
  51. localConn, err := connect(s.opts.localaddr, "prv")
  52. if err != nil {
  53. remoteConn.Warn("Failed to open private leg %s: %v", s.opts.localaddr, err)
  54. return
  55. }
  56. defer localConn.Close()
  57. m := s.metrics
  58. m.proxySetupTimer.Update(time.Since(start))
  59. m.connMeter.Mark(1)
  60. ctl.Update(s)
  61. m.connTimer.Time(func() {
  62. localConn := s.protocol.WrapConn(localConn)
  63. bytesIn, bytesOut := conn.Join(localConn, remoteConn)
  64. m.bytesIn.Update(bytesIn)
  65. m.bytesOut.Update(bytesOut)
  66. m.bytesInCount.Inc(bytesIn)
  67. m.bytesOutCount.Inc(bytesOut)
  68. })
  69. ctl.Update(s)
  70. }
  71. /**
  72. * Establishes and manages a tunnel control connection with the server
  73. */
  74. func control(s *State, ctl *ui.Controller) {
  75. defer func() {
  76. if r := recover(); r != nil {
  77. log.Error("Recovering from failure %v, attempting to reconnect to server after 10 seconds . . .", r)
  78. s.status = "reconnecting"
  79. ctl.Update(s)
  80. time.Sleep(10 * time.Second)
  81. go control(s, ctl)
  82. }
  83. }()
  84. // establish control channel
  85. conn, err := connect(s.opts.server, "ctl")
  86. if err != nil {
  87. panic(err)
  88. }
  89. defer conn.Close()
  90. // register with the server
  91. err = msg.WriteMsg(conn, &msg.RegMsg{
  92. Protocol: s.opts.protocol,
  93. OS: runtime.GOOS,
  94. HttpAuth: s.opts.httpAuth,
  95. Hostname: s.opts.hostname,
  96. Subdomain: s.opts.subdomain,
  97. ClientId: s.id,
  98. Version: msg.Version,
  99. })
  100. if err != nil {
  101. panic(err)
  102. }
  103. // wait for the server to ack our register
  104. var regAck msg.RegAckMsg
  105. if err = msg.ReadMsgInto(conn, &regAck); err != nil {
  106. panic(err)
  107. }
  108. if regAck.Error != "" {
  109. emsg := fmt.Sprintf("Server failed to allocate tunnel: %s", regAck.Error)
  110. ctl.Cmds <- ui.Command{ui.QUIT, emsg}
  111. return
  112. }
  113. // update UI state
  114. conn.Info("Tunnel established at %v", regAck.Url)
  115. //state.version = regAck.Version
  116. s.publicUrl = regAck.Url
  117. s.status = "online"
  118. s.serverVersion = regAck.Version
  119. ctl.Update(s)
  120. // main control loop
  121. for {
  122. var m msg.Message
  123. if m, err = msg.ReadMsg(conn); err != nil {
  124. panic(err)
  125. }
  126. switch m.(type) {
  127. case *msg.ReqProxyMsg:
  128. go proxy(regAck.ProxyAddr, s, ctl)
  129. case *msg.PongMsg:
  130. //msg.WriteMsg(conn, &msg.PongMsg{})
  131. // XXX: update our live status
  132. }
  133. }
  134. }
  135. func Main() {
  136. // XXX: should do this only if they ask us too
  137. nlog.LogToFile()
  138. // parse options
  139. opts := parseArgs()
  140. // init client state
  141. s := &State{
  142. status: "connecting",
  143. // unique client id
  144. id: util.RandId(),
  145. // command-line options
  146. opts: opts,
  147. // metrics
  148. metrics: NewClientMetrics(),
  149. }
  150. switch opts.protocol {
  151. case "http":
  152. s.protocol = proto.NewHttp()
  153. case "tcp":
  154. s.protocol = proto.NewTcp()
  155. }
  156. // init ui
  157. ctl := ui.NewController()
  158. term.New(ctl, s)
  159. web.NewWebView(ctl, s, opts.webport)
  160. go control(s, ctl)
  161. quitMessage := ""
  162. ctl.Wait.Add(1)
  163. go func() {
  164. defer ctl.Wait.Done()
  165. for {
  166. select {
  167. case cmd := <-ctl.Cmds:
  168. switch cmd.Code {
  169. case ui.QUIT:
  170. quitMessage = cmd.Payload.(string)
  171. ctl.DoShutdown()
  172. return
  173. case ui.REPLAY:
  174. go func() {
  175. payload := cmd.Payload.([]byte)
  176. localConn, err := connect(s.opts.localaddr, "prv")
  177. if err != nil {
  178. log.Warn("Failed to open private leg %s: %v", s.opts.localaddr, err)
  179. return
  180. }
  181. //defer localConn.Close()
  182. localConn = s.protocol.WrapConn(localConn)
  183. localConn.Write(payload)
  184. ioutil.ReadAll(localConn)
  185. }()
  186. }
  187. }
  188. }
  189. }()
  190. ctl.Wait.Wait()
  191. fmt.Println(quitMessage)
  192. }