<commit_before>package proxy

import (
	"bufio"
	"context"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/getlantern/errors"
	"github.com/getlantern/netx"
	"github.com/getlantern/preconn"
	"github.com/getlantern/proxy/filters"
)

func (opts *Opts) applyHTTPDefaults() {
	// Apply defaults
	if opts.Filter == nil {
		opts.Filter = filters.FilterFunc(defaultFilter)
	}
	if opts.OnError == nil {
		opts.OnError = defaultOnError
	}
}

// Handle implements the interface Proxy
func (proxy *proxy) Handle(ctx context.Context, downstreamIn io.Reader, downstream net.Conn) (err error) {
	defer func() {
		p := recover()
		if p != nil {
			safeClose(downstream)
			err = errors.New("Recovered from panic handling connection: %v", p)
		}
	}()

	err = proxy.handle(ctx, downstreamIn, downstream, nil)
	return
}

func safeClose(conn net.Conn) {
	defer func() {
		p := recover()
		if p != nil {
			log.Errorf("Panic on closing connection: %v", p)
		}
	}()

	conn.Close()
}

func (proxy *proxy) logInitialReadError(downstream net.Conn, err error) error {
	rem := downstream.RemoteAddr()
	r := ""
	if rem != nil {
		r = rem.String()
	}
	// Ignore our generated error that should have already been reported.
	if !strings.HasPrefix(err.Error(), "Client Hello has no cipher suites") {
		// These errors should all typically be internal go errors, typically with
		// TLS. We don't add our own messaging here to make it more likely we and
		// stackdriver can properly group them.
		return log.Errorf("%v from %s", err, r)
	}
	return err
}

func (proxy *proxy) handle(ctx context.Context, downstreamIn io.Reader, downstream net.Conn, upstream net.Conn) error {
	defer func() {
		if closeErr := downstream.Close(); closeErr != nil {
			log.Tracef("Error closing downstream connection: %s", closeErr)
		}
	}()

	downstreamBuffered := bufio.NewReader(downstreamIn)
	fctx := filters.WrapContext(withAwareConn(ctx), downstream)

	// Read initial request
	req, err := http.ReadRequest(downstreamBuffered)
	if req != nil {
		remoteAddr := downstream.RemoteAddr()
		if remoteAddr != nil {
			req.RemoteAddr = downstream.RemoteAddr().String()
		}
		if origURLScheme(ctx) == "" {
			fctx = fctx.
				WithValue(ctxKeyOrigURLScheme, req.URL.Scheme).
				WithValue(ctxKeyOrigURLHost, req.URL.Host).
				WithValue(ctxKeyOrigHost, req.Host)
		}
	}

	if err != nil {
		if isUnexpected(err) {
			errResp := proxy.OnError(fctx, req, true, err)
			if errResp != nil {
				proxy.writeResponse(downstream, req, errResp)
			}

			return proxy.logInitialReadError(downstream, err)
		}
		return nil
	}

	var next filters.Next
	if req.Method == http.MethodConnect {
		next = proxy.nextCONNECT(downstream)
	} else {
		var tr *http.Transport
		if upstream != nil {
			setUpstreamForAwareConn(fctx, upstream)
			tr = &http.Transport{
				DialContext: func(ctx context.Context, net, addr string) (net.Conn, error) {
					// always use the supplied upstream connection, but don't allow it to
					// be closed by the transport
					return &noCloseConn{upstream}, nil
				},
				// this transport is only used once, don't keep any idle connections,
				// however still allow the transport to close the connection after using
				// it
				MaxIdleConnsPerHost: -1,
			}
		} else {
			tr = &http.Transport{
				DialContext: func(ctx context.Context, net, addr string) (net.Conn, error) {
					conn, err := proxy.Dial(ctx, false, net, addr)
					if err == nil {
						// On first dialing conn, handle RequestAware
						setUpstreamForAwareConn(ctx, conn)
						handleRequestAware(ctx)
					}
					return conn, err
				},
				IdleConnTimeout: proxy.IdleTimeout,
				// since we have one transport per downstream connection, we don't need
				// more than this
				MaxIdleConnsPerHost: 1,
			}
		}

		defer tr.CloseIdleConnections()
		next = func(ctx filters.Context, modifiedReq *http.Request) (*http.Response, filters.Context, error) {
			modifiedReq = modifiedReq.WithContext(ctx)
			setRequestForAwareConn(ctx, modifiedReq)
			handleRequestAware(ctx)
			resp, err := tr.RoundTrip(prepareRequest(modifiedReq))
			handleResponseAware(ctx, modifiedReq, resp, err)
			if err != nil {
				err = errors.New("Unable to round-trip http request to upstream: %v", err)
			}
			return resp, ctx, err
		}
	}

	return proxy.processRequests(fctx, req.RemoteAddr, req, downstream, downstreamBuffered, next)
}

func (proxy *proxy) processRequests(ctx filters.Context, remoteAddr string, req *http.Request, downstream net.Conn, downstreamBuffered *bufio.Reader, next filters.Next) error {
	var readErr error
	var resp *http.Response
	var err error

	for {
		if req.URL.Scheme == "" {
			req.URL.Scheme = origURLScheme(ctx)
		}
		if req.URL.Host == "" {
			req.URL.Host = origURLHost(ctx)
		}
		if req.Host == "" {
			req.Host = origHost(ctx)
		}
		resp, ctx, err = proxy.Filter.Apply(ctx, req, next)
		if err != nil && resp == nil {
			resp = proxy.OnError(ctx, req, false, err)
			if resp != nil {
				// On error, we will always close the connection
				resp.Close = true
			}
		}

		if resp != nil {
			writeErr := proxy.writeResponse(downstream, req, resp)
			if writeErr != nil {
				if isUnexpected(writeErr) {
					return log.Errorf("Unable to write response to downstream: %v", writeErr)
				}
				// Error is not unexpected, but we're done
				return err
			}
		}

		if err != nil {
			// We encountered an error on round-tripping, stop now
			return err
		}

		upstream := upstreamConn(ctx)
		upstreamAddr := upstreamAddr(ctx)
		isConnect := upstream != nil || upstreamAddr != ""

		buffered := downstreamBuffered.Buffered()
		if buffered > 0 {
			b, _ := downstreamBuffered.Peek(buffered)
			downstream = preconn.Wrap(downstream, b)
		}

		if isConnect {
			return proxy.proceedWithConnect(ctx, req, upstreamAddr, upstream, downstream)
		}

		if req.Close {
			// Client signaled that they would close the connection after this
			// request, finish
			return err
		}

		if err == nil && resp != nil && resp.Close {
			// Last response, finish
			return err
		}

		// read the next request
		req, readErr = http.ReadRequest(downstreamBuffered)
		if readErr != nil {
			if isUnexpected(readErr) {
				errResp := proxy.OnError(ctx, req, true, readErr)
				if errResp != nil {
					proxy.writeResponse(downstream, req, errResp)
				}
				return log.Errorf("Unable to read next request from downstream: %v", readErr)
			}
			return err
		}

		// Preserve remote address from original request
		ctx = ctx.IncrementRequestNumber()
		req.RemoteAddr = remoteAddr
		req = req.WithContext(ctx)
	}
}

func handleRequestAware(ctx context.Context) {
	upstream := upstreamForAwareConn(ctx)
	if upstream == nil {
		return
	}

	netx.WalkWrapped(upstream, func(wrapped net.Conn) bool {
		switch t := wrapped.(type) {
		case RequestAware:
			req := requestForAwareConn(ctx)
			t.OnRequest(req)
		}
		return true
	})
}

func handleResponseAware(ctx context.Context, req *http.Request, resp *http.Response, err error) {
	upstream := upstreamForAwareConn(ctx)
	if upstream == nil {
		return
	}

	netx.WalkWrapped(upstream, func(wrapped net.Conn) bool {
		switch t := wrapped.(type) {
		case ResponseAware:
			t.OnResponse(req, resp, err)
		}
		return true
	})
}

func (proxy *proxy) writeResponse(downstream io.Writer, req *http.Request, resp *http.Response) error {
	if resp.Request == nil {
		resp.Request = req
	}
	out := downstream
	if resp.ProtoMajor == 0 {
		resp.ProtoMajor = 1
		resp.ProtoMinor = 1
	}
	belowHTTP11 := !resp.ProtoAtLeast(1, 1)
	if belowHTTP11 && resp.StatusCode < 200 {
		// HTTP 1.0 doesn't define status codes below 200, discard response
		// see http://coad.measurement-factory.com/cgi-bin/coad/SpecCgi?spec_id=rfc2616#excerpt/rfc2616/859a092cb26bde76c25284196171c94d
		out = ioutil.Discard
	} else {
		resp = prepareResponse(resp, belowHTTP11)
		proxy.addIdleKeepAlive(resp.Header)
	}
	err := resp.Write(out)
	// resp.Write closes the body only if it's successfully sent. Close
	// manually when error happens.
	if err != nil && resp.Body != nil {
		resp.Body.Close()
	}
	return err
}

// prepareRequest prepares the request in line with the HTTP spec for proxies.
func prepareRequest(req *http.Request) *http.Request {
	req.Proto = "HTTP/1.1"
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	// Overwrite close flag: keep persistent connection for the backend servers
	req.Close = false

	// Request Header
	newHeader := make(http.Header)
	copyHeadersForForwarding(newHeader, req.Header)
	// Ensure we have a HOST header (important for Go 1.6+ because http.Server
	// strips the HOST header from the inbound request)
	newHeader.Set("Host", req.Host)
	req.Header = newHeader

	// Request URL
	req.URL = cloneURL(req.URL)
	// If req.URL.Scheme was blank, it's http. Otherwise, it's https and we leave
	// it alone.
	if req.URL.Scheme == "" {
		req.URL.Scheme = "http"
	}
	// We need to make sure the host is defined in the URL (not the actual URI)
	req.URL.Host = req.Host

	userAgent := req.UserAgent()
	if userAgent == "" {
		req.Header.Del("User-Agent")
	} else {
		req.Header.Set("User-Agent", userAgent)
	}

	return req
}

// prepareResponse prepares the response in line with the HTTP spec
func prepareResponse(resp *http.Response, belowHTTP11 bool) *http.Response {
	origHeader := resp.Header
	resp.Header = make(http.Header)
	copyHeadersForForwarding(resp.Header, origHeader)
	// Below added due to CoAdvisor test failure
	if resp.Header.Get("Date") == "" {
		resp.Header.Set("Date", time.Now().Format(time.RFC850))
	}
	if belowHTTP11 {
		// Also, make sure we're not sending chunked transfer encoding to 1.0 clients
		resp.TransferEncoding = nil
	}
	return resp
}

// cloneURL provides update safe copy by avoiding shallow copying User field
func cloneURL(i *url.URL) *url.URL {
	out := *i
	if i.User != nil {
		out.User = &(*i.User)
	}
	return &out
}

// copyHeadersForForwarding will copy the headers but filter those that shouldn't be
// forwarded
func copyHeadersForForwarding(dst, src http.Header) {
	var extraHopByHopHeaders []string
	for k, vv := range src {
		switch k {
		// Skip hop-by-hop headers, ref section 13.5.1 of http://www.ietf.org/rfc/rfc2616.txt
		case "Connection":
			// section 14.10 of rfc2616
			// the slice is short typically, don't bother sort it to speed up lookup
			extraHopByHopHeaders = vv
		case "Keep-Alive":
		case "Proxy-Authenticate":
		case "Proxy-Authorization":
		case "TE":
		case "Trailers":
		case "Transfer-Encoding":
		case "Upgrade":
		default:
			if !contains(k, extraHopByHopHeaders) {
				for _, v := range vv {
					dst.Add(k, v)
				}
			}
		}
	}
}

func contains(k string, s []string) bool {
	for _, h := range s {
		if k == h {
			return true
		}
	}
	return false
}

func isUnexpected(err error) bool {
	if err == nil {
		return false
	}
	if err == io.EOF {
		return false
	}
	// This is okay per the HTTP spec.
	// See https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4
	if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
		return false
	}

	text := err.Error()
	return !strings.HasSuffix(text, "EOF") &&
		!strings.Contains(text, "i/o timeout") &&
		!strings.Contains(text, "Use of idled network connection") &&
		!strings.Contains(text, "use of closed network connection") &&
		// usually caused by client disconnecting
		!strings.Contains(text, "broken pipe") &&
		// usually caused by client disconnecting
		!strings.Contains(text, "connection reset by peer")
}

