示例#1
0
func default_dialer(proto, laddr, raddr string, timeout time.Duration) (net.Conn, error) {
	if proto == "" {
		if strings.IndexRune(raddr, ':') != -1 {
			proto = "tcp"
		} else {
			proto = "unix"
		}
	}

	// Make a connection
	d := &net.Dialer{Timeout: timeout}
	if laddr != "" {
		var err error
		switch proto {
		case "tcp", "tcp4", "tcp6":
			d.LocalAddr, err = net.ResolveTCPAddr(proto, laddr)
		case "unix":
			d.LocalAddr, err = net.ResolveTCPAddr(proto, laddr)
		default:
			err = net.UnknownNetworkError(proto)
		}
		if err != nil {
			return nil, err
		}
	}
	return d.Dial(proto, raddr)
}
示例#2
0
func ResolveAddr(network, addr string) (net.Addr, error) {
	resolver := resolvers[network]
	if resolver == nil {
		return nil, net.UnknownNetworkError(network)
	}

	return resolver(addr)
}
示例#3
0
func (cn *badConn) Read([]byte) (int, error) {
	if cn.readDelay != 0 {
		time.Sleep(cn.readDelay)
	}
	if cn.readErr != nil {
		return 0, cn.readErr
	}
	return 0, net.UnknownNetworkError("badConn")
}
示例#4
0
func (cn *badConn) Write([]byte) (int, error) {
	if cn.writeDelay != 0 {
		time.Sleep(cn.writeDelay)
	}
	if cn.writeErr != nil {
		return 0, cn.writeErr
	}
	return 0, net.UnknownNetworkError("badConn")
}
示例#5
0
// get a new connection using the specified transport.
func (f *Fluent) getConnection() (net.Conn, error) {
	switch f.Config.FluentNetwork {
	case "tcp":
		return net.DialTimeout(f.Config.FluentNetwork, f.Config.FluentHost+":"+strconv.Itoa(f.Config.FluentPort), f.Config.Timeout)
	case "unix":
		return net.DialTimeout(f.Config.FluentNetwork, f.Config.FluentSocketPath, f.Config.Timeout)
	default:
		return nil, net.UnknownNetworkError(f.Config.FluentNetwork)
	}
}
示例#6
0
func (a *peerAddr) Dial(e *e3x.Endpoint, x *e3x.Exchange) (net.Conn, error) {
	mod, _ := FromEndpoint(e).(*module)
	if mod == nil {
		return nil, net.UnknownNetworkError("unable to bridge")
	}

	router := e.GetExchange(a.router)
	if router == nil {
		return nil, net.UnknownNetworkError("unable to bridge")
	}

	conn := newConnection(x.RemoteHashname(), a, router, func() {
		mod.unregisterConnection(router, x.LocalToken())
	})

	mod.registerConnection(router, x.LocalToken(), conn)

	return conn, nil
}
示例#7
0
文件: fluent.go 项目: gmelika/rack
// connect establishes a new connection using the specified transport.
func (f *Fluent) connect() (err error) {
	switch f.Config.FluentNetwork {
	case "tcp":
		f.conn, err = net.DialTimeout(f.Config.FluentNetwork, f.Config.FluentHost+":"+strconv.Itoa(f.Config.FluentPort), f.Config.Timeout)
	case "unix":
		f.conn, err = net.DialTimeout(f.Config.FluentNetwork, f.Config.FluentSocketPath, f.Config.Timeout)
	default:
		err = net.UnknownNetworkError(f.Config.FluentNetwork)
	}
	return
}
示例#8
0
func (d *Dialer) dialMulti(network, address string, ips []net.IP, port string) (conn net.Conn, err error) {
	if d.Level <= 1 || len(ips) == 1 {
		for i, ip := range ips {
			addr := net.JoinHostPort(ip.String(), port)
			conn, err := d.Dialer.Dial(network, addr)
			if err != nil {
				if i < len(ips)-1 {
					continue
				} else {
					return nil, err
				}
			}
			return conn, nil
		}
	} else {
		type racer struct {
			c net.Conn
			e error
		}

		level := len(ips)
		if level > d.Level {
			level = d.Level
			ips = ips[:level]
		}

		lane := make(chan racer, level)
		for i := 0; i < level; i++ {
			go func(addr string, c chan<- racer) {
				conn, err := d.Dialer.Dial(network, addr)
				lane <- racer{conn, err}
			}(net.JoinHostPort(ips[i].String(), port), lane)
		}

		var r racer
		for j := 0; j < level; j++ {
			r = <-lane
			if r.e == nil {
				go func(count int) {
					var r1 racer
					for ; count > 0; count-- {
						r1 = <-lane
						if r1.c != nil {
							r1.c.Close()
						}
					}
				}(level - 1 - j)
				return r.c, nil
			}
		}
	}

	return nil, net.UnknownNetworkError("Unkown transport/direct error")
}
示例#9
0
func (c *ConnMock) Read(b []byte) (n int, err error) {
	if c.ReturnTimeout {
		return 0, net.UnknownNetworkError("i/o timeout")
	}
	if c.ReadData != nil {
		l := copy(b, c.ReadData)
		c.ReadData = nil
		return l, nil
	}
	return 0, io.EOF
}
示例#10
0
func utp2udp(n string) (string, error) {
	switch n {
	case "utp":
		return "udp", nil
	case "utp4":
		return "udp4", nil
	case "utp6":
		return "udp6", nil
	default:
		return "", net.UnknownNetworkError(n)
	}
}
示例#11
0
func ResolveAddr(network, address string) (net.Addr, error) {
	switch network {
	default:
		return nil, net.UnknownNetworkError(network)
	case "ip", "ip4", "ip6":
		return net.ResolveIPAddr(network, address)
	case "tcp", "tcp4", "tcp6":
		return net.ResolveTCPAddr(network, address)
	case "udp", "udp4", "udp6":
		return net.ResolveUDPAddr(network, address)
	case "unix", "unixgram", "unixpacket":
		return net.ResolveUnixAddr(network, address)
	}
}
示例#12
0
func getTestErrors() testErrors {
	errs := testErrors{
		Busy:       ErrServerBusy,
		Declined:   ErrChannelClosed,
		Timeout:    ErrTimeout,
		Network:    NewSystemError(ErrCodeNetwork, "fake network error"),
		Connection: net.UnknownNetworkError("fake connection error"),
		BadRequest: ErrTimeoutRequired,
		Unexpected: NewSystemError(ErrCodeUnexpected, "fake unexpected error"),
		Cancelled:  NewSystemError(ErrCodeCancelled, "fake cancelled error"),
	}
	errs.all = []error{errs.Busy, errs.Declined, errs.Timeout, errs.Network, errs.Connection,
		errs.BadRequest, errs.Unexpected, errs.Cancelled}
	return errs
}
示例#13
0
// NewDefaultHealthChecker returns an instance of the default health checker
// algorithm. The default health checker tries to do a simple connection to the
// server. If the connection is successful the health check pass, otherwise it
// fails with an error. Possible proto values are tcp or udp.
func NewDefaultHealthChecker() HealthChecker {
	return HealthCheckerFunc(func(target string, port uint16, proto string) (ok bool, err error) {
		address := fmt.Sprintf("%s:%d", target, port)
		if proto != "tcp" && proto != "udp" {
			return false, net.UnknownNetworkError(proto)
		}

		conn, err := net.Dial(proto, address)
		if err != nil {
			return false, err
		}
		conn.Close()
		return true, nil
	})
}
示例#14
0
文件: udpserve.go 项目: leepro/goplay
// DialUDP connects to the remote address raddr on the network net,
// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is used
// as the local address for the connection.
func DialUDP(netType string, laddr, raddr *net.UDPAddr) (c *net.UDPConn, err os.Error) {
	switch netType {
	case "udp", "udp4", "udp6":
	default:
		return nil, net.UnknownNetworkError(netType)
	}
	if raddr == nil {
		return nil, &net.OpError{"dial", "udp", nil, errMissingAddress}
	}
	fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
	if e != nil {
		return nil, e
	}
	return newUDPConn(fd), nil
}
示例#15
0
// ListenUDT listens for incoming UDT packets addressed to the local
// address laddr.  Net must be "udt", "udt4", or "udt6".  If laddr has
// a port of 0, ListenUDT will choose an available port.
// The LocalAddr method of the returned UDTConn can be used to
// discover the port.  The returned connection's ReadFrom and WriteTo
// methods can be used to receive and send UDT packets with per-packet
// addressing.
func ListenUDT(network string, laddr *UDTAddr) (*UDTListener, error) {
	switch network {
	case "udt", "udt4", "udt6":
	default:
		return nil, &net.OpError{Op: "listen", Net: network, Addr: laddr, Err: net.UnknownNetworkError(network)}
	}
	if laddr == nil {
		laddr = &UDTAddr{addr: &net.UDPAddr{}}
	}

	fdl, err := listenFD(laddr)
	if err != nil {
		return nil, err
	}
	return &UDTListener{fd: fdl}, nil
}
示例#16
0
func Ping(IP string) (bool, error) {
	if os.Getuid() != 0 {
		return false, net.UnknownNetworkError("must be root to ping")
	}

	wait := 100 * time.Millisecond
	network := "ip4:icmp"
	seqnum := rand.Int() & (1<<16 - 1)
	id := os.Getpid() & 0xffff
	echo := newICMPv4EchoRequest(id, seqnum, 128, []byte("KT online Ping"))

	c, err := net.ListenPacket(network, "")
	if err != nil {
		return false, err
	}
	c.SetDeadline(time.Now().Add(wait))
	defer c.Close()

	ra, err := net.ResolveIPAddr(network, IP)
	if err != nil {
		return false, err
	}

	_, err = c.WriteTo(echo, ra)
	if err != nil {
		return false, err
	}

	reply := make([]byte, 256)
	for {
		_, _, err = c.ReadFrom(reply)
		if err != nil {
			if e, v := err.(*net.OpError); v && e.Timeout() {
				return false, nil
			}
			return false, err
		}
		rpType, rpCode, rid, rseqnum := parseICMPEchoReply(reply)
		if rpType == ICMP4_ECHO_REPLY &&
			rpCode == ICMP4_ECHO_X_CODE &&
			rid == id &&
			rseqnum == seqnum {
			return true, nil
		}
	}
	panic("You should not bee here!")
}
示例#17
0
// DialUDT connects to the remote address raddr on the network net,
// which must be "udt", "udt4", or "udt6".
func (d *Dialer) DialUDT(network string, raddr *UDTAddr) (*UDTConn, error) {
	switch network {
	case "udt", "udt4", "udt6":
	default:
		return nil, &net.OpError{Op: "dial", Net: network, Addr: raddr, Err: net.UnknownNetworkError(network)}
	}
	if raddr == nil {
		return nil, &net.OpError{Op: "dial", Net: network, Addr: nil, Err: errMissingAddress}
	}

	laddr, ok := d.LocalAddr.(*UDTAddr)
	if !ok {
		laddr = nil
	}

	return dialConn(laddr, raddr)
}
示例#18
0
// connect establishes a new connection using the specified transport.
func (f *Fluent) connect() (err error) {
	f.muconn.Lock()
	defer f.muconn.Unlock()

	switch f.Config.FluentNetwork {
	case "tcp":
		f.conn, err = net.DialTimeout(f.Config.FluentNetwork, f.Config.FluentHost+":"+strconv.Itoa(f.Config.FluentPort), f.Config.Timeout)
	case "unix":
		f.conn, err = net.DialTimeout(f.Config.FluentNetwork, f.Config.FluentSocketPath, f.Config.Timeout)
	default:
		err = net.UnknownNetworkError(f.Config.FluentNetwork)
	}

	if err != nil {
		f.reconnecting = false
	}
	return
}
示例#19
0
文件: net.go 项目: absolute8511/grace
// Listen announces on the local network address laddr. The network net must be
// a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". It
// returns an inherited net.Listener for the matching network and address, or
// creates a new one using net.Listen.
func (n *Net) Listen(nett, laddr string) (net.Listener, error) {
	switch nett {
	default:
		return nil, net.UnknownNetworkError(nett)
	case "tcp", "tcp4", "tcp6":
		addr, err := net.ResolveTCPAddr(nett, laddr)
		if err != nil {
			return nil, err
		}
		return n.ListenTCP(nett, addr)
	case "unix", "unixpacket", "invalid_unix_net_for_test":
		addr, err := net.ResolveUnixAddr(nett, laddr)
		if err != nil {
			return nil, err
		}
		return n.ListenUnix(nett, addr)
	}
}
示例#20
0
文件: net.go 项目: bosky101/minio
// Listen announces on the local network address laddr. The network net must be
// a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". It
// returns an inherited net.Listener for the matching network and address, or
// creates a new one using net.Listen()
func (n *nimbleNet) Listen(nett, laddr string) (net.Listener, error) {
	switch nett {
	default:
		return nil, net.UnknownNetworkError(nett)
	case "tcp", "tcp4", "tcp6":
		addr, err := net.ResolveTCPAddr(nett, laddr)
		if err != nil {
			return nil, iodine.New(err, nil)
		}
		return n.ListenTCP(nett, addr)
	case "unix", "unixpacket":
		addr, err := net.ResolveUnixAddr(nett, laddr)
		if err != nil {
			return nil, iodine.New(err, nil)
		}
		return n.ListenUnix(nett, addr)
	}
}
示例#21
0
文件: net.go 项目: nohitall/minio
// Listen announces on the local network address laddr. The network net must be
// a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". It
// returns an inherited net.Listener for the matching network and address, or
// creates a new one using net.Listen()
func (n *minNet) Listen(nett, laddr string) (net.Listener, *probe.Error) {
	switch nett {
	default:
		return nil, probe.NewError(net.UnknownNetworkError(nett))
	case "tcp", "tcp4", "tcp6":
		addr, err := net.ResolveTCPAddr(nett, laddr)
		if err != nil {
			return nil, probe.NewError(err)
		}
		return n.ListenTCP(nett, addr)
	case "unix", "unixpacket":
		addr, err := net.ResolveUnixAddr(nett, laddr)
		if err != nil {
			return nil, probe.NewError(err)
		}
		return n.ListenUnix(nett, addr)
	}
}
示例#22
0
// TestThreadedScan tests the threadedScan method.
func TestThreadedScan(t *testing.T) {
	hdb := bareHostDB()
	hdb.persist = &memPersist{}

	// use a real sleeper; this will prevent threadedScan from looping too
	// quickly.
	hdb.sleeper = stdSleeper{}
	// use a dummy dialer that always fails
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		return nil, net.UnknownNetworkError("fail")
	})

	// create a host to be scanned
	h := new(hostEntry)
	h.NetAddress = "foo"
	h.Reliability = types.NewCurrency64(1)
	hdb.activeHosts[h.NetAddress] = &hostNode{hostEntry: h}

	// perform one scan
	go hdb.threadedScan()

	// host should be sent down scanPool
	select {
	case <-hdb.scanPool:
	case <-time.After(time.Second):
		t.Error("host was not scanned")
	}

	// remove the host from activeHosts and add it to allHosts
	hdb.mu.Lock()
	delete(hdb.activeHosts, h.NetAddress)
	hdb.allHosts[h.NetAddress] = h
	hdb.mu.Unlock()

	// perform one scan
	go hdb.threadedScan()

	// host should be sent down scanPool
	select {
	case <-hdb.scanPool:
	case <-time.After(time.Second):
		t.Error("host was not scanned")
	}
}
示例#23
0
// ResolveUTPAddr parses addr as a UTP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "utp", "utp4" or
// "utp6".  A literal address or host name for IPv6 must be enclosed
// in square brackets, as in "[::1]:80", "[ipv6-host]:http" or
// "[ipv6-host%zone]:80".
func ResolveUTPAddr(net_, addr string) (*UTPAddr, error) {
	switch net_ {
	case "utp", "utp4", "utp6":
	case "":
		net_ = "utp"
	default:
		return nil, net.UnknownNetworkError(net_)
	}

	net_ = strings.Replace(net_, "d", "t", 1)
	a, err := net.ResolveUDPAddr(net_, addr)
	if err != nil {
		return nil, err
	}
	return &UTPAddr{
		IP:   a.IP,
		Port: a.Port,
		Zone: a.Zone,
	}, nil
}
示例#24
0
func SendMagicPacket(MAC string, broadcast string) error {
	broadcast = broadcast + ":" + wol_port
	packet, err := constructMagicPacket(MAC)
	if err != nil {
		return err
	}

	c, err := net.Dial("udp4", broadcast)
	if err != nil {
		return err
	}
	defer c.Close()

	written, err := c.Write(packet)
	// println("Sending magic packet to", broadcast, "with", MAC)
	if err != nil {
		return err
	}
	if written < len(packet) {
		return net.UnknownNetworkError("package not completely send")
	}
	return nil
}
示例#25
0
文件: addrs.go 项目: wptad/dvara
func resolveAddr(addr string) (net.Addr, error) {
	parts := strings.Split(addr, ":")
	if len(parts) != 3 {
		return nil, fmt.Errorf(
			`invalid address format, must be "net:host:port": %s`,
			addr,
		)
	}

	hp := parts[1] + ":" + parts[2]
	switch parts[0] {
	default:
		return nil, net.UnknownNetworkError(parts[0])
	case "ip", "ip4", "ip6":
		return net.ResolveIPAddr(parts[0], hp)
	case "tcp", "tcp4", "tcp6":
		return net.ResolveTCPAddr(parts[0], hp)
	case "udp", "udp4", "udp6":
		return net.ResolveUDPAddr(parts[0], hp)
	case "unix", "unixgram", "unixpacket":
		return net.ResolveUnixAddr(parts[0], hp)
	}
}
示例#26
0
文件: rpc.go 项目: nangong92t/go_src
// Construct a new RpcServer via string URL
// Currently supporting json RPC over unix or tcp socket
func NewRpcServer(listenURL string) (*RpcServer, error) {
	var listener net.Listener
	var cleanup func()

	url, err := url.Parse(listenURL)
	if err != nil {
		return nil, err
	}

	switch url.Scheme {
	case "tcp":
		if url.Host == "" {
			err = fmt.Errorf("Invalid URL %q", listenURL)
		} else {
			listener, err = net.Listen("tcp", url.Host)
		}
	case "", "unix":
		// If the file already exists, we need to remove it otherwise gonit can't
		// start.
		os.Remove(url.Path)
		listener, err = net.Listen("unix", url.Path)
		cleanup = func() { os.Remove(url.Path) }
	default:
		err = net.UnknownNetworkError(url.Scheme)
	}

	if err != nil {
		return nil, err
	}

	server := &RpcServer{
		listener: listener,
		cleanup:  cleanup,
	}

	return server, nil
}
示例#27
0
文件: mysql.go 项目: strogo/mymysql
func (my *Conn) connect() (err error) {
	defer catchError(&err)

	// Make connection
	switch my.proto {
	case "tcp", "tcp4", "tcp6":
		var la, ra *net.TCPAddr
		if my.laddr != "" {
			if la, err = net.ResolveTCPAddr("", my.laddr); err != nil {
				return
			}
		}
		if my.raddr != "" {
			if ra, err = net.ResolveTCPAddr("", my.raddr); err != nil {
				return
			}
		}
		if my.net_conn, err = net.DialTCP(my.proto, la, ra); err != nil {
			my.net_conn = nil
			return
		}

	case "unix":
		var la, ra *net.UnixAddr
		if my.raddr != "" {
			if ra, err = net.ResolveUnixAddr(my.proto, my.raddr); err != nil {
				return
			}
		}
		if my.laddr != "" {
			if la, err = net.ResolveUnixAddr(my.proto, my.laddr); err != nil {
				return
			}
		}
		if my.net_conn, err = net.DialUnix(my.proto, la, ra); err != nil {
			my.net_conn = nil
			return
		}

	default:
		err = net.UnknownNetworkError(my.proto)
	}

	my.rd = bufio.NewReader(my.net_conn)
	my.wr = bufio.NewWriter(my.net_conn)

	// Initialisation
	my.init()
	my.auth()
	res := my.getResult(nil, nil)
	if res == nil {
		// Try old password
		my.oldPasswd()
		res = my.getResult(nil, nil)
		if res == nil {
			return AUTHENTICATION_ERROR
		}
	}

	// Execute all registered commands
	for _, cmd := range my.init_cmds {
		// Send command
		my.sendCmd(_COM_QUERY, cmd)
		// Get command response
		res := my.getResponse()

		if res.StatusOnly() {
			// No fields in result (OK result)
			continue
		}
		// Read and discard all result rows
		row := res.MakeRow()
		for {
			err = res.getRow(row)
			if err == io.EOF {
				res, err = res.nextResult()
				if err != nil {
					return
				}
				if res == nil {
					// No more rows and results from this cmd
					break
				}
				row = res.MakeRow()
			}
			if err != nil {
				return
			}
		}
	}

	return
}
示例#28
0
func (d *Dialer) Dial(network, address string) (conn net.Conn, err error) {
	glog.V(3).Infof("Dail(%#v, %#v)", network, address)

	switch network {
	case "tcp", "tcp4", "tcp6":
		if d.DNSCache != nil {
			if addr, ok := d.DNSCache.Get(address); ok {
				address = addr.(string)
			} else {
				if host, port, err := net.SplitHostPort(address); err == nil {
					if ips, err := net.LookupIP(host); err == nil && len(ips) > 0 {
						ip := ips[0].String()
						if d.LoopbackAddrs != nil {
							if _, ok := d.LoopbackAddrs[ip]; ok {
								return nil, net.InvalidAddrError(fmt.Sprintf("Invaid DNS Record: %s(%s)", host, ip))
							}
						}
						addr := net.JoinHostPort(ip, port)
						expiry := d.DNSCacheExpiry
						if expiry == 0 {
							expiry = DefaultDNSCacheExpiry
						}
						d.DNSCache.Set(address, addr, time.Now().Add(expiry))
						glog.V(3).Infof("direct Dial cache dns %#v=%#v", address, addr)
						address = addr
					}
				}
			}
		}
	default:
		break
	}

	if d.Level <= 1 {
		retry := d.RetryTimes
		if retry == 0 {
			retry = DefaultRetryTimes
		}

		for i := 0; i < retry; i++ {
			conn, err = d.Dialer.Dial(network, address)
			if err == nil || i == retry-1 {
				break
			}
			retryDelay := d.RetryDelay
			if retryDelay == 0 {
				retryDelay = DefaultRetryDelay
			}
			time.Sleep(retryDelay)
		}
		return conn, err
	} else {
		type racer struct {
			c net.Conn
			e error
		}

		lane := make(chan racer, d.Level)
		retry := (d.RetryTimes + d.Level - 1) / d.Level
		for i := 0; i < retry; i++ {
			for j := 0; j < d.Level; j++ {
				go func(addr string, c chan<- racer) {
					conn, err := d.Dialer.Dial(network, addr)
					lane <- racer{conn, err}
				}(address, lane)
			}

			var r racer
			for k := 0; k < d.Level; k++ {
				r = <-lane
				if r.e == nil {
					go func(count int) {
						var r1 racer
						for ; count > 0; count-- {
							r1 = <-lane
							if r1.c != nil {
								r1.c.Close()
							}
						}
					}(d.Level - 1 - k)
					return r.c, nil
				}
			}

			if i == retry-1 {
				return nil, r.e
			}
		}
	}

	return nil, net.UnknownNetworkError("Unkown transport/direct error")
}
示例#29
0
func (badNetConn) Write([]byte) (int, error) {
	return 0, net.UnknownNetworkError("badNetConn")
}
示例#30
0
		if strings.IndexRune(raddr, ':') != -1 {
			proto = "tcp"
		}
	}

	// Make a connection
	d := &net.Dialer{Timeout: timeout}
	if laddr != "" {
		var err error
		switch proto {
		case "tcp", "tcp4", "tcp6":
			d.LocalAddr, err = net.ResolveTCPAddr(proto, laddr)
		case "unix":
			d.LocalAddr, err = net.ResolveTCPAddr(proto, laddr)
		default:
			err = net.UnknownNetworkError(proto)
		}
		if err != nil {
			return nil, err
		}
	}
	return d.Dial(proto, raddr)
}

func (my *Conn) SetDialer(d mysql.Dialer) {
	my.dialer = d
}

func (my *Conn) connect() (err error) {
	defer catchError(&err)