func (c *Client) initialConnect() (tun *Conn) { var theParam = new(tunParams) var man = &d5cman{connectionInfo: c.connInfo} var err error tun, err = man.Connect(theParam) if err != nil { log.Errorf("Failed to connect to %s %s Retry after %s", c.connInfo.RemoteName(), ex.Detail(err), RETRY_INTERVAL) return nil } else { log.Infof("Login to server %s with %s successfully", c.connInfo.RemoteName(), c.connInfo.user) c.params = theParam c.token = theParam.token return } }
// return header=1 + TKSZ*many func (s *SessionMgr) createTokens(session *Session, many int) []byte { s.lock.Lock() defer s.lock.Unlock() // issue #35 // clearTokens() invoked prior to createTokens() if session == nil || session.tokens == nil { return nil } var ( tokens = make([]byte, 1+many*TKSZ) i64buf = make([]byte, 8) _tokens = tokens[1:] sha = sha1.New() ) rand.Seed(time.Now().UnixNano()) sha.Write([]byte(session.uid)) for i := 0; i < many; i++ { binary.BigEndian.PutUint64(i64buf, uint64(rand.Int63())) sha.Write(i64buf) binary.BigEndian.PutUint64(i64buf, uint64(time.Now().UnixNano())) sha.Write(i64buf) pos := i * TKSZ sha.Sum(_tokens[pos:pos]) token := _tokens[pos : pos+TKSZ] key := fmt.Sprintf("%x", token) if _, y := s.container[key]; y { i-- continue } s.container[key] = session session.tokens[key] = true } if log.V(log.LV_SESSION) { log.Errorf("SessionMap created=%d len=%d\n", many, len(s.container)) } return tokens }
func (p *multiplexer) relay(edge *edgeConn, tun *Conn, sid uint16) { var ( buf = bytePool.Get(FRAME_MAX_LEN) code byte src = edge.conn ) defer func() { // actively close then notify peer if edge.bitwiseCompareAndSet(TCP_CLOSE_R) && code != FRAME_ACTION_OPEN_DENIED { pack(buf, FRAME_ACTION_CLOSE_W, sid, nil) go func() { // tell peer to closeW frameWriteBuffer(tun, buf[:FRAME_HEADER_LEN]) bytePool.Put(buf) }() } else { bytePool.Put(buf) } if code == FRAME_ACTION_OPEN_Y { closeR(src) } else { // remote open failed SafeClose(src) if log.V(log.LV_REQ) { switch code { case FRAME_ACTION_OPEN_N: log.Infof("Remote open %s failed", edge.dest) case FRAME_ACTION_OPEN_DENIED: log.Infof("Request %s was denied by remote", edge.dest) } } } }() if edge.active { // for client _len := pack(buf, FRAME_ACTION_OPEN, sid, []byte(edge.dest[2:])) // dest with a leading mark if frameWriteBuffer(tun, buf[:_len]) != nil { SafeClose(tun) return } } var ( tn int // total nr int er error _fast_open = p.isClient ) for { if _fast_open { // In fastOpening, the timeout will give rise to recheck fastopen state src.SetReadDeadline(time.Now().Add(READ_TMO_IN_FASTOPEN)) received := false select { case code = <-edge.ready: received = true default: } if received { if code == FRAME_ACTION_OPEN_Y { _fast_open = false // fastopen finished } else { return } } else { // ready-chan was not ready if tn >= FAST_OPEN_BUF_MAX_SIZE { // must waiting for signal select { case code = <-edge.ready: case <-time.After(WAITING_OPEN_TIMEOUT): log.Errorf("Waiting open-signal sid=%d timeout for %s\n", sid, edge.dest) } // timeout or open-signal received if code == FRAME_ACTION_OPEN_Y { _fast_open = false // fastopen finished } else { return } } } // Received signal-y then finish fastopen if !_fast_open { // read forever src.SetReadDeadline(ZERO_TIME) } } nr, er = src.Read(buf[FRAME_HEADER_LEN:]) if nr > 0 { tn += nr pack(buf, FRAME_ACTION_DATA, sid, uint16(nr)) if frameWriteBuffer(tun, buf[:nr+FRAME_HEADER_LEN]) != nil { SafeClose(tun) return } } // timeout to recheck open signal if er != nil && !(_fast_open && IsTimeout(er)) { if er != io.EOF && DEBUG { log.Infof("Read to the end of edge total=%d err=(%v)", tn, er) } return } } }
func (c *Client) StartTun(mustRestart bool) { var ( tun *Conn wait bool rn = atomic.LoadInt32(&c.round) ) for { if wait { time.Sleep(RETRY_INTERVAL) } if rn < atomic.LoadInt32(&c.round) { return } if mustRestart { // clear mustRestart mustRestart = false // prevent concurrently if atomic.CompareAndSwapInt32(&c.state, CLT_WORKING, CLT_PENDING) { tun, rn = c.restart() } else { return } } if atomic.LoadInt32(&c.state) == CLT_WORKING { var dtcnt int32 var err error // not restarting, ordinary data tun if tun == nil { tun, err = c.createDataTun() if err != nil { log.Errorf("Connection failed %s Reconnect after %s", ex.Detail(err), RETRY_INTERVAL) wait = true continue } } if log.V(log.LV_CLT_CONNECT) { log.Infof("Tun %s is established\n", tun.identifier) } dtcnt = atomic.AddInt32(&c.dtCnt, 1) err = c.mux.Listen(tun, c.eventHandler, c.params.pingInterval+int(dtcnt)) dtcnt = atomic.AddInt32(&c.dtCnt, -1) if log.V(log.LV_CLT_CONNECT) { log.Errorf("Tun %s was disconnected %s Reconnect after %s\n", tun.identifier, ex.Detail(err), RETRY_INTERVAL) } // reset tun, wait = nil, true // received ping count if atomic.LoadInt32(&c.mux.pingCnt) <= 0 { // dirty tokens: used abandoned tokens c.clearTokens() } // restart: all connections were disconnected if dtcnt <= 0 { log.Errorf("Currently offline, all connections %s were lost\n", c.connInfo.RemoteName()) go c.StartTun(true) return } } else { // now is restarting then exit return } } }