func defaultFilter(ctx filters.Context, req *http.Request, next filters.Next) (*http.Response, filters.Context, error) {
	return next(ctx, req)
}

func defaultOnError(ctx filters.Context, req *http.Request, read bool, err error) *http.Response {
	return nil
}
<commit_msg>More error logging tweaks<commit_after>package proxy

import (
	"bufio"
	"context"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/getlantern/errors"
	"github.com/getlantern/netx"
	"github.com/getlantern/preconn"
	"github.com/getlantern/proxy/filters"
)

func (opts *Opts) applyHTTPDefaults() {
	// Apply defaults
	if opts.Filter == nil {
		opts.Filter = filters.FilterFunc(defaultFilter)
	}
	if opts.OnError == nil {
		opts.OnError = defaultOnError
	}
}

// Handle implements the interface Proxy
func (proxy *proxy) Handle(ctx context.Context, downstreamIn io.Reader, downstream net.Conn) (err error) {
	defer func() {
		p := recover()
		if p != nil {
			safeClose(downstream)
			err = errors.New("Recovered from panic handling connection: %v", p)
		}
	}()

	err = proxy.handle(ctx, downstreamIn, downstream, nil)
	return
}

func safeClose(conn net.Conn) {
	defer func() {
		p := recover()
		if p != nil {
			log.Errorf("Panic on closing connection: %v", p)
		}
	}()

	conn.Close()
}

func (proxy *proxy) logInitialReadError(downstream net.Conn, err error) error {
	rem := downstream.RemoteAddr()
	r := ""
	if rem != nil {
		r = rem.String()
	}
	// Ignore our generated error that should have already been reported.
	if strings.HasPrefix(err.Error(), "Client Hello has no cipher suites") {
		log.Debugf("No cipher suites in common -- old Lantern client")
		return err
	}
	// These errors should all typically be internal go errors, typically with TLS.
	return log.Errorf("Initial ReadRequest: %v from %v", err, r)
}

func (proxy *proxy) handle(ctx context.Context, downstreamIn io.Reader, downstream net.Conn, upstream net.Conn) error {
	defer func() {
		if closeErr := downstream.Close(); closeErr != nil {
			log.Tracef("Error closing downstream connection: %s", closeErr)
		}
	}()

	downstreamBuffered := bufio.NewReader(downstreamIn)
	fctx := filters.WrapContext(withAwareConn(ctx), downstream)

	// Read initial request
	req, err := http.ReadRequest(downstreamBuffered)
	if req != nil {
		remoteAddr := downstream.RemoteAddr()
		if remoteAddr != nil {
			req.RemoteAddr = downstream.RemoteAddr().String()
		}
		if origURLScheme(ctx) == "" {
			fctx = fctx.
				WithValue(ctxKeyOrigURLScheme, req.URL.Scheme).
				WithValue(ctxKeyOrigURLHost, req.URL.Host).
				WithValue(ctxKeyOrigHost, req.Host)
		}
	}

	if err != nil {
		if isUnexpected(err) {
			errResp := proxy.OnError(fctx, req, true, err)
			if errResp != nil {
				proxy.writeResponse(downstream, req, errResp)
			}

			return proxy.logInitialReadError(downstream, err)
		}
		return nil
	}

	var next filters.Next
	if req.Method == http.MethodConnect {
		next = proxy.nextCONNECT(downstream)
	} else {
		var tr *http.Transport
		if upstream != nil {
			setUpstreamForAwareConn(fctx, upstream)
			tr = &http.Transport{
				DialContext: func(ctx context.Context, net, addr string) (net.Conn, error) {
					// always use the supplied upstream connection, but don't allow it to
					// be closed by the transport
					return &noCloseConn{upstream}, nil
				},
				// this transport is only used once, don't keep any idle connections,
				// however still allow the transport to close the connection after using
				// it
				MaxIdleConnsPerHost: -1,
			}
		} else {
			tr = &http.Transport{
				DialContext: func(ctx context.Context, net, addr string) (net.Conn, error) {
					conn, err := proxy.Dial(ctx, false, net, addr)
					if err == nil {
						// On first dialing conn, handle RequestAware
						setUpstreamForAwareConn(ctx, conn)
						handleRequestAware(ctx)
					}
					return conn, err
				},
				IdleConnTimeout: proxy.IdleTimeout,
				// since we have one transport per downstream connection, we don't need
				// more than this
				MaxIdleConnsPerHost: 1,
			}
		}

		defer tr.CloseIdleConnections()
		next = func(ctx filters.Context, modifiedReq *http.Request) (*http.Response, filters.Context, error) {
			modifiedReq = modifiedReq.WithContext(ctx)
			setRequestForAwareConn(ctx, modifiedReq)
			handleRequestAware(ctx)
			resp, err := tr.RoundTrip(prepareRequest(modifiedReq))
			handleResponseAware(ctx, modifiedReq, resp, err)
			if err != nil {
				err = errors.New("Unable to round-trip http request to upstream: %v", err)
			}
			return resp, ctx, err
		}
	}

	return proxy.processRequests(fctx, req.RemoteAddr, req, downstream, downstreamBuffered, next)
}

func (proxy *proxy) processRequests(ctx filters.Context, remoteAddr string, req *http.Request, downstream net.Conn, downstreamBuffered *bufio.Reader, next filters.Next) error {
	var readErr error
	var resp *http.Response
	var err error

	for {
		if req.URL.Scheme == "" {
			req.URL.Scheme = origURLScheme(ctx)
		}
		if req.URL.Host == "" {
			req.URL.Host = origURLHost(ctx)
		}
		if req.Host == "" {
			req.Host = origHost(ctx)
		}
		resp, ctx, err = proxy.Filter.Apply(ctx, req, next)
		if err != nil && resp == nil {
			resp = proxy.OnError(ctx, req, false, err)
			if resp != nil {
				// On error, we will always close the connection
				resp.Close = true
			}
		}

		if resp != nil {
			writeErr := proxy.writeResponse(downstream, req, resp)
			if writeErr != nil {
				if isUnexpected(writeErr) {
					return log.Errorf("Unable to write response to downstream: %v", writeErr)
				}
				// Error is not unexpected, but we're done
				return err
			}
		}

		if err != nil {
			// We encountered an error on round-tripping, stop now
			return err
		}

		upstream := upstreamConn(ctx)
		upstreamAddr := upstreamAddr(ctx)
		isConnect := upstream != nil || upstreamAddr != ""

		buffered := downstreamBuffered.Buffered()
		if buffered > 0 {
			b, _ := downstreamBuffered.Peek(buffered)
			downstream = preconn.Wrap(downstream, b)
		}

		if isConnect {
			return proxy.proceedWithConnect(ctx, req, upstreamAddr, upstream, downstream)
		}

		if req.Close {
			// Client signaled that they would close the connection after this
			// request, finish
			return err
		}

		if err == nil && resp != nil && resp.Close {
			// Last response, finish
			return err
		}

		// read the next request
		req, readErr = http.ReadRequest(downstreamBuffered)
		if readErr != nil {
			if isUnexpected(readErr) {
				errResp := proxy.OnError(ctx, req, true, readErr)
				if errResp != nil {
					proxy.writeResponse(downstream, req, errResp)
				}
				return log.Errorf("Unable to read next request from downstream: %v", readErr)
			}
			return err
		}

		// Preserve remote address from original request
		ctx = ctx.IncrementRequestNumber()
		req.RemoteAddr = remoteAddr
		req = req.WithContext(ctx)
	}
}

func handleRequestAware(ctx context.Context) {
	upstream := upstreamForAwareConn(ctx)
	if upstream == nil {
		return
	}

	netx.WalkWrapped(upstream, func(wrapped net.Conn) bool {
		switch t := wrapped.(type) {
		case RequestAware:
			req := requestForAwareConn(ctx)
			t.OnRequest(req)
		}
		return true
	})
}

func handleResponseAware(ctx context.Context, req *http.Request, resp *http.Response, err error) {
	upstream := upstreamForAwareConn(ctx)
	if upstream == nil {
		return
	}

	netx.WalkWrapped(upstream, func(wrapped net.Conn) bool {
		switch t := wrapped.(type) {
		case ResponseAware:
			t.OnResponse(req, resp, err)
		}
		return true
	})
}

func (proxy *proxy) writeResponse(downstream io.Writer, req *http.Request, resp *http.Response) error {
	if resp.Request == nil {
		resp.Request = req
	}
	out := downstream
	if resp.ProtoMajor == 0 {
		resp.ProtoMajor = 1
		resp.ProtoMinor = 1
	}
	belowHTTP11 := !resp.ProtoAtLeast(1, 1)
	if belowHTTP11 && resp.StatusCode < 200 {
		// HTTP 1.0 doesn't define status codes below 200, discard response
		// see http://coad.measurement-factory.com/cgi-bin/coad/SpecCgi?spec_id=rfc2616#excerpt/rfc2616/859a092cb26bde76c25284196171c94d
		out = ioutil.Discard
	} else {
		resp = prepareResponse(resp, belowHTTP11)
		proxy.addIdleKeepAlive(resp.Header)
	}
	err := resp.Write(out)
	// resp.Write closes the body only if it's successfully sent. Close
	// manually when error happens.
	if err != nil && resp.Body != nil {
		resp.Body.Close()
	}
	return err
}

// prepareRequest prepares the request in line with the HTTP spec for proxies.
func prepareRequest(req *http.Request) *http.Request {
	req.Proto = "HTTP/1.1"
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	// Overwrite close flag: keep persistent connection for the backend servers
	req.Close = false

	// Request Header
	newHeader := make(http.Header)
	copyHeadersForForwarding(newHeader, req.Header)
	// Ensure we have a HOST header (important for Go 1.6+ because http.Server
	// strips the HOST header from the inbound request)
	newHeader.Set("Host", req.Host)
	req.Header = newHeader

	// Request URL
	req.URL = cloneURL(req.URL)
	// If req.URL.Scheme was blank, it's http. Otherwise, it's https and we leave
	// it alone.
	if req.URL.Scheme == "" {
		req.URL.Scheme = "http"
	}
	// We need to make sure the host is defined in the URL (not the actual URI)
	req.URL.Host = req.Host

	userAgent := req.UserAgent()
	if userAgent == "" {
		req.Header.Del("User-Agent")
	} else {
		req.Header.Set("User-Agent", userAgent)
	}

	return req
}

// prepareResponse prepares the response in line with the HTTP spec
func prepareResponse(resp *http.Response, belowHTTP11 bool) *http.Response {
	origHeader := resp.Header
	resp.Header = make(http.Header)
	copyHeadersForForwarding(resp.Header, origHeader)
	// Below added due to CoAdvisor test failure
	if resp.Header.Get("Date") == "" {
		resp.Header.Set("Date", time.Now().Format(time.RFC850))
	}
	if belowHTTP11 {
		// Also, make sure we're not sending chunked transfer encoding to 1.0 clients
		resp.TransferEncoding = nil
	}
	return resp
}

// cloneURL provides update safe copy by avoiding shallow copying User field
func cloneURL(i *url.URL) *url.URL {
	out := *i
	if i.User != nil {
		out.User = &(*i.User)
	}
	return &out
}

// copyHeadersForForwarding will copy the headers but filter those that shouldn't be
// forwarded
func copyHeadersForForwarding(dst, src http.Header) {
	var extraHopByHopHeaders []string
	for k, vv := range src {
		switch k {
		// Skip hop-by-hop headers, ref section 13.5.1 of http://www.ietf.org/rfc/rfc2616.txt
		case "Connection":
			// section 14.10 of rfc2616
			// the slice is short typically, don't bother sort it to speed up lookup
			extraHopByHopHeaders = vv
		case "Keep-Alive":
		case "Proxy-Authenticate":
		case "Proxy-Authorization":
		case "TE":
		case "Trailers":
		case "Transfer-Encoding":
		case "Upgrade":
		default:
			if !contains(k, extraHopByHopHeaders) {
				for _, v := range vv {
					dst.Add(k, v)
				}
			}
		}
	}
}

