Пример #1
0
func main() {
	flag.Parse()

	klog.SetPrinter(
		klog.Chain(klog.NewFilterREST("", klog.FilterOut).AddSuffix("debug", "timeout"),
			klog.Chain(klog.NewDedup(),
				klog.Fork(
					klog.NewRingREST("", 1000),
					klog.GetPrinter()))))

	body, err := ioutil.ReadFile(*config)
	if err != nil {
		log.Fatalf("unable to read file '%s': %s", *config, err.Error())
	}

	controller := new(nfork.Controller)
	if err := json.Unmarshal(body, &controller.Inbounds); err != nil {
		log.Fatalf("unable to parse config '%s': %s", *config, err.Error())
	}

	klog.KPrintf("init.info", "starting nfork control on %s\n", *listen)
	controller.Start()

	rest.AddService(controller)
	rest.ListenAndServe(*listen, nil)
}
Пример #2
0
func (inbound *Inbound) error(title, outbound string, err error, t0 time.Time) error {

	if urlErr, ok := err.(*url.Error); ok {
		return inbound.error(title, outbound, urlErr.Err, t0)

	} else if netErr, ok := err.(*net.OpError); ok {
		if errno, ok := netErr.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED {
			klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err)
			inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)})
			return err
		}

		return inbound.error(title, outbound, netErr.Err, t0)
	}

	switch err.Error() {

	// Prevents spamming the logs with closed connections even though they were
	// not properly closed.
	case "EOF":
		inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)})
		return err

	// I hate this but net and net/http provides no useful errors or indicators
	// that a request ended up in a timeout. Furthermore, most of the errors are
	// either not exported or are just randomly created as string. In other
	// words, this is a crappy interface that needs to be fixed bad.
	case "use of closed network connection": // net.errClosing
		fallthrough
	case "net/http: transport closed before response was received":
		fallthrough
	case "net/http: request canceled while waiting for connection":
		klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err)
		inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)})
		return err
	}

	klog.KPrintf(klog.Keyf("%s.%s.%s.error", inbound.Name, outbound, title), "%T -> %v", err, err)
	inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)})
	return err
}
Пример #3
0
// ActivateOutbound activates the given outbound for the given inbound.
func (control *Controller) ActivateOutbound(inbound, outbound string) error {
	control.mutex.Lock()
	defer control.mutex.Unlock()

	server, ok := control.inbounds[inbound]
	if !ok {
		return fmt.Errorf("unknown inbound '%s'", inbound)
	}

	klog.KPrintf("controller.info", "ActivateOutbound(%s, %s)", inbound, outbound)
	return server.ActivateOutbound(outbound)
}
Пример #4
0
// NewInboundServer creates and starts a new HTTP server associated with the
// given Inbound.
func NewInboundServer(inbound *Inbound) (*InboundServer, error) {
	server := new(InboundServer)

	if err := inbound.Validate(); err != nil {
		return nil, err
	}
	inbound.Init()

	server.setInbound(inbound)

	listener, err := net.Listen("tcp", inbound.Listen)
	if err != nil {
		klog.KPrintf(klog.Keyf("%s.listen", inbound.Name), "unable to listen on %s: %s", inbound.Listen, err)
		return nil, err
	}
	server.listener = listener

	go func() {
		err := http.Serve(tcpKeepAliveListener{listener.(*net.TCPListener)}, server)
		klog.KPrintf(klog.Keyf("%s.close", server.getInbound().Name), "server closed with: %s", err)
	}()

	return server, nil
}
Пример #5
0
// RemoveInbound kills and removes the given inbound.
func (control *Controller) RemoveInbound(inbound string) error {
	control.mutex.Lock()
	defer control.mutex.Unlock()

	server, ok := control.inbounds[inbound]
	if !ok {
		return fmt.Errorf("unknown inbound '%s'", inbound)
	}

	klog.KPrintf("controller.info", "RemoveInbound(%s)", inbound)

	server.Close()
	delete(control.inbounds, inbound)

	return nil
}
Пример #6
0
// AddInbound creates a new InboundServer for the given inbound and launches it.
func (control *Controller) AddInbound(inbound *Inbound) error {
	control.mutex.Lock()
	defer control.mutex.Unlock()

	if _, ok := control.inbounds[inbound.Name]; ok {
		return fmt.Errorf("inbound '%s' already exists", inbound.Name)
	}

	server, err := NewInboundServer(inbound)
	if err != nil {
		return fmt.Errorf("unable to add inbound '%s': %s", inbound.Name, err)
	}

	klog.KPrintf("controller.info", "AddInbound(%s, %s)", inbound.Name, inbound.Listen)
	control.inbounds[inbound.Name] = server

	return nil
}