func (t *Tunnel) HandlePublicConnection(publicConn conn.Conn) { defer publicConn.Close() defer func() { if r := recover(); r != nil { publicConn.Warn("HandlePublicConnection failed with error %v", r) } }() startTime := time.Now() metrics.OpenConnection(t, publicConn) var proxyConn conn.Conn var err error for i := 0; i < (2 * proxyMaxPoolSize); i++ { // get a proxy connection if proxyConn, err = t.ctl.GetProxy(); err != nil { t.Warn("Failed to get proxy connection: %v", err) return } defer proxyConn.Close() t.Info("Got proxy connection %s", proxyConn.Id()) proxyConn.AddLogPrefix(t.Id()) // tell the client we're going to start using this proxy connection startPxyMsg := &msg.StartProxy{ Url: t.url, ClientAddr: publicConn.RemoteAddr().String(), } if err = msg.WriteMsg(proxyConn, startPxyMsg); err != nil { proxyConn.Warn("Failed to write StartProxyMessage: %v, attempt %d", err, i) proxyConn.Close() } else { // success break } } if err != nil { // give up publicConn.Error("Too many failures starting proxy connection") return } // To reduce latency handling tunnel connections, we employ the following curde heuristic: // Whenever we take a proxy connection from the pool, replace it with a new one util.PanicToError(func() { t.ctl.out <- &msg.ReqProxy{} }) // no timeouts while connections are joined proxyConn.SetDeadline(time.Time{}) // join the public and proxy connections bytesIn, bytesOut := conn.Join(publicConn, proxyConn) metrics.CloseConnection(t, publicConn, startTime, bytesIn, bytesOut) //log.Info("Proxy authId=%s bytesIn=%d, bytesOut=%d\n", t.ctl.userInfo.Uc.UserId, bytesIn, bytesOut) atomic.AddInt32(&t.ctl.userInfo.TransPerDay, int32(bytesIn+bytesOut)) atomic.AddInt32(&t.ctl.userInfo.TransAll, int32(bytesIn+bytesOut)) }
/** * Establishes and manages a tunnel proxy connection with the server */ func proxy(proxyAddr string, s *State, ctl *ui.Controller) { start := time.Now() remoteConn, err := conn.Dial(proxyAddr, "pxy", tlsConfig) if err != nil { // XXX: What is the proper response here? // display something to the user? // retry? // reset control connection? log.Error("Failed to establish proxy connection: %v", err) return } defer remoteConn.Close() err = msg.WriteMsg(remoteConn, &msg.RegProxyMsg{Url: s.publicUrl}) if err != nil { // XXX: What is the proper response here? // display something to the user? // retry? // reset control connection? log.Error("Failed to write RegProxyMsg: %v", err) return } localConn, err := conn.Dial(s.opts.localaddr, "prv", nil) if err != nil { remoteConn.Warn("Failed to open private leg %s: %v", s.opts.localaddr, err) badGatewayBody := fmt.Sprintf(BadGateway, s.publicUrl, s.opts.localaddr, s.opts.localaddr) remoteConn.Write([]byte(fmt.Sprintf(`HTTP/1.0 502 Bad Gateway Content-Type: text/html Content-Length: %d %s`, len(badGatewayBody), badGatewayBody))) return } defer localConn.Close() m := s.metrics m.proxySetupTimer.Update(time.Since(start)) m.connMeter.Mark(1) ctl.Update(s) m.connTimer.Time(func() { localConn := s.protocol.WrapConn(localConn) bytesIn, bytesOut := conn.Join(localConn, remoteConn) m.bytesIn.Update(bytesIn) m.bytesOut.Update(bytesOut) m.bytesInCount.Inc(bytesIn) m.bytesOutCount.Inc(bytesOut) }) ctl.Update(s) }
func (t *Tunnel) HandlePublicConnection(publicConn conn.Conn) { defer publicConn.Close() defer func() { if r := recover(); r != nil { publicConn.Warn("HandlePublicConnection failed with error %v", r) } }() startTime := time.Now() metrics.OpenConnection(t, publicConn) var proxyConn conn.Conn var attempts int var err error for { // get a proxy connection if proxyConn, err = t.ctl.GetProxy(); err != nil { t.Warn("Failed to get proxy connection: %v", err) return } defer proxyConn.Close() t.Info("Got proxy connection %s", proxyConn.Id()) proxyConn.AddLogPrefix(t.Id()) // tell the client we're going to start using this proxy connection startPxyMsg := &msg.StartProxy{ Url: t.url, ClientAddr: publicConn.RemoteAddr().String(), } if err = msg.WriteMsg(proxyConn, startPxyMsg); err != nil { attempts += 1 proxyConn.Warn("Failed to write StartProxyMessage: %v, attempt %d", err, attempts) if attempts > 3 { // give up publicConn.Error("Too many failures starting proxy connection") return } } else { // success break } } // join the public and proxy connections bytesIn, bytesOut := conn.Join(publicConn, proxyConn) metrics.CloseConnection(t, publicConn, startTime, bytesIn, bytesOut) }
func (t *Tunnel) HandlePublicConnection(publicConn conn.Conn) { defer publicConn.Close() defer func() { if r := recover(); r != nil { publicConn.Warn("HandlePublicConnection failed with error %v", r) } }() metrics.requestTimer.Time(func() { metrics.requestMeter.Mark(1) t.Debug("Requesting new proxy connection") t.ctl.out <- &msg.ReqProxyMsg{} proxyConn := <-t.proxies t.Info("Returning proxy connection %s", proxyConn.Id()) defer proxyConn.Close() conn.Join(publicConn, proxyConn) }) }
func (t *Tunnel) HandlePublicConnection(publicConn conn.Conn) { defer publicConn.Close() defer func() { if r := recover(); r != nil { publicConn.Warn("HandlePublicConnection failed with error %v", r) } }() startTime := time.Now() metrics.OpenConnection(t, publicConn) t.Debug("Requesting new proxy connection") t.ctl.out <- &msg.ReqProxyMsg{} proxyConn := <-t.proxies t.Info("Returning proxy connection %s", proxyConn.Id()) defer proxyConn.Close() bytesIn, bytesOut := conn.Join(publicConn, proxyConn) metrics.CloseConnection(t, publicConn, startTime, bytesIn, bytesOut) }
// Establishes and manages a tunnel proxy connection with the server func (c *ClientModel) proxy() { var ( remoteConn conn.Conn err error ) if c.proxyUrl == "" { remoteConn, err = conn.Dial(c.serverAddr, "pxy", c.tlsConfig) } else { remoteConn, err = conn.DialHttpProxy(c.proxyUrl, c.serverAddr, "pxy", c.tlsConfig) } if err != nil { log.Error("Failed to establish proxy connection: %v", err) return } defer remoteConn.Close() err = msg.WriteMsg(remoteConn, &msg.RegProxy{ClientId: c.id}) if err != nil { remoteConn.Error("Failed to write RegProxy: %v", err) return } // wait for the server to ack our register var startPxy msg.StartProxy if err = msg.ReadMsgInto(remoteConn, &startPxy); err != nil { remoteConn.Error("Server failed to write StartProxy: %v", err) return } tunnel, ok := c.tunnels[startPxy.Url] if !ok { remoteConn.Error("Couldn't find tunnel for proxy: %s", startPxy.Url) return } // start up the private connection start := time.Now() localConn, err := conn.Dial(tunnel.LocalAddr, "prv", nil) if err != nil { remoteConn.Warn("Failed to open private leg %s: %v", tunnel.LocalAddr, err) if tunnel.Protocol.GetName() == "http" { // try to be helpful when you're in HTTP mode and a human might see the output badGatewayBody := fmt.Sprintf(BadGateway, tunnel.PublicUrl, tunnel.LocalAddr, tunnel.LocalAddr) remoteConn.Write([]byte(fmt.Sprintf(`HTTP/1.0 502 Bad Gateway Content-Type: text/html Content-Length: %d %s`, len(badGatewayBody), badGatewayBody))) } return } defer localConn.Close() m := c.metrics m.proxySetupTimer.Update(time.Since(start)) m.connMeter.Mark(1) c.update() m.connTimer.Time(func() { localConn := tunnel.Protocol.WrapConn(localConn, mvc.ConnectionContext{Tunnel: tunnel, ClientAddr: startPxy.ClientAddr}) bytesIn, bytesOut := conn.Join(localConn, remoteConn) m.bytesIn.Update(bytesIn) m.bytesOut.Update(bytesOut) m.bytesInCount.Inc(bytesIn) m.bytesOutCount.Inc(bytesOut) }) c.update() }