func contains(k string, s []string) bool {
	for _, h := range s {
		if k == h {
			return true
		}
	}
	return false
}

func isUnexpected(err error) bool {
	if err == nil {
		return false
	}
	if err == io.EOF {
		return false
	}
	// This is okay per the HTTP spec.
	// See https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4
	if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
		return false
	}

	text := err.Error()
	return !strings.HasSuffix(text, "EOF") &&
		!strings.Contains(text, "i/o timeout") &&
		!strings.Contains(text, "Use of idled network connection") &&
		!strings.Contains(text, "use of closed network connection") &&
		// usually caused by client disconnecting
		!strings.Contains(text, "broken pipe") &&
		// usually caused by client disconnecting
		!strings.Contains(text, "connection reset by peer")
}

func defaultFilter(ctx filters.Context, req *http.Request, next filters.Next) (*http.Response, filters.Context, error) {
	return next(ctx, req)
}

func defaultOnError(ctx filters.Context, req *http.Request, read bool, err error) *http.Response {
	return nil
}
<|endoftext|>


<commit_before>package deemon

import (
	"fmt"
	//d "github.com/sevlyar/go-daemon"
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path"
	"runtime/debug"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const (
	MARK_KEY            = "_DEEMON_PROC_TYPE_"
	MARK_CHILD          = "CHILD"
	MARK_WATCHDOG       = "WATCHDOG"
	MARK_STARTER        = "STARTER"
	DefaultMaxKillRetry = 10
)

type Config struct {
	Pidfile string
	Logfile string
	Workdir string
}

var defaultConfig Config

func init() {
	flag.StringVar(&defaultConfig.Pidfile, "pidfile", "", "Location of the pidfile.")
	flag.StringVar(&defaultConfig.Logfile, "logfile", "", "Location of the logfile.")
	flag.StringVar(&defaultConfig.Workdir, "workdir", "", "Location of the working directory to change to.")
}

// The loop is only restarted if none of the Handler implementations return an error != nil.
type StartFunc func() error
type ReturnHandlerFunc func(error) error
type SignalHandlerFunc func(os.Signal) error
type PanicHandlerFunc func(interface{}) error
type ExitHandlerFunc func(*os.ProcessState) error
type AnyHandlerFunc func(error) error

type Context struct {
	Config

	UseWatchdog  bool
	MaxKillRetry int

	OnExit   ExitHandlerFunc
	OnPanic  PanicHandlerFunc
	OnSignal SignalHandlerFunc
	OnReturn ReturnHandlerFunc
	OnAny    AnyHandlerFunc

	DefaultOnExit   ExitHandlerFunc
	DefaultOnPanic  PanicHandlerFunc
	DefaultOnSignal SignalHandlerFunc
	DefaultOnReturn ReturnHandlerFunc
	DefaultOnAny    AnyHandlerFunc

	Start StartFunc

	Name     string
	MustRun  time.Duration
	ptype    string
	rchild   *os.Process
	watchdog *os.Process
	lf       *os.File
}

func Launch(s StartFunc, args ...interface{}) (ctx *Context, err error) {
	c := NewContext(s, args...)
	err = c.Launch()
	if err != nil {
		c.Logf("error: %s", err)
	}
	return c, err
}

func NewContext(s StartFunc, args ...interface{}) *Context {

	//determin which kind of proc this is.
	ptype := os.Getenv(MARK_KEY)
	if len(ptype) == 0 {
		ptype = MARK_STARTER
	}

	name := path.Base(os.Args[0])

	var ret *Context
	ret = &Context{
		Config:       defaultConfig,
		rchild:       nil,
		ptype:        ptype,
		Name:         name,
		MaxKillRetry: DefaultMaxKillRetry,
		DefaultOnExit: func(state *os.ProcessState) error {
			ret.Logf("onExit %s", state.String())
			return nil
		},
		DefaultOnPanic: func(i interface{}) error {
			ret.Logf("onPanic %s", i)
			debug.PrintStack()
			return nil
		},
		DefaultOnReturn: func(err error) error {
			ret.Logf("onReturn %s", err)
			return nil
		},
		DefaultOnSignal: func(sig os.Signal) error {
			ret.Logf("onSignal %s", sig)
			return ret.Errorf("exiting due to sig %s", sig)
		},
		DefaultOnAny: func(err error) error {
			return err
		},
		Start:   s,
		MustRun: time.Second * 1,
	}

	if len(ret.Config.Pidfile) <= 0 {
		ret.Config.Pidfile = name + ".pid"
	}

	if len(ret.Config.Logfile) <= 0 {
		ret.Config.Logfile = name + ".log"
	}

	ret.OnExit = ret.DefaultOnExit
	ret.OnPanic = ret.DefaultOnPanic
	ret.OnReturn = ret.DefaultOnReturn
	ret.OnSignal = ret.DefaultOnSignal
	ret.OnAny = ret.DefaultOnAny

	for _, m := range args {
		if v, ok := m.(ReturnHandlerFunc); ok {
			ret.Logf("registering ReturnHandler")
			ret.OnReturn = v
		}

		if v, ok := m.(PanicHandlerFunc); ok {
			ret.Logf("registering PanicHandler")
			ret.OnPanic = v
		}

		if v, ok := m.(SignalHandlerFunc); ok {
			ret.Logf("registering SignalHandler")
			ret.OnSignal = v
		}

		if v, ok := m.(ExitHandlerFunc); ok {
			ret.Logf("registering ExitHandler")
			ret.OnExit = v
		}

		if v, ok := m.(AnyHandlerFunc); ok {
			ret.Logf("registering AnyHandler")
			ret.OnAny = v
		}
	}

	ret.readPidfile()
	return ret
}

func (c *Context) doChild() error {
	c.Logf("doChild")
	ret := make(chan error, 1)

	run := true
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT)

	for run {
		laststart := time.Now()
		go func() {
			var err error
			defer func() {
				if r := recover(); r != nil {
					err = c.OnPanic(r)
				}
				ret <- err
			}()
			c.Logf("starting Start() routine")
			err = c.Start()
		}()

		var err error
		select {
		case err := <-ret: // START returned an error
			err = c.OnReturn(err)

		case sig := <-sc: // A Termination signal was catched
			err = c.OnSignal(sig)
		}
		err = c.OnAny(err)
		if err != nil {
			return c.Errorf("exiting due to error in handler: '%s'", err)
		}

		delta := time.Now().Sub(laststart)
		if delta < c.MustRun {
			log.Fatalf("returned within %.3f seconds. Assuming startup error. Aborted.", delta.Seconds())
		}

		c.Logf("restarting: %s %s", c.Name, c.ptype)
	}
	return nil
}

func (c *Context) doWatchdog() (err error) {
	proc, err := os.FindProcess(os.Getpid())
	if err != nil {
		return
	}
	c.watchdog = proc

	defer c.close()
	run := true

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT)
	go func() {
		sig := <-sc
		c.Logf("received signal %d", sig)
		run = false
		if c.rchild != nil {
			c.Logf("pass signal %d to PID=%d", sig, c.rchild.Pid)
			c.rchild.Signal(sig) //  Pass the same signal to the child
		}
	}()

	for run {
		laststart := time.Now()

		err = c.restartAs(MARK_CHILD)
		if err != nil {
			return
		}

		err = ioutil.WriteFile(c.Pidfile, []byte(fmt.Sprintf("%d\n%d", c.rchild.Pid, os.Getpid())), 0644)
		if err != nil {
			return
		}

		c.Logf("observing")
		state, err := c.rchild.Wait()
		if err != nil {
			return err
		}

		delta := time.Now().Sub(laststart)
		if delta < c.MustRun {
			return c.Errorf("child returned within %.3f seconds", delta.Seconds)
		}
		err = c.OnExit(state)
		if err != nil {
			err = c.Errorf("exiting due to error in 'onExit' handler: '%s'", err)
			log.Print(err)
			return err
		}

		if run {
			c.Logf("restarting child")
		}
	}
	return nil
}

func (c *Context) restartAs(mark string) (err error) {
	oe := os.Environ()
	ne := make([]string, 0)

	for _, e := range oe {
		if !strings.HasPrefix(e, MARK_KEY) {
			ne = append(ne, e)
		}
	}
	ne = append(ne, fmt.Sprintf("%s=%s", MARK_KEY, mark))

	attr := &os.ProcAttr{
		Dir: c.Config.Workdir,
		Env: ne,
		Files: []*os.File{
			os.Stdin,
			c.lf,
			c.lf,
		},
		Sys: &syscall.SysProcAttr{
			Setsid: true,
		},
	}

	c.Logf("restarting to %s", mark)
	child, err := os.StartProcess(os.Args[0], os.Args, attr)
	if err != nil {
		return err
	}

	if child == nil {
		return c.Errorf("child should never become a same proc type: %s,%s", c.Name, c.ptype)
	}
	c.rchild = child

	return err
}

func (c *Context) doStarter() (err error) {
	//TODO: check for UseWatchdog
	err = c.restartAs(MARK_WATCHDOG)
	if err != nil {
		return
	}

	c.Logf("Starter done. Please find logs at '%s'", c.Logfile)
	return nil
}

func (c *Context) close() error {
	c.lf.Close()
	return os.Remove(c.Pidfile)
}

func (c *Context) Launch() (err error) {
	c.lf, err = os.OpenFile(c.Config.Logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		return err
	}

	/* route proc type */
	switch c.ptype {
	case MARK_CHILD:
		log.SetOutput(c.lf)
		err = c.doChild()
		c.Logf("Exiting: %s", err)
		os.Exit(0)
	case MARK_WATCHDOG:
		c.Logf("Starting. Writing logs to: '%s'", c.Logfile)
		log.SetOutput(c.lf)
		err = c.doWatchdog()
		c.Logf("Exiting: %s", err)
		os.Exit(0)
	case MARK_STARTER:
		return c.doStarter()
	default:
		return c.Errorf("unknown proc type: %s", c.ptype)
	}
	return nil
}

func (c *Context) Logf(pat string, args ...interface{}) {
	log.Printf("[%s|%s|%d] "+pat, append([]interface{}{c.Name, c.ptype, os.Getpid()}, args...)...)
}

func (c *Context) Errorf(pat string, args ...interface{}) error {
	return fmt.Errorf("[%s|%s|%d] "+pat, append([]interface{}{c.Name, c.ptype, os.Getpid()}, args...)...)
}

func (c *Context) readPidfile() error {
	c.rchild = nil
	c.watchdog = nil

	data, err := ioutil.ReadFile(c.Config.Pidfile)
	if err != nil {
		return nil
	}

	sb := bytes.Split(data, []byte{'\n'})
	if len(sb) >= 1 {
		cpid, err := strconv.Atoi(string(sb[0]))
		if err != nil {
			return err
		}

		proc, _ := os.FindProcess(cpid)
		c.rchild = proc
	}

	if len(sb) >= 2 {
		wdpid, err := strconv.Atoi(string(sb[1]))
		if err != nil {
			return err
		}
		proc, _ := os.FindProcess(wdpid)
		c.watchdog = proc
	}

	return nil
}

func (c *Context) Kill() error {
	return c.kill(syscall.SIGKILL)
}

func (c *Context) Stop() error {
	return c.kill(syscall.SIGTERM)
}

func (c *Context) kill(sig os.Signal) error {
	for i := 0; i < c.MaxKillRetry; i++ {
		c.readPidfile()

		if c.IsDown() {
			return nil
		}

		if c.watchdog != nil {
			c.Logf("Sending %s to watchdog PID=%d", sig, c.watchdog.Pid)
			c.watchdog.Signal(syscall.SIGTERM) // Never send the watchdog a kill
		}

		if c.rchild != nil {
			c.Logf("Sending %s to child PID=%d", sig, c.rchild.Pid)
			c.rchild.Signal(sig)
		}
		time.Sleep(time.Second * 1)
	}

	return c.Errorf("Could not stop process '%s' after %d retries.", c.Name, c.MaxKillRetry)
}

