func NewControl(ctlConn conn.Conn, authMsg *msg.Auth) { var err error // create the object // channels are buffered because we read and write to them // from the same goroutine in managerThread() c := &Control{ auth: authMsg, conn: ctlConn, out: make(chan msg.Message, 5), in: make(chan msg.Message, 5), stop: make(chan msg.Message, 5), proxies: make(chan conn.Conn, 10), lastPing: time.Now(), } failAuth := func(e error) { _ = msg.WriteMsg(ctlConn, &msg.AuthResp{Error: e.Error()}) ctlConn.Close() } // register the clientid c.id = authMsg.ClientId if c.id == "" { // it's a new session, assign an ID if c.id, err = util.SecureRandId(16); err != nil { failAuth(err) return } } if authMsg.Version != version.Proto { failAuth(fmt.Errorf("Incompatible versions. Server %s, client %s. Download a new version at http://ngrok.com", version.MajorMinor(), authMsg.Version)) return } // register the control controlRegistry.Add(c.id, c) c.out <- &msg.AuthResp{ Version: version.Proto, MmVersion: version.MajorMinor(), ClientId: c.id, } // As a performance optimization, ask for a proxy connection up front c.out <- &msg.ReqProxy{} // set logging prefix ctlConn.SetType("ctl") // manage the connection go c.managerThread() go c.readThread() }
func NewProxy(pxyConn conn.Conn, regPxy *msg.RegProxy) { // fail gracefully if the proxy connection fails to register defer func() { if r := recover(); r != nil { pxyConn.Warn("Failed with error: %v", r) pxyConn.Close() } }() // set logging prefix pxyConn.SetType("pxy") // look up the control connection for this proxy pxyConn.Info("Registering new proxy for %s", regPxy.ClientId) ctl := controlRegistry.Get(regPxy.ClientId) if ctl == nil { panic("No client found for identifier: " + regPxy.ClientId) } ctl.RegisterProxy(pxyConn) }
func NewControl(ctlConn conn.Conn, authMsg *msg.Auth, required_secret string) { var err error // create the object c := &Control{ auth: authMsg, conn: ctlConn, out: make(chan msg.Message), in: make(chan msg.Message), proxies: make(chan conn.Conn, 10), lastPing: time.Now(), writerShutdown: util.NewShutdown(), readerShutdown: util.NewShutdown(), managerShutdown: util.NewShutdown(), shutdown: util.NewShutdown(), } failAuth := func(e error) { _ = msg.WriteMsg(ctlConn, &msg.AuthResp{Error: e.Error()}) ctlConn.Close() } // register the clientid c.id = authMsg.ClientId if c.id == "" { // it's a new session, assign an ID if c.id, err = util.SecureRandId(16); err != nil { failAuth(err) return } } // set logging prefix ctlConn.SetType("ctl") ctlConn.AddLogPrefix(c.id) if authMsg.Version != version.Proto { failAuth(fmt.Errorf("Incompatible versions. Server %s, client %s. Download a new version at http://ngrok.com", version.MajorMinor(), authMsg.Version)) return } if required_secret != "" && authMsg.User != required_secret { failAuth(fmt.Errorf("Invalid authtoken %s", authMsg.User)) return } // register the control if replaced := controlRegistry.Add(c.id, c); replaced != nil { replaced.shutdown.WaitComplete() } // start the writer first so that the following messages get sent go c.writer() // Respond to authentication c.out <- &msg.AuthResp{ Version: version.Proto, MmVersion: version.MajorMinor(), ClientId: c.id, } // As a performance optimization, ask for a proxy connection up front c.out <- &msg.ReqProxy{} // manage the connection go c.manager() go c.reader() go c.stopper() }