예제 #1
0
func main() {
	var normal tec.TempErrCatcher
	var skipper tec.TempErrCatcher
	skipper.IsTemp = func(e error) bool {
		return e == ErrSkip
	}

	fmt.Println("trying normal (uses Temporary interface)")
	tryTec(normal)
	fmt.Println("")
	fmt.Println("trying skipper (uses our IsTemp function)")
	tryTec(skipper)
}
예제 #2
0
// accept continously accepts incoming connections and
// adds them to the listener's Swarm. is is meant to be
// run in a goroutine.
// TODO: add rate limiting
func (l *Listener) accept() {
	var wg sync.WaitGroup
	defer func() {
		wg.Wait() // must happen before teardown
		l.teardown()
	}()

	// catching the error here is odd. doing what net/http does:
	// http://golang.org/src/net/http/server.go?s=51504:51550#L1728
	// Using the lib: https://godoc.org/github.com/jbenet/go-temp-err-catcher
	var catcher tec.TempErrCatcher

	// rate limit concurrency
	limit := make(chan struct{}, AcceptConcurrency)

	// loop forever accepting connections
	for {
		conn, err := l.netList.Accept()
		if err != nil {
			if catcher.IsTemporary(err) {
				continue
			}
			l.acceptErr <- fmt.Errorf("peerstream listener failed: %s", err)
			return // ok, problems. bail.
		}

		// add conn to swarm and listen for incoming streams
		// do this in a goroutine to avoid blocking the Accept loop.
		// note that this does not rate limit accepts.
		limit <- struct{}{} // sema down
		wg.Add(1)
		go func(conn net.Conn) {
			defer func() { <-limit }() // sema up
			defer wg.Done()

			conn2, err := l.swarm.addConn(conn, true)
			if err != nil {
				l.acceptErr <- err
				return
			}
			conn2.groups.AddSet(&l.groups) // add out groups
		}(conn)
	}
}
예제 #3
0
func tryTec(c tec.TempErrCatcher) {
	errs := []error{
		ErrTemp,
		ErrSkip,
		ErrOther,
		ErrTemp,
		ErrSkip,
		ErrOther,
	}

	for _, e := range errs {
		if c.IsTemporary(e) {
			fmt.Printf("\tIsTemporary: true  - skipped     %s\n", e)
			continue
		}

		fmt.Printf("\tIsTemporary: false - not skipped %s\n", e)
	}
}
예제 #4
0
// Accept waits for and returns the next connection to the listener.
// Note that unfortunately this
func (l *listener) Accept() (net.Conn, error) {

	// listeners dont have contexts. given changes dont make sense here anymore
	// note that the parent of listener will Close, which will interrupt all io.
	// Contexts and io don't mix.
	ctx := context.Background()

	var catcher tec.TempErrCatcher

	catcher.IsTemp = func(e error) bool {
		// ignore connection breakages up to this point. but log them
		if e == io.EOF {
			log.Debugf("listener ignoring conn with EOF: %s", e)
			return true
		}

		te, ok := e.(tec.Temporary)
		if ok {
			log.Debugf("listener ignoring conn with temporary err: %s", e)
			return te.Temporary()
		}
		return false
	}

	for {
		maconn, err := l.Listener.Accept()
		if err != nil {
			if catcher.IsTemporary(err) {
				continue
			}
			return nil, err
		}

		log.Debugf("listener %s got connection: %s <---> %s", l, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr())

		if l.filters != nil && l.filters.AddrBlocked(maconn.RemoteMultiaddr()) {
			log.Debugf("blocked connection from %s", maconn.RemoteMultiaddr())
			maconn.Close()
			continue
		}
		// If we have a wrapper func, wrap this conn
		if l.wrapper != nil {
			maconn = l.wrapper(maconn)
		}

		c, err := newSingleConn(ctx, l.local, "", maconn)
		if err != nil {
			if catcher.IsTemporary(err) {
				continue
			}
			return nil, err
		}

		if l.privk == nil || EncryptConnections == false {
			log.Warning("listener %s listening INSECURELY!", l)
			return c, nil
		}
		sc, err := newSecureConn(ctx, l.privk, c)
		if err != nil {
			log.Infof("ignoring conn we failed to secure: %s %s", err, c)
			continue
		}
		return sc, nil
	}
}