func (c *Context) IsRunning() bool {
	return (c.rchild != nil && c.watchdog != nil)
}

func (c *Context) IsDown() bool {
	return (c.rchild == nil && c.watchdog == nil)
}

func (c *Context) amITheChild() bool {
	if c.rchild != nil {
		return c.rchild.Pid == os.Getpid()
	}
	return false
}

func Command(cmd string, s StartFunc, fs ...interface{}) (ctx *Context, err error) {
	ctx = NewContext(s, fs...)
	if ctx == nil {
		return nil, fmt.Errorf("Could not create context.")
	}
	err = ctx.Command(cmd)
	return ctx, err
}

func PrintUsage() {
	fmt.Fprintf(os.Stderr, `
usage: %s [flags...] <target>

Targets:
--------
	start		Start the service.
	stop		Stop the service.
	kill		Kill the service.
	status		Print if service is running.

Flags:
------
`, os.Args[0])
	flag.PrintDefaults()
}

func (c *Context) Command(cmd string) (err error) {
	c.readPidfile()
	cm := strings.ToLower(cmd)
	running := c.IsRunning()
	switch cm {
	case "stop":
		if !running {
			return
		}
		return c.Stop()
	case "kill":
		if !running {
			return
		}
		return c.Kill()
	case "start":
		if !running || c.amITheChild() {
			return c.Launch()
		} else {
			c.Logf("Already Running")
			return c.Errorf("Service already running.")
		}
	case "status":
		if running {
			c.Logf("Service %s is running at PID=%d,%d\n", c.Name, c.watchdog.Pid, c.rchild.Pid)

			/* TODO: Send SIG INFO/STATUS to child process */
			return nil
		} else {
			return c.Errorf("Service %s is not running", c.Name)
		}
		flag.PrintDefaults()
	default:
		return c.Errorf("unknown command: %s", cmd)
	}
	return
}
<commit_msg>Fixed err shadow bug.<commit_after>package deemon

import (
	"fmt"
	//d "github.com/sevlyar/go-daemon"
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path"
	"runtime/debug"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const (
	MARK_KEY            = "_DEEMON_PROC_TYPE_"
	MARK_CHILD          = "CHILD"
	MARK_WATCHDOG       = "WATCHDOG"
	MARK_STARTER        = "STARTER"
	DefaultMaxKillRetry = 10
)

type Config struct {
	Pidfile string
	Logfile string
	Workdir string
}

var defaultConfig Config

func init() {
	flag.StringVar(&defaultConfig.Pidfile, "pidfile", "", "Location of the pidfile.")
	flag.StringVar(&defaultConfig.Logfile, "logfile", "", "Location of the logfile.")
	flag.StringVar(&defaultConfig.Workdir, "workdir", "", "Location of the working directory to change to.")
}

// The loop is only restarted if none of the Handler implementations return an error != nil.
type StartFunc func() error
type ReturnHandlerFunc func(error) error
type SignalHandlerFunc func(os.Signal) error
type PanicHandlerFunc func(interface{}) error
type ExitHandlerFunc func(*os.ProcessState) error
type AnyHandlerFunc func(error) error

type Context struct {
	Config

	UseWatchdog  bool
	MaxKillRetry int

	OnExit   ExitHandlerFunc
	OnPanic  PanicHandlerFunc
	OnSignal SignalHandlerFunc
	OnReturn ReturnHandlerFunc
	OnAny    AnyHandlerFunc

	DefaultOnExit   ExitHandlerFunc
	DefaultOnPanic  PanicHandlerFunc
	DefaultOnSignal SignalHandlerFunc
	DefaultOnReturn ReturnHandlerFunc
	DefaultOnAny    AnyHandlerFunc

	Start StartFunc

	Name     string
	MustRun  time.Duration
	ptype    string
	rchild   *os.Process
	watchdog *os.Process
	lf       *os.File
}

func Launch(s StartFunc, args ...interface{}) (ctx *Context, err error) {
	c := NewContext(s, args...)
	err = c.Launch()
	if err != nil {
		c.Logf("error: %s", err)
	}
	return c, err
}

func NewContext(s StartFunc, args ...interface{}) *Context {

	//determin which kind of proc this is.
	ptype := os.Getenv(MARK_KEY)
	if len(ptype) == 0 {
		ptype = MARK_STARTER
	}

	name := path.Base(os.Args[0])

	var ret *Context
	ret = &Context{
		Config:       defaultConfig,
		rchild:       nil,
		ptype:        ptype,
		Name:         name,
		MaxKillRetry: DefaultMaxKillRetry,
		DefaultOnExit: func(state *os.ProcessState) error {
			ret.Logf("onExit %s", state.String())
			return nil
		},
		DefaultOnPanic: func(i interface{}) error {
			ret.Logf("onPanic %s", i)
			debug.PrintStack()
			return nil
		},
		DefaultOnReturn: func(err error) error {
			ret.Logf("onReturn %s", err)
			return nil
		},
		DefaultOnSignal: func(sig os.Signal) error {
			ret.Logf("onSignal %s", sig)
			return ret.Errorf("exiting due to sig %s", sig)
		},
		DefaultOnAny: func(err error) error {
			return err
		},
		Start:   s,
		MustRun: time.Second * 1,
	}

	if len(ret.Config.Pidfile) <= 0 {
		ret.Config.Pidfile = name + ".pid"
	}

	if len(ret.Config.Logfile) <= 0 {
		ret.Config.Logfile = name + ".log"
	}

	ret.OnExit = ret.DefaultOnExit
	ret.OnPanic = ret.DefaultOnPanic
	ret.OnReturn = ret.DefaultOnReturn
	ret.OnSignal = ret.DefaultOnSignal
	ret.OnAny = ret.DefaultOnAny

	for _, m := range args {
		if v, ok := m.(ReturnHandlerFunc); ok {
			ret.Logf("registering ReturnHandler")
			ret.OnReturn = v
		}

		if v, ok := m.(PanicHandlerFunc); ok {
			ret.Logf("registering PanicHandler")
			ret.OnPanic = v
		}

		if v, ok := m.(SignalHandlerFunc); ok {
			ret.Logf("registering SignalHandler")
			ret.OnSignal = v
		}

		if v, ok := m.(ExitHandlerFunc); ok {
			ret.Logf("registering ExitHandler")
			ret.OnExit = v
		}

		if v, ok := m.(AnyHandlerFunc); ok {
			ret.Logf("registering AnyHandler")
			ret.OnAny = v
		}
	}

	ret.readPidfile()
	return ret
}

func (c *Context) doChild() error {
	c.Logf("doChild")
	ret := make(chan error, 1)

	run := true
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT)

	for run {
		laststart := time.Now()
		go func() {
			var err error
			defer func() {
				if r := recover(); r != nil {
					err = c.OnPanic(r)
				}
				ret <- err
			}()
			c.Logf("starting Start() routine")
			err = c.Start()
		}()

		var err error
		select {
		case err = <-ret: // START returned an error
			err = c.OnReturn(err)

		case sig := <-sc: // A Termination signal was catched
			err = c.OnSignal(sig)
		}
		err = c.OnAny(err)
		if err != nil {
			return c.Errorf("exiting due to error in handler: '%s'", err)
		}

		delta := time.Now().Sub(laststart)
		if delta < c.MustRun {
			log.Fatalf("returned within %.3f seconds. Assuming startup error. Aborted.", delta.Seconds())
		}

		c.Logf("restarting: %s %s", c.Name, c.ptype)
	}
	return nil
}

func (c *Context) doWatchdog() (err error) {
	proc, err := os.FindProcess(os.Getpid())
	if err != nil {
		return
	}
	c.watchdog = proc

	defer c.close()
	run := true

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT)
	go func() {
		sig := <-sc
		c.Logf("received signal %d", sig)
		run = false
		if c.rchild != nil {
			c.Logf("pass signal %d to PID=%d", sig, c.rchild.Pid)
			c.rchild.Signal(sig) //  Pass the same signal to the child
		}
	}()

	for run {
		laststart := time.Now()

		err = c.restartAs(MARK_CHILD)
		if err != nil {
			return
		}

		err = ioutil.WriteFile(c.Pidfile, []byte(fmt.Sprintf("%d\n%d", c.rchild.Pid, os.Getpid())), 0644)
		if err != nil {
			return
		}

		c.Logf("observing")
		state, err := c.rchild.Wait()
		if err != nil {
			return err
		}

		delta := time.Now().Sub(laststart)
		if delta < c.MustRun {
			return c.Errorf("child returned within %.3f seconds", delta.Seconds)
		}
		err = c.OnExit(state)
		if err != nil {
			err = c.Errorf("exiting due to error in 'onExit' handler: '%s'", err)
			log.Print(err)
			return err
		}

		if run {
			c.Logf("restarting child")
		}
	}
	return nil
}

func (c *Context) restartAs(mark string) (err error) {
	oe := os.Environ()
	ne := make([]string, 0)

	for _, e := range oe {
		if !strings.HasPrefix(e, MARK_KEY) {
			ne = append(ne, e)
		}
	}
	ne = append(ne, fmt.Sprintf("%s=%s", MARK_KEY, mark))

	attr := &os.ProcAttr{
		Dir: c.Config.Workdir,
		Env: ne,
		Files: []*os.File{
			os.Stdin,
			c.lf,
			c.lf,
		},
		Sys: &syscall.SysProcAttr{
			Setsid: true,
		},
	}

	c.Logf("restarting to %s", mark)
	child, err := os.StartProcess(os.Args[0], os.Args, attr)
	if err != nil {
		return err
	}

	if child == nil {
		return c.Errorf("child should never become a same proc type: %s,%s", c.Name, c.ptype)
	}
	c.rchild = child

	return err
}

func (c *Context) doStarter() (err error) {
	//TODO: check for UseWatchdog
	err = c.restartAs(MARK_WATCHDOG)
	if err != nil {
		return
	}

	c.Logf("Starter done. Please find logs at '%s'", c.Logfile)
	return nil
}

func (c *Context) close() error {
	c.lf.Close()
	return os.Remove(c.Pidfile)
}

func (c *Context) Launch() (err error) {
	c.lf, err = os.OpenFile(c.Config.Logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		return err
	}

	/* route proc type */
	switch c.ptype {
	case MARK_CHILD:
		log.SetOutput(c.lf)
		err = c.doChild()
		c.Logf("Exiting: %s", err)
		os.Exit(0)
	case MARK_WATCHDOG:
		c.Logf("Starting. Writing logs to: '%s'", c.Logfile)
		log.SetOutput(c.lf)
		err = c.doWatchdog()
		c.Logf("Exiting: %s", err)
		os.Exit(0)
	case MARK_STARTER:
		return c.doStarter()
	default:
		return c.Errorf("unknown proc type: %s", c.ptype)
	}
	return nil
}

func (c *Context) Logf(pat string, args ...interface{}) {
	log.Printf("[%s|%s|%d] "+pat, append([]interface{}{c.Name, c.ptype, os.Getpid()}, args...)...)
}

func (c *Context) Errorf(pat string, args ...interface{}) error {
	return fmt.Errorf("[%s|%s|%d] "+pat, append([]interface{}{c.Name, c.ptype, os.Getpid()}, args...)...)
}

func (c *Context) readPidfile() error {
	c.rchild = nil
	c.watchdog = nil

	data, err := ioutil.ReadFile(c.Config.Pidfile)
	if err != nil {
		return nil
	}

	sb := bytes.Split(data, []byte{'\n'})
	if len(sb) >= 1 {
		cpid, err := strconv.Atoi(string(sb[0]))
		if err != nil {
			return err
		}

		proc, _ := os.FindProcess(cpid)
		c.rchild = proc
	}

	if len(sb) >= 2 {
		wdpid, err := strconv.Atoi(string(sb[1]))
		if err != nil {
			return err
		}
		proc, _ := os.FindProcess(wdpid)
		c.watchdog = proc
	}

	return nil
}

func (c *Context) Kill() error {
	return c.kill(syscall.SIGKILL)
}

func (c *Context) Stop() error {
	return c.kill(syscall.SIGTERM)
}

