main.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. package client
  2. import (
  3. log "code.google.com/p/log4go"
  4. "crypto/rand"
  5. "fmt"
  6. "net"
  7. "ngrok/client/ui"
  8. "ngrok/conn"
  9. nlog "ngrok/log"
  10. "ngrok/proto"
  11. "runtime"
  12. "time"
  13. )
  14. /**
  15. * Connect to the ngrok server
  16. */
  17. func connect(addr string, typ string) (c conn.Conn, err error) {
  18. var (
  19. tcpAddr *net.TCPAddr
  20. tcpConn *net.TCPConn
  21. )
  22. if tcpAddr, err = net.ResolveTCPAddr("tcp", addr); err != nil {
  23. return
  24. }
  25. log.Debug("Dialing %v", addr)
  26. if tcpConn, err = net.DialTCP("tcp", nil, tcpAddr); err != nil {
  27. return
  28. }
  29. c = conn.NewTCP(tcpConn, typ)
  30. c.Debug("Connected to: %v", tcpAddr)
  31. return c, nil
  32. }
  33. /**
  34. * Establishes and manages a tunnel proxy connection with the server
  35. */
  36. func proxy(proxyAddr string, s *State) {
  37. start := time.Now()
  38. remoteConn, err := connect(proxyAddr, "pxy")
  39. if err != nil {
  40. panic(err)
  41. }
  42. defer remoteConn.Close()
  43. err = proto.WriteMsg(remoteConn, &proto.RegProxyMsg{Url: s.publicUrl})
  44. if err != nil {
  45. panic(err)
  46. }
  47. localConn, err := connect(s.opts.localaddr, "prv")
  48. if err != nil {
  49. remoteConn.Warn("Failed to open private leg %s: %v", s.opts.localaddr, err)
  50. return
  51. }
  52. defer localConn.Close()
  53. m := s.metrics
  54. m.proxySetupTimer.Update(time.Since(start))
  55. m.connMeter.Mark(1)
  56. s.Update()
  57. m.connTimer.Time(func() {
  58. if s.opts.protocol == "http" {
  59. teeConn := conn.NewTee(remoteConn)
  60. remoteConn = teeConn
  61. go conn.ParseHttp(teeConn, s.history.reqs, s.history.resps)
  62. }
  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. s.Update()
  70. }
  71. /**
  72. * Establishes and manages a tunnel control connection with the server
  73. */
  74. func control(s *State) {
  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. s.Update()
  80. time.Sleep(10 * time.Second)
  81. go control(s)
  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 = proto.WriteMsg(conn, &proto.RegMsg{
  92. Protocol: s.opts.protocol,
  93. OS: runtime.GOOS,
  94. Hostname: s.opts.hostname,
  95. Subdomain: s.opts.subdomain,
  96. ClientId: s.id,
  97. })
  98. if err != nil {
  99. panic(err)
  100. }
  101. // wait for the server to ack our register
  102. var regAck proto.RegAckMsg
  103. if err = proto.ReadMsgInto(conn, &regAck); err != nil {
  104. panic(err)
  105. }
  106. if regAck.Error != "" {
  107. emsg := fmt.Sprintf("Server failed to allocate tunnel: %s", regAck.Error)
  108. s.ui.Cmds <- ui.Command{ui.QUIT, emsg}
  109. return
  110. }
  111. // update UI state
  112. conn.Info("Tunnel established at %v", regAck.Url)
  113. //state.version = regAck.Version
  114. s.publicUrl = regAck.Url
  115. s.status = "online"
  116. s.Update()
  117. // main control loop
  118. for {
  119. var msg proto.Message
  120. if msg, err = proto.ReadMsg(conn); err != nil {
  121. panic(err)
  122. }
  123. switch msg.GetType() {
  124. case "ReqProxyMsg":
  125. go proxy(regAck.ProxyAddr, s)
  126. case "PingMsg":
  127. proto.WriteMsg(conn, &proto.PongMsg{})
  128. }
  129. }
  130. }
  131. // create a random identifier for this client
  132. func mkid() string {
  133. b := make([]byte, 8)
  134. _, err := rand.Read(b)
  135. if err != nil {
  136. panic(fmt.Sprintf("Couldn't create random client identifier, %v", err))
  137. }
  138. return fmt.Sprintf("%x", b)
  139. }
  140. func Main() {
  141. // XXX: should do this only if they ask us too
  142. nlog.LogToFile()
  143. // parse options
  144. opts := parseArgs()
  145. // init terminal, http UI
  146. termView := ui.NewTerm()
  147. httpView := ui.NewHttp(9999)
  148. // init client state
  149. s := &State{
  150. // unique client id
  151. id: mkid(),
  152. // ui communication channels
  153. ui: ui.NewUi(termView, httpView),
  154. //ui: ui.NewUi(httpView),
  155. // command-line options
  156. opts: opts,
  157. // metrics
  158. metrics: NewClientMetrics(),
  159. }
  160. // request history
  161. // XXX: don't use a callback, use a channel
  162. // and define it inline in the struct
  163. s.history = NewRequestHistory(opts.historySize, s.metrics, func(history []*RequestHistoryEntry) {
  164. s.historyEntries = history
  165. s.Update()
  166. })
  167. // set initial ui state
  168. s.status = "connecting"
  169. s.protocol = opts.protocol
  170. s.Update()
  171. go control(s)
  172. quitMessage := ""
  173. s.ui.Wait.Add(1)
  174. go func() {
  175. defer s.ui.Wait.Done()
  176. for {
  177. select {
  178. case cmd := <-s.ui.Cmds:
  179. switch cmd.Code {
  180. case ui.QUIT:
  181. quitMessage = cmd.Payload.(string)
  182. s.stopping = true
  183. s.Update()
  184. return
  185. }
  186. }
  187. }
  188. }()
  189. s.ui.Wait.Wait()
  190. fmt.Println(quitMessage)
  191. }