func (c *Context) kill(sig os.Signal) error {
	for i := 0; i < c.MaxKillRetry; i++ {
		c.readPidfile()

		if c.IsDown() {
			return nil
		}

		if c.watchdog != nil {
			c.Logf("Sending %s to watchdog PID=%d", sig, c.watchdog.Pid)
			c.watchdog.Signal(syscall.SIGTERM) // Never send the watchdog a kill
		}

		if c.rchild != nil {
			c.Logf("Sending %s to child PID=%d", sig, c.rchild.Pid)
			c.rchild.Signal(sig)
		}
		time.Sleep(time.Second * 1)
	}

	return c.Errorf("Could not stop process '%s' after %d retries.", c.Name, c.MaxKillRetry)
}

func (c *Context) IsRunning() bool {
	return (c.rchild != nil && c.watchdog != nil)
}

func (c *Context) IsDown() bool {
	return (c.rchild == nil && c.watchdog == nil)
}

func (c *Context) amITheChild() bool {
	if c.rchild != nil {
		return c.rchild.Pid == os.Getpid()
	}
	return false
}

func Command(cmd string, s StartFunc, fs ...interface{}) (ctx *Context, err error) {
	ctx = NewContext(s, fs...)
	if ctx == nil {
		return nil, fmt.Errorf("Could not create context.")
	}
	err = ctx.Command(cmd)
	return ctx, err
}

func PrintUsage() {
	fmt.Fprintf(os.Stderr, `
usage: %s [flags...] <target>

Targets:
--------
	start		Start the service.
	stop		Stop the service.
	kill		Kill the service.
	status		Print if service is running.

Flags:
------
`, os.Args[0])
	flag.PrintDefaults()
}

func (c *Context) Command(cmd string) (err error) {
	c.readPidfile()
	cm := strings.ToLower(cmd)
	running := c.IsRunning()
	switch cm {
	case "stop":
		if !running {
			return
		}
		return c.Stop()
	case "kill":
		if !running {
			return
		}
		return c.Kill()
	case "start":
		if !running || c.amITheChild() {
			return c.Launch()
		} else {
			c.Logf("Already Running")
			return c.Errorf("Service already running.")
		}
	case "status":
		if running {
			c.Logf("Service %s is running at PID=%d,%d\n", c.Name, c.watchdog.Pid, c.rchild.Pid)

			/* TODO: Send SIG INFO/STATUS to child process */
			return nil
		} else {
			return c.Errorf("Service %s is not running", c.Name)
		}
		flag.PrintDefaults()
	default:
		return c.Errorf("unknown command: %s", cmd)
	}
	return
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "math/rand"

func main() {
	inArray := rand.Perm(10)
	fmt.Println("in:")
	fmt.Printf("%v", inArray)
	fmt.Println()

	quicksort(inArray, 0, len(inArray)-1)
	fmt.Println()
	fmt.Println("out:")
	fmt.Printf("%v", inArray)
	fmt.Println()
}

func quicksort(arr []int, lo int, hi int) {
	if lo >= hi {
		return
	}

	pivotIndex := partition(arr, lo, hi)

	quicksort(arr, lo, pivotIndex)
	quicksort(arr, pivotIndex+1, hi)
}

func partition(arr []int, lo int, hi int) int {
	pivotIndex := arr[(lo+hi)/2]
	pivotValue := arr[pivotIndex]

	swap(arr, pivotIndex, hi)

	left := lo
	right := hi - 1

	for left < right {
		for arr[left] < pivotValue {
			left++
		}

		for right >= left && arr[right] >= pivotValue {
			right--
		}

		if right > left {
			swap(arr, left, right)
		}
	}

	swap(arr, hi, left)
	return left
}

func swap(arr []int, first int, second int) {
	temp := arr[first]
	arr[first] = arr[second]
	arr[second] = temp
}
<commit_msg>Added pointers<commit_after>package main

import "fmt"
import "math/rand"

func main() {
	inArray := rand.Perm(10)
	fmt.Println("in:")
	fmt.Printf("%v", inArray)
	fmt.Println()

	quicksort(inArray, 0, len(inArray)-1)
	fmt.Println()
	fmt.Println("out:")
	fmt.Printf("%v", inArray)
	fmt.Println()
}

func quicksort(arr []int, lo int, hi int) {
	if lo >= hi {
		return
	}

	pivotIndex := partition(arr, lo, hi)

	quicksort(arr, lo, pivotIndex)
	quicksort(arr, pivotIndex+1, hi)
}

func partition(arr []int, lo int, hi int) int {
	pivotIndex := arr[(lo+hi)/2]
	pivotValue := arr[pivotIndex]

	swap(&arr[pivotIndex], &arr[hi])

	left := lo
	right := hi - 1

	for left < right {
		for arr[left] < pivotValue {
			left++
		}

		for right >= left && arr[right] >= pivotValue {
			right--
		}

		if right > left {
			swap(&arr[left], &arr[right])
		}
	}

	swap(&arr[hi], &arr[left])
	return left
}

func swap(first *int, second *int) {
	temp := *first
	*first = *second
	*second = temp
}
<|endoftext|>


<commit_before>package locking

import (
	"github.com/divtxt/raft"
	"log"
)

// In-memory implementation of Lock API
type InMemoryLock struct {
	// Lock state
	committedLocks   map[string]bool
	uncommittedLocks map[string]bool

	// Raft things
	raftCM  raft.IConsensusModule
	raftLog raft.LogReadOnly

	// entries                  []raft.LogEntry
	// commitIndex              raft.LogIndex
	// maxEntriesPerAppendEntry uint64
}

// Construct a new InMemoryLock.
//
// Rebuilds the state machine by replaying from the log. This could take a while!
//
// It is expected that raft.ConsensusModule.Start() will be called later using the
// returned InMemoryLock as the raft.ChangeListener parameter.
//
func NewInMemoryLock(raftCM raft.IConsensusModule, raftLog raft.LogReadOnly) *InMemoryLock {
	iml := &InMemoryLock{
		make(map[string]bool),
		make(map[string]bool),
		raftCM,
		raftLog,
	}

	// Build state machine from log
	log.Print("NewInMemoryLock(): Rebuilding state machine from raft log...")
	// iole, err := raftLog.GetIndexOfLastEntry()

	// FIXME: ...

	log.Printf("NewInMemoryLock(): Rebuilt state machine by replaying %v log entries", -1)

	return iml
}

// -- Implement LockApi interface

func (iml *InMemoryLock) Lock(name string) (bool, error) {
	// FIXME: mutex

	// check uncommitted state - if already locked return false
	if _, hasKey := iml.uncommittedLocks[name]; hasKey {
		return false, nil
	}

	// add lock to uncommitted
	iml.uncommittedLocks[name] = true

	// append command to raft log
	command, err := CmdSerialize(&Cmd{true, name})
	if err != nil {
		return false, err
	}
	err = iml.raftCM.AppendCommand(command)
	if err != nil {
		return false, err
	}

	// FIXME: wait for commit

	return true, nil
}

func (iml *InMemoryLock) Unlock(name string) (bool, error) {
	// FIXME: mutex

	// check uncommitted state - if not locked return false
	if _, hasKey := iml.uncommittedLocks[name]; !hasKey {
		return false, nil
	}

	// remove lock from uncommitted
	delete(iml.uncommittedLocks, name)

	// append command to raft log
	command, err := CmdSerialize(&Cmd{false, name})
	if err != nil {
		return false, err
	}
	err = iml.raftCM.AppendCommand(command)
	if err != nil {
		return false, err
	}

	// FIXME: wait for commit

	return true, nil
}

// -- Implement raft.ChangeListener interface

func (iml *InMemoryLock) CommitIndexChanged(logIndex raft.LogIndex) {
	// FIXME: advance commit!
}
<commit_msg>Match change in AppendCommand return type<commit_after>package locking

import (
	"github.com/divtxt/raft"
	"log"
)

// In-memory implementation of Lock API
type InMemoryLock struct {
	// Lock state
	committedLocks   map[string]bool
	uncommittedLocks map[string]bool

	// Raft things
	raftCM  raft.IConsensusModule
	raftLog raft.LogReadOnly

	// entries                  []raft.LogEntry
	// commitIndex              raft.LogIndex
	// maxEntriesPerAppendEntry uint64
}

// Construct a new InMemoryLock.
//
// Rebuilds the state machine by replaying from the log. This could take a while!
//
// It is expected that raft.ConsensusModule.Start() will be called later using the
// returned InMemoryLock as the raft.ChangeListener parameter.
//
func NewInMemoryLock(raftCM raft.IConsensusModule, raftLog raft.LogReadOnly) *InMemoryLock {
	iml := &InMemoryLock{
		make(map[string]bool),
		make(map[string]bool),
		raftCM,
		raftLog,
	}

	// Build state machine from log
	log.Print("NewInMemoryLock(): Rebuilding state machine from raft log...")
	// iole, err := raftLog.GetIndexOfLastEntry()

	// FIXME: ...

	log.Printf("NewInMemoryLock(): Rebuilt state machine by replaying %v log entries", -1)

	return iml
}

// -- Implement LockApi interface

func (iml *InMemoryLock) Lock(name string) (bool, error) {
	// FIXME: mutex

	// check uncommitted state - if already locked return false
	if _, hasKey := iml.uncommittedLocks[name]; hasKey {
		return false, nil
	}

	// add lock to uncommitted
	iml.uncommittedLocks[name] = true

	// append command to raft log
	command, err := CmdSerialize(&Cmd{true, name})
	if err != nil {
		return false, err
	}
	_, err = iml.raftCM.AppendCommand(command)
	if err != nil {
		return false, err
	}

	// FIXME: wait for commit

	return true, nil
}

func (iml *InMemoryLock) Unlock(name string) (bool, error) {
	// FIXME: mutex

	// check uncommitted state - if not locked return false
	if _, hasKey := iml.uncommittedLocks[name]; !hasKey {
		return false, nil
	}

	// remove lock from uncommitted
	delete(iml.uncommittedLocks, name)

	// append command to raft log
	command, err := CmdSerialize(&Cmd{false, name})
	if err != nil {
		return false, err
	}
	_, err = iml.raftCM.AppendCommand(command)
	if err != nil {
		return false, err
	}

	// FIXME: wait for commit

	return true, nil
}

// -- Implement raft.ChangeListener interface

func (iml *InMemoryLock) CommitIndexChanged(logIndex raft.LogIndex) {
	// FIXME: advance commit!
}
<|endoftext|>


<commit_before>package raftgorums

import (
	"fmt"
	"log"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
	gorums "github.com/relab/raft/raftgorums/gorumspb"
	pb "github.com/relab/raft/raftgorums/raftpb"
)

// Node ties an instance of Raft to the network.
type Node struct {
	id uint64

	Raft    *Raft
	storage Storage

	lookup map[uint64]int
	peers  []string

	catchingUp map[uint32]chan uint64
	catchUp    chan *catchUpRequest

	mgr  *gorums.Manager
	conf *gorums.Configuration
}

// NewNode returns a Node with an instance of Raft given the configuration.
func NewNode(server *grpc.Server, sm raft.StateMachine, cfg *Config) *Node {
	peers := make([]string, len(cfg.Nodes))
	// We don't want to mutate cfg.Nodes.
	copy(peers, cfg.Nodes)

	id := cfg.ID
	// Exclude self.
	peers = append(peers[:id-1], peers[id:]...)

	var pos int
	lookup := make(map[uint64]int)

	for i := 0; i < len(cfg.Nodes); i++ {
		if uint64(i) == id {
			continue
		}

		lookup[uint64(i)] = pos
		pos++
	}

	n := &Node{
		id:         id,
		Raft:       NewRaft(sm, cfg),
		storage:    cfg.Storage,
		lookup:     lookup,
		peers:      peers,
		catchingUp: make(map[uint32]chan uint64),
		catchUp:    make(chan *catchUpRequest),
	}

	gorums.RegisterRaftServer(server, n)

	return n
}

// Run start listening for incoming messages, and delivers outgoing messages.
func (n *Node) Run() error {
	opts := []gorums.ManagerOption{
		gorums.WithGrpcDialOptions(
			grpc.WithBlock(),
			grpc.WithInsecure(),
			grpc.WithTimeout(TCPConnect*time.Millisecond)),
	}

	mgr, err := gorums.NewManager(n.peers, opts...)

	if err != nil {
		return err
	}

	n.mgr = mgr
	n.conf, err = mgr.NewConfiguration(mgr.NodeIDs(), NewQuorumSpec(len(n.peers)+1))

	if err != nil {
		return err
	}

	go n.Raft.Run()

	for {
		rvreqout := n.Raft.RequestVoteRequestChan()
		aereqout := n.Raft.AppendEntriesRequestChan()
		sreqout := n.Raft.SnapshotRequestChan()

		select {
		case req := <-sreqout:
			n.Raft.Lock()
			leader := n.Raft.leader
			n.Raft.Unlock()
			ctx, cancel := context.WithTimeout(context.Background(), TCPConnect*time.Millisecond)
			node, _ := n.mgr.Node(n.getNodeID(leader))
			snapshot, err := node.RaftClient.GetState(ctx, req)
			cancel()

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("Snapshot request failed = %v", err))

			}

			n.Raft.restoreCh <- snapshot

		case req := <-rvreqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.RequestVote(ctx, req)
			cancel()

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("RequestVote failed = %v", err))

			}

			if res.RequestVoteResponse == nil {
				continue
			}

			n.Raft.HandleRequestVoteResponse(res.RequestVoteResponse)

		case req := <-aereqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.AppendEntries(ctx, req)

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("AppendEntries failed = %v", err))

				if res.AppendEntriesResponse == nil {
					continue
				}
			}

			// Cancel on abort.
			if !res.AppendEntriesResponse.Success {
				cancel()
			}

			n.Raft.HandleAppendEntriesResponse(res.AppendEntriesResponse, len(res.NodeIDs))

			for nodeID, matchIndex := range n.catchingUp {
				select {
				case index, ok := <-matchIndex:
					if !ok {
						n.addBackNode(nodeID)
						continue
					}

					matchIndex <- res.MatchIndex

					if index == res.MatchIndex {
						n.addBackNode(nodeID)
					}
				default:
				}
			}

		case creq := <-n.catchUp:
			oldSet := n.conf.NodeIDs()

			// Don't remove servers when we would've gone below the
			// quorum size. The quorum function handles recovery
			// when a majority fails.
			if len(oldSet)-1 < len(n.peers)/2 {
				continue
			}

			nodeID := n.getNodeID(creq.followerID)
			// We use 2 peers as we need to count the leader.
			single, err := n.mgr.NewConfiguration([]uint32{nodeID}, NewQuorumSpec(2))

			if err != nil {
				panic(fmt.Sprintf("tried to catch up node %d->%d: %v", creq.followerID, nodeID, err))
			}

			tmpSet := make([]uint32, len(oldSet)-1)

			var i int
			for _, id := range oldSet {
				if id == nodeID {
					continue
				}

				tmpSet[i] = id
				i++
			}

			// It's important not to change the quorum size when
			// removing the server. We reduce N by one so we don't
			// wait on the recovering server.
			n.conf, err = mgr.NewConfiguration(tmpSet, &QuorumSpec{
				N: len(tmpSet),
				Q: (len(n.peers) + 1) / 2,
			})

			if err != nil {
				panic(fmt.Sprintf("tried to create new configuration %v: %v", tmpSet, err))
			}

			matchIndex := make(chan uint64)
			n.catchingUp[nodeID] = matchIndex
			go n.doCatchUp(single, creq.nextIndex, matchIndex)
		}
	}
}

func (n *Node) addBackNode(nodeID uint32) {
	delete(n.catchingUp, nodeID)

	newSet := append(n.conf.NodeIDs(), nodeID)
	var err error
	n.conf, err = n.mgr.NewConfiguration(newSet, &QuorumSpec{
		N: len(newSet),
		Q: (len(n.peers) + 1) / 2,
	})

	if err != nil {
		panic(fmt.Sprintf("tried to create new configuration %v: %v", newSet, err))
	}
}

// RequestVote implements gorums.RaftServer.
func (n *Node) RequestVote(ctx context.Context, req *pb.RequestVoteRequest) (*pb.RequestVoteResponse, error) {
	return n.Raft.HandleRequestVoteRequest(req), nil
}

// AppendEntries implements gorums.RaftServer.
func (n *Node) AppendEntries(ctx context.Context, req *pb.AppendEntriesRequest) (*pb.AppendEntriesResponse, error) {
	return n.Raft.HandleAppendEntriesRequest(req), nil
}

// GetState implements gorums.RaftServer.
func (n *Node) GetState(ctx context.Context, req *pb.SnapshotRequest) (*commonpb.Snapshot, error) {
	future := make(chan *commonpb.Snapshot)
	n.Raft.snapCh <- future

	select {
	case snapshot := <-future:
		n.catchUp <- &catchUpRequest{
			nextIndex:  snapshot.Index + 1,
			followerID: req.FollowerID,
		}
		return snapshot, nil
	case <-ctx.Done():
		return nil, ctx.Err()
	}
}

type catchUpRequest struct {
	nextIndex  uint64
	followerID uint64
}

func (n *Node) doCatchUp(conf *gorums.Configuration, nextIndex uint64, matchIndex chan uint64) {
	for {
		state := n.Raft.State()

		if state != Leader {
			close(matchIndex)
			return
		}

		n.Raft.Lock()
		entries := n.Raft.getNextEntries(nextIndex)
		request := n.Raft.getAppendEntriesRequest(nextIndex, entries)
		n.Raft.Unlock()

		ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
		res, err := conf.AppendEntries(ctx, request)

		if err != nil {
			// TODO Better error message.
			log.Println(fmt.Sprintf("Catch-up AppendEntries failed = %v", err))

			if res.AppendEntriesResponse == nil {
				continue
			}
		}

		cancel()

		response := res.AppendEntriesResponse

		if response.Success {
			matchIndex <- response.MatchIndex
			index := <-matchIndex

			if response.MatchIndex == index {
				close(matchIndex)
				return
			}

			nextIndex = response.MatchIndex + 1

			continue
		}

		// If AppendEntries was unsuccessful a new catch-up process will
		// start.
		close(matchIndex)
		return
	}
}

func (n *Node) getNodeID(raftID uint64) uint32 {
	return n.mgr.NodeIDs()[n.lookup[raftID-1]]
}
<commit_msg>raftgorums/node.go: Cleanly exit failed catch-up<commit_after>package raftgorums

import (
	"fmt"
	"log"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
	gorums "github.com/relab/raft/raftgorums/gorumspb"
	pb "github.com/relab/raft/raftgorums/raftpb"
)

// Node ties an instance of Raft to the network.
type Node struct {
	id uint64

	Raft    *Raft
	storage Storage

	lookup map[uint64]int
	peers  []string

	catchingUp map[uint32]chan uint64
	catchUp    chan *catchUpRequest

	mgr  *gorums.Manager
	conf *gorums.Configuration
}

// NewNode returns a Node with an instance of Raft given the configuration.
func NewNode(server *grpc.Server, sm raft.StateMachine, cfg *Config) *Node {
	peers := make([]string, len(cfg.Nodes))
	// We don't want to mutate cfg.Nodes.
	copy(peers, cfg.Nodes)

	id := cfg.ID
	// Exclude self.
	peers = append(peers[:id-1], peers[id:]...)

	var pos int
	lookup := make(map[uint64]int)

	for i := 0; i < len(cfg.Nodes); i++ {
		if uint64(i) == id {
			continue
		}

		lookup[uint64(i)] = pos
		pos++
	}

	n := &Node{
		id:         id,
		Raft:       NewRaft(sm, cfg),
		storage:    cfg.Storage,
		lookup:     lookup,
		peers:      peers,
		catchingUp: make(map[uint32]chan uint64),
		catchUp:    make(chan *catchUpRequest),
	}

	gorums.RegisterRaftServer(server, n)

	return n
}

// Run start listening for incoming messages, and delivers outgoing messages.
func (n *Node) Run() error {
	opts := []gorums.ManagerOption{
		gorums.WithGrpcDialOptions(
			grpc.WithBlock(),
			grpc.WithInsecure(),
			grpc.WithTimeout(TCPConnect*time.Millisecond)),
	}

	mgr, err := gorums.NewManager(n.peers, opts...)

	if err != nil {
		return err
	}

	n.mgr = mgr
	n.conf, err = mgr.NewConfiguration(mgr.NodeIDs(), NewQuorumSpec(len(n.peers)+1))

	if err != nil {
		return err
	}

	go n.Raft.Run()

	for {
		rvreqout := n.Raft.RequestVoteRequestChan()
		aereqout := n.Raft.AppendEntriesRequestChan()
		sreqout := n.Raft.SnapshotRequestChan()

		select {
		case req := <-sreqout:
			n.Raft.Lock()
			leader := n.Raft.leader
			n.Raft.Unlock()
			ctx, cancel := context.WithTimeout(context.Background(), TCPConnect*time.Millisecond)
			node, _ := n.mgr.Node(n.getNodeID(leader))
			snapshot, err := node.RaftClient.GetState(ctx, req)
			cancel()

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("Snapshot request failed = %v", err))

			}

			n.Raft.restoreCh <- snapshot

		case req := <-rvreqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.RequestVote(ctx, req)
			cancel()

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("RequestVote failed = %v", err))

			}

			if res.RequestVoteResponse == nil {
				continue
			}

			n.Raft.HandleRequestVoteResponse(res.RequestVoteResponse)

		case req := <-aereqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.AppendEntries(ctx, req)

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("AppendEntries failed = %v", err))

				if res.AppendEntriesResponse == nil {
					continue
				}
			}

			// Cancel on abort.
			if !res.AppendEntriesResponse.Success {
				cancel()
			}

			n.Raft.HandleAppendEntriesResponse(res.AppendEntriesResponse, len(res.NodeIDs))

			for nodeID, matchIndex := range n.catchingUp {
				select {
				case index, ok := <-matchIndex:
					if !ok {
						n.addBackNode(nodeID)
						continue
					}

					matchIndex <- res.MatchIndex

					if index == res.MatchIndex {
						n.addBackNode(nodeID)
					}
				default:
				}
			}

		case creq := <-n.catchUp:
			oldSet := n.conf.NodeIDs()

			// Don't remove servers when we would've gone below the
			// quorum size. The quorum function handles recovery
			// when a majority fails.
			if len(oldSet)-1 < len(n.peers)/2 {
				continue
			}

			nodeID := n.getNodeID(creq.followerID)
			// We use 2 peers as we need to count the leader.
			single, err := n.mgr.NewConfiguration([]uint32{nodeID}, NewQuorumSpec(2))

			if err != nil {
				panic(fmt.Sprintf("tried to catch up node %d->%d: %v", creq.followerID, nodeID, err))
			}

			tmpSet := make([]uint32, len(oldSet)-1)

			var i int
			for _, id := range oldSet {
				if id == nodeID {
					continue
				}

				tmpSet[i] = id
				i++
			}

			// It's important not to change the quorum size when
			// removing the server. We reduce N by one so we don't
			// wait on the recovering server.
			n.conf, err = mgr.NewConfiguration(tmpSet, &QuorumSpec{
				N: len(tmpSet),
				Q: (len(n.peers) + 1) / 2,
			})

			if err != nil {
				panic(fmt.Sprintf("tried to create new configuration %v: %v", tmpSet, err))
			}

			matchIndex := make(chan uint64)
			n.catchingUp[nodeID] = matchIndex
			go n.doCatchUp(single, creq.nextIndex, matchIndex)
		}
	}
}

func (n *Node) addBackNode(nodeID uint32) {
	delete(n.catchingUp, nodeID)

	newSet := append(n.conf.NodeIDs(), nodeID)
	var err error
	n.conf, err = n.mgr.NewConfiguration(newSet, &QuorumSpec{
		N: len(newSet),
		Q: (len(n.peers) + 1) / 2,
	})

	if err != nil {
		panic(fmt.Sprintf("tried to create new configuration %v: %v", newSet, err))
	}
}

// RequestVote implements gorums.RaftServer.
func (n *Node) RequestVote(ctx context.Context, req *pb.RequestVoteRequest) (*pb.RequestVoteResponse, error) {
	return n.Raft.HandleRequestVoteRequest(req), nil
}

// AppendEntries implements gorums.RaftServer.
func (n *Node) AppendEntries(ctx context.Context, req *pb.AppendEntriesRequest) (*pb.AppendEntriesResponse, error) {
	return n.Raft.HandleAppendEntriesRequest(req), nil
}

// GetState implements gorums.RaftServer.
func (n *Node) GetState(ctx context.Context, req *pb.SnapshotRequest) (*commonpb.Snapshot, error) {
	future := make(chan *commonpb.Snapshot)
	n.Raft.snapCh <- future

	select {
	case snapshot := <-future:
		n.catchUp <- &catchUpRequest{
			nextIndex:  snapshot.Index + 1,
			followerID: req.FollowerID,
		}
		return snapshot, nil
	case <-ctx.Done():
		return nil, ctx.Err()
	}
}

type catchUpRequest struct {
	nextIndex  uint64
	followerID uint64
}

func (n *Node) doCatchUp(conf *gorums.Configuration, nextIndex uint64, matchIndex chan uint64) {
	for {
		state := n.Raft.State()

		if state != Leader {
			close(matchIndex)
			return
		}

		n.Raft.Lock()
		entries := n.Raft.getNextEntries(nextIndex)
		request := n.Raft.getAppendEntriesRequest(nextIndex, entries)
		n.Raft.Unlock()

		ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
		res, err := conf.AppendEntries(ctx, request)
		cancel()

		if err != nil {

			// TODO Better error message.
			log.Println(fmt.Sprintf("Catch-up AppendEntries failed = %v", err))

			close(matchIndex)
			return
		}

		response := res.AppendEntriesResponse

		if response.Success {
			matchIndex <- response.MatchIndex
			index := <-matchIndex

			if response.MatchIndex == index {
				close(matchIndex)
				return
			}

			nextIndex = response.MatchIndex + 1

			continue
		}

		// If AppendEntries was unsuccessful a new catch-up process will
		// start.
		close(matchIndex)
		return
	}
}

func (n *Node) getNodeID(raftID uint64) uint32 {
	return n.mgr.NodeIDs()[n.lookup[raftID-1]]
}
<|endoftext|>


<commit_before>package runtime

import (
	"fmt"
	"os"
	"strings"

	"github.com/go-clang/gen"
)

// PrepareFunctionName prepares C function naming to Go function name.
func PrepareFunctionName(g *gen.Generation, f *gen.Function) string {
	fname := strings.TrimPrefix(f.Name, "clang_")

	// trim some allowlisted prefixes by their function name
	switch {
	case strings.HasPrefix(fname, "indexLoc_"):
		fname = strings.TrimPrefix(fname, "indexLoc_")

	case strings.HasPrefix(fname, "index_"):
		fname = strings.TrimPrefix(fname, "index_")

	case strings.HasPrefix(fname, "Location_"):
		fname = strings.TrimPrefix(fname, "Location_")

	case strings.HasPrefix(fname, "Range_"):
		fname = strings.TrimPrefix(fname, "Range_")

	case strings.HasPrefix(fname, "remap_"):
		fname = strings.TrimPrefix(fname, "remap_")
	}

	// trim some allowlisted prefixes by their types
	if len(f.Parameters) > 0 && g.IsEnumOrStruct(f.Parameters[0].Type.GoName) {
		switch f.Parameters[0].Type.GoName {
		case "CodeCompleteResults":
			fname = strings.TrimPrefix(fname, "codeComplete")

		case "CompletionString":
			if f.CName == "clang_getNumCompletionChunks" {
				fname = "NumChunks"
			} else {
				fname = strings.TrimPrefix(fname, "getCompletion")
			}

		case "SourceRange":
			fname = strings.TrimPrefix(fname, "getRange")
		}
	}

	return fname
}

// PrepareFunction prepares C function to Go function.
func PrepareFunction(f *gen.Function) {
	for i := range f.Parameters {
		p := &f.Parameters[i]

		if f.CName == "clang_getRemappingsFromFileList" {
			switch p.CName {
			case "filePaths":
				p.Type.IsSlice = true

			case "numFiles":
				p.Type.LengthOfSlice = "filePaths"
			}

			continue
		}

		// allowflag types that are return arguments
		switch p.Type.PointerLevel {
		case 1:
			switch p.Type.GoName {
			case
				gen.GoInt32,
				gen.GoUInt32,
				"File",
				"FileUniqueID",
				"IdxClientFile",
				"cxstring",
				"CompilationDatabase_Error",
				"PlatformAvailability",
				"SourceRange",
				"LoadDiag_Error":

				p.Type.IsReturnArgument = true
			}

		case 2:
			switch p.Type.GoName {
			case
				"Token",
				"Cursor":

				p.Type.IsReturnArgument = true
			}
		}

		if f.CName == "clang_disposeOverriddenCursors" && p.CName == "overridden" {
			p.Type.IsSlice = true
		}

		// if this is an array length parameter we need to find its partner
		paCName := gen.ArrayNameFromLength(p.CName)

		if paCName != "" {
			for j := range f.Parameters {
				pa := &f.Parameters[j]

				if strings.EqualFold(pa.CName, paCName) {
					switch pa.Type.GoName {
					case "UnsavedFile":
						pa.Type.GoName = "UnsavedFile"
						pa.Type.CGoName = "struct_CXUnsavedFile"

					case "CompletionResult", "Token", "Cursor":
						// nothing to do

					default:
						if pa.Type.CGoName != gen.CSChar && pa.Type.PointerLevel != 2 {
							break
						}
					}

					p.Type.LengthOfSlice = pa.Name
					pa.Type.IsSlice = true

					if pa.Type.IsReturnArgument && p.Type.PointerLevel > 0 {
						p.Type.IsReturnArgument = true
					}

					break
				}
			}
		}
	}

	for i := range f.Parameters {
		p := &f.Parameters[i]

		if p.Type.CGoName == gen.CSChar && p.Type.PointerLevel == 2 && !p.Type.IsSlice {
			p.Type.IsReturnArgument = true
		}
	}
}

// FilterFunction reports whether the f function filtered to a particular condition.
func FilterFunction(f *gen.Function) bool {
	switch f.CName {
	case "clang_CompileCommand_getMappedSourceContent", "clang_CompileCommand_getMappedSourcePath", "clang_CompileCommand_getNumMappedSources":
		// some functions are not compiled in the library see https://lists.launchpad.net/desktop-packages/msg75835.html for a never resolved bug report
		fmt.Fprintf(os.Stderr, "Ignore function %q because it is not compiled within libClang\n", f.CName)

		return false

	case "clang_executeOnThread", "clang_getInclusions":
		// some functions can not be handled automatically by us
		fmt.Fprintf(os.Stderr, "Ignore function %q because it cannot be handled automatically\n", f.CName)

		return false

	case "clang_annotateTokens", "clang_getCursorPlatformAvailability", "clang_visitChildren":
		// some functions are simply manually implemented
		fmt.Fprintf(os.Stderr, "Ignore function %q because it is manually implemented\n", f.CName)

		return false
	}

	// TODO(go-clang): if this function is from CXString.h we ignore it https://github.com/go-clang/gen/issues/25
	for i := range f.IncludeFiles {
		if strings.HasSuffix(i, "CXString.h") {
			return false
		}
	}

	return true
}

// FilterFunctionParameter reports whether the p function parameter filtered to a particular condition.
func FilterFunctionParameter(p gen.FunctionParameter) bool {
	// these pointers are ok
	if p.Type.PointerLevel == 1 {
		if p.Type.CGoName == gen.CSChar {
			return false
		}

		switch p.Type.GoName {
		case "UnsavedFile",
			"CodeCompleteResults",
			"CursorKind",
			"IdxContainerInfo",
			"IdxDeclInfo",
			"IndexerCallbacks",
			"TranslationUnit",
			"IdxEntityInfo",
			"IdxAttrInfo":

			return false
		}
	}

	return true
}

// FixFunctionName fixes the function name under certain conditions.
func FixFunctionName(f *gen.Function) string {
	// needs to be renamed manually since clang_getTranslationUnitCursor will conflict with clang_getCursor
	if f.CName == "clang_getTranslationUnitCursor" {
		return "TranslationUnitCursor"
	}

	return ""
}

// PrepareStructFields prepares struct fields names.
func PrepareStructFields(s *gen.Struct) {
	for _, f := range s.Fields {
		if (strings.HasPrefix(f.CName, "has") || strings.HasPrefix(f.CName, "is")) && f.Type.GoName == gen.GoInt32 {
			f.Type.GoName = gen.GoBool
		}

		// if this is an array length parameter we need to find its partner
		faCName := gen.ArrayNameFromLength(f.CName)

		if faCName != "" {
			for _, fa := range s.Fields {
				if strings.EqualFold(fa.CName, faCName) {
					f.Type.LengthOfSlice = fa.CName
					fa.Type.IsSlice = true
					// TODO(go-clang): wrong usage but needed for the getter generation...
					// maybe refactor this LengthOfSlice all together?
					// https://github.com/go-clang/gen/issues/49
					fa.Type.LengthOfSlice = f.CName

					break
				}
			}
		}
	}

	prepareStructFieldsArrayStruct(s)
}

// prepareStructFieldsArrayStruct checks if the struct has two field variables, one is an array and the other a plain
// int/uint with size/length/count/len is its name because then this should be an array struct, and we connect them to handle a slice.
func prepareStructFieldsArrayStruct(s *gen.Struct) {
	if len(s.Fields) != 2 {
		return
	}

	if !arrayLengthCombination(&s.Fields[0].Type, &s.Fields[1].Type) && !arrayLengthCombination(&s.Fields[1].Type, &s.Fields[0].Type) {
		return
	}

	// if one of the fields is already marked as array/slice another heuristic has already covered both fields
	switch {
	case s.Fields[0].Type.IsArray,
		s.Fields[1].Type.IsArray,
		s.Fields[0].Type.IsSlice,
		s.Fields[1].Type.IsSlice:

		return
	}

	var a *gen.StructField
	var c *gen.StructField

	if s.Fields[0].Type.PointerLevel == 1 {
		a = s.Fields[0]
		c = s.Fields[1]
	} else {
		c = s.Fields[0]
		a = s.Fields[1]
	}

	lengthName := strings.ToLower(c.CName)
	if lengthName != "count" &&
		lengthName != "len" && lengthName != "length" && lengthName != "size" {

		return
	}

	c.Type.LengthOfSlice = a.CName
	a.Type.IsSlice = true
	// TODO(go-clang): wrong usage but needed for the getter generation...
	// maybe refactor this LengthOfSlice all together?
	// https://github.com/go-clang/gen/issues/49
	a.Type.LengthOfSlice = c.CName
}

// arrayLengthCombination reports whether the x and y to correct combination.
func arrayLengthCombination(x *gen.Type, y *gen.Type) bool {
	return x.PointerLevel == 1 && y.PointerLevel == 0 &&
		!gen.IsInteger(x) && gen.IsInteger(y)
}

// FilterStructFieldGetter reports whether the m struct field filtered to a particular condition.
func FilterStructFieldGetter(f *gen.StructField) bool {
	// we do not want getters to *int_data fields
	return !strings.HasSuffix(f.CName, "int_data")
}
<commit_msg>cmd/go-clang-gen/runtime: add special case<commit_after>package runtime

import (
	"fmt"
	"os"
	"strings"

	"github.com/go-clang/gen"
)

// PrepareFunctionName prepares C function naming to Go function name.
func PrepareFunctionName(g *gen.Generation, f *gen.Function) string {
	fname := strings.TrimPrefix(f.Name, "clang_")

	// trim some allowlisted prefixes by their function name
	switch {
	case strings.HasPrefix(fname, "indexLoc_"):
		fname = strings.TrimPrefix(fname, "indexLoc_")

	case strings.HasPrefix(fname, "index_"):
		fname = strings.TrimPrefix(fname, "index_")

	case strings.HasPrefix(fname, "Location_"):
		fname = strings.TrimPrefix(fname, "Location_")

	case strings.HasPrefix(fname, "Range_"):
		fname = strings.TrimPrefix(fname, "Range_")

	case strings.HasPrefix(fname, "remap_"):
		fname = strings.TrimPrefix(fname, "remap_")

	case strings.EqualFold(fname, "Install_aborting_llvm_fatal_error_handler"): // special case
		// fname = strings.Trim(fname, "llvm_")
		// fname = gen.ToCamelCase(fname)
		fname = "InstallAbortingFatalErrorHandler"

	case strings.EqualFold(fname, "Uninstall_llvm_fatal_error_handler"):
		fname = "UninstallFatalErrorHandler"
	}

	// trim some allowlisted prefixes by their types
	if len(f.Parameters) > 0 && g.IsEnumOrStruct(f.Parameters[0].Type.GoName) {
		switch f.Parameters[0].Type.GoName {
		case "CodeCompleteResults":
			fname = strings.TrimPrefix(fname, "codeComplete")

		case "CompletionString":
			if f.CName == "clang_getNumCompletionChunks" {
				fname = "NumChunks"
			} else {
				fname = strings.TrimPrefix(fname, "getCompletion")
			}

		case "SourceRange":
			fname = strings.TrimPrefix(fname, "getRange")
		}
	}

	return fname
}

// PrepareFunction prepares C function to Go function.
func PrepareFunction(f *gen.Function) {
	for i := range f.Parameters {
		p := &f.Parameters[i]

		if f.CName == "clang_getRemappingsFromFileList" {
			switch p.CName {
			case "filePaths":
				p.Type.IsSlice = true

			case "numFiles":
				p.Type.LengthOfSlice = "filePaths"
			}

			continue
		}

		// allowflag types that are return arguments
		switch p.Type.PointerLevel {
		case 1:
			switch p.Type.GoName {
			case
				gen.GoInt32,
				gen.GoUInt32,
				"File",
				"FileUniqueID",
				"IdxClientFile",
				"cxstring",
				"CompilationDatabase_Error",
				"PlatformAvailability",
				"SourceRange",
				"LoadDiag_Error":

				p.Type.IsReturnArgument = true
			}

		case 2:
			switch p.Type.GoName {
			case
				"Token",
				"Cursor":

				p.Type.IsReturnArgument = true
			}
		}

		if f.CName == "clang_disposeOverriddenCursors" && p.CName == "overridden" {
			p.Type.IsSlice = true
		}

		// if this is an array length parameter we need to find its partner
		paCName := gen.ArrayNameFromLength(p.CName)

		if paCName != "" {
			for j := range f.Parameters {
				pa := &f.Parameters[j]

				if strings.EqualFold(pa.CName, paCName) {
					switch pa.Type.GoName {
					case "UnsavedFile":
						pa.Type.GoName = "UnsavedFile"
						pa.Type.CGoName = "struct_CXUnsavedFile"

					case "CompletionResult", "Token", "Cursor":
						// nothing to do

					default:
						if pa.Type.CGoName != gen.CSChar && pa.Type.PointerLevel != 2 {
							break
						}
					}

					p.Type.LengthOfSlice = pa.Name
					pa.Type.IsSlice = true

					if pa.Type.IsReturnArgument && p.Type.PointerLevel > 0 {
						p.Type.IsReturnArgument = true
					}

					break
				}
			}
		}
	}

	for i := range f.Parameters {
		p := &f.Parameters[i]

		if p.Type.CGoName == gen.CSChar && p.Type.PointerLevel == 2 && !p.Type.IsSlice {
			p.Type.IsReturnArgument = true
		}
	}
}

// FilterFunction reports whether the f function filtered to a particular condition.
func FilterFunction(f *gen.Function) bool {
	switch f.CName {
	case "clang_CompileCommand_getMappedSourceContent", "clang_CompileCommand_getMappedSourcePath", "clang_CompileCommand_getNumMappedSources":
		// some functions are not compiled in the library see https://lists.launchpad.net/desktop-packages/msg75835.html for a never resolved bug report
		fmt.Fprintf(os.Stderr, "Ignore function %q because it is not compiled within libClang\n", f.CName)

		return false

	case "clang_executeOnThread", "clang_getInclusions":
		// some functions can not be handled automatically by us
		fmt.Fprintf(os.Stderr, "Ignore function %q because it cannot be handled automatically\n", f.CName)

		return false

	case "clang_annotateTokens", "clang_getCursorPlatformAvailability", "clang_visitChildren":
		// some functions are simply manually implemented
		fmt.Fprintf(os.Stderr, "Ignore function %q because it is manually implemented\n", f.CName)

		return false
	}

	// TODO(go-clang): if this function is from CXString.h we ignore it https://github.com/go-clang/gen/issues/25
	for i := range f.IncludeFiles {
		if strings.HasSuffix(i, "CXString.h") {
			return false
		}
	}

	return true
}

// FilterFunctionParameter reports whether the p function parameter filtered to a particular condition.
func FilterFunctionParameter(p gen.FunctionParameter) bool {
	// these pointers are ok
	if p.Type.PointerLevel == 1 {
		if p.Type.CGoName == gen.CSChar {
			return false
		}

		switch p.Type.GoName {
		case
			"UnsavedFile",
			"CodeCompleteResults",
			"CursorKind",
			"IdxContainerInfo",
			"IdxDeclInfo",
			"IndexerCallbacks",
			"TranslationUnit",
			"IdxEntityInfo",
			"IdxAttrInfo":

			return false
		}
	}

	return true
}

// FixFunctionName fixes the function name under certain conditions.
func FixFunctionName(f *gen.Function) string {
	// needs to be renamed manually since clang_getTranslationUnitCursor will conflict with clang_getCursor
	if f.CName == "clang_getTranslationUnitCursor" {
		return "TranslationUnitCursor"
	}

	return ""
}

// PrepareStructFields prepares struct fields names.
func PrepareStructFields(s *gen.Struct) {
	for _, f := range s.Fields {
		if (strings.HasPrefix(f.CName, "has") || strings.HasPrefix(f.CName, "is")) && f.Type.GoName == gen.GoInt32 {
			f.Type.GoName = gen.GoBool
		}

		// if this is an array length parameter we need to find its partner
		faCName := gen.ArrayNameFromLength(f.CName)

		if faCName != "" {
			for _, fa := range s.Fields {
				if strings.EqualFold(fa.CName, faCName) {
					f.Type.LengthOfSlice = fa.CName
					fa.Type.IsSlice = true
					// TODO(go-clang): wrong usage but needed for the getter generation...
					// maybe refactor this LengthOfSlice all together?
					// https://github.com/go-clang/gen/issues/49
					fa.Type.LengthOfSlice = f.CName

					break
				}
			}
		}
	}

	prepareStructFieldsArrayStruct(s)
}

// prepareStructFieldsArrayStruct checks if the struct has two field variables, one is an array and the other a plain
// int/uint with size/length/count/len is its name because then this should be an array struct, and we connect them to handle a slice.
func prepareStructFieldsArrayStruct(s *gen.Struct) {
	if len(s.Fields) != 2 {
		return
	}

	if !arrayLengthCombination(&s.Fields[0].Type, &s.Fields[1].Type) && !arrayLengthCombination(&s.Fields[1].Type, &s.Fields[0].Type) {
		return
	}

	// if one of the fields is already marked as array/slice another heuristic has already covered both fields
	switch {
	case s.Fields[0].Type.IsArray,
		s.Fields[1].Type.IsArray,
		s.Fields[0].Type.IsSlice,
		s.Fields[1].Type.IsSlice:

		return
	}

	var a *gen.StructField
	var c *gen.StructField

	if s.Fields[0].Type.PointerLevel == 1 {
		a = s.Fields[0]
		c = s.Fields[1]
	} else {
		c = s.Fields[0]
		a = s.Fields[1]
	}

	lengthName := strings.ToLower(c.CName)
	if lengthName != "count" &&
		lengthName != "len" && lengthName != "length" && lengthName != "size" {

		return
	}

	c.Type.LengthOfSlice = a.CName
	a.Type.IsSlice = true
	// TODO(go-clang): wrong usage but needed for the getter generation...
	// maybe refactor this LengthOfSlice all together?
	// https://github.com/go-clang/gen/issues/49
	a.Type.LengthOfSlice = c.CName
}

// arrayLengthCombination reports whether the x and y to correct combination.
func arrayLengthCombination(x *gen.Type, y *gen.Type) bool {
	return x.PointerLevel == 1 && y.PointerLevel == 0 &&
		!gen.IsInteger(x) && gen.IsInteger(y)
}

// FilterStructFieldGetter reports whether the m struct field filtered to a particular condition.
func FilterStructFieldGetter(f *gen.StructField) bool {
	// we do not want getters to *int_data fields
	return !strings.HasSuffix(f.CName, "int_data")
}
<|endoftext|>


<commit_before>package cc1100

import (
	"bytes"
	"fmt"

	"github.com/ecc1/gpio"
	"github.com/ecc1/radio"
	"github.com/ecc1/spi"
)

const (
	spiSpeed  = 6000000 // Hz
	gpioPin   = 14      // Intel Edison GPIO connected to GDO0
	hwVersion = 0x0014
)

type Radio struct {
	device       *spi.Device
	interruptPin gpio.InputPin

	radioStarted       bool
	receiveBuffer      bytes.Buffer
	transmittedPackets chan radio.Packet
	receivedPackets    chan radio.Packet
	interrupt          chan struct{}
	stats              radio.Statistics
}

func Open() (*Radio, error) {
	dev, err := spi.Open(spiSpeed)
	if err != nil {
		return nil, err
	}
	err = dev.SetMaxSpeed(spiSpeed)
	if err != nil {
		return nil, err
	}
	pin, err := gpio.Input(gpioPin, "both", false)
	if err != nil {
		return nil, err
	}
	r := &Radio{
		device:             dev,
		interruptPin:       pin,
		transmittedPackets: make(chan radio.Packet, 100),
		receivedPackets:    make(chan radio.Packet, 10),
		interrupt:          make(chan struct{}, 10),
	}
	v, err := r.Version()
	if err == nil && v != hwVersion {
		err = fmt.Errorf("unexpected hardware version (%04X instead of %04X)", v, hwVersion)
	}
	return r, err
}

func (r *Radio) Init(frequency uint32) error {
	err := r.Reset()
	if err != nil {
		return err
	}
	err = r.InitRF(frequency)
	if err != nil {
		return err
	}
	r.Start()
	return nil
}

func (r *Radio) Statistics() radio.Statistics {
	return r.stats
}
<commit_msg>Don't use buffered channel for interrupts<commit_after>package cc1100

import (
	"bytes"
	"fmt"

	"github.com/ecc1/gpio"
	"github.com/ecc1/radio"
	"github.com/ecc1/spi"
)

const (
	spiSpeed  = 6000000 // Hz
	gpioPin   = 14      // Intel Edison GPIO connected to GDO0
	hwVersion = 0x0014
)

type Radio struct {
	device       *spi.Device
	interruptPin gpio.InputPin

	radioStarted       bool
	receiveBuffer      bytes.Buffer
	transmittedPackets chan radio.Packet
	receivedPackets    chan radio.Packet
	interrupt          chan struct{}
	stats              radio.Statistics
}

func Open() (*Radio, error) {
	dev, err := spi.Open(spiSpeed)
	if err != nil {
		return nil, err
	}
	err = dev.SetMaxSpeed(spiSpeed)
	if err != nil {
		return nil, err
	}
	pin, err := gpio.Input(gpioPin, "both", false)
	if err != nil {
		return nil, err
	}
	r := &Radio{
		device:             dev,
		interruptPin:       pin,
		transmittedPackets: make(chan radio.Packet, 100),
		receivedPackets:    make(chan radio.Packet, 100),
		interrupt:          make(chan struct{}),
	}
	v, err := r.Version()
	if err == nil && v != hwVersion {
		err = fmt.Errorf("unexpected hardware version (%04X instead of %04X)", v, hwVersion)
	}
	return r, err
}

func (r *Radio) Init(frequency uint32) error {
	err := r.Reset()
	if err != nil {
		return err
	}
	err = r.InitRF(frequency)
	if err != nil {
		return err
	}
	r.Start()
	return nil
}

func (r *Radio) Statistics() radio.Statistics {
	return r.stats
}
<|endoftext|>