예제 #1
0
파일: porcelain.go 프로젝트: johto/femebe
func (c *simpleConnector) dial() (core.Stream, error) {
	bareConn, err := util.AutoDial(c.backendAddr)
	if err != nil {
		return nil, fmt.Errorf("could not connect to %v: %v", c.backendAddr, err)
	}

	// the simpleConnector always prefers TLS
	beConn, err := util.NegotiateTLS(bareConn, &util.SSLConfig{
		Mode:   util.SSLPrefer,
		Config: tls.Config{InsecureSkipVerify: true},
	})
	if err != nil {
		return nil, fmt.Errorf("could not negotiate TLS: %v", err)
	}

	return core.NewBackendStream(beConn), nil
}
예제 #2
0
func logWorker(die dieCh, l net.Listener, cfg logplexc.Config, sr *serveRecord) {
	// Make world-writable so anything can connect and send logs.
	// This may be be worth locking down more, but as-is unless
	// pg_logplexcollector and the Postgres server share the same
	// running user common umasks will be useless.
	fi, err := os.Stat(sr.P)
	if err != nil {
		log.Fatalf(
			"exiting, cannot stat just created socket %q: %v",
			sr.P, err)
	}

	err = os.Chmod(sr.P, fi.Mode().Perm()|0222)
	if err != nil {
		log.Fatalf(
			"exiting, cannot make just created socket "+
				"world-writable %q: %v",
			sr.P, err)
	}

	for {
		select {
		case <-die:
			log.Print("listener exits normally from die request")
			return
		default:
			break
		}

		conn, err := l.Accept()
		if err != nil {
			log.Printf("accept error: %v", err)
		}

		if err != nil {
			log.Fatalf("serve database suffers unrecoverable "+
				"error: %v", err)
		}

		go func() {
			stream := core.NewBackendStream(conn)

			var exit exitFn
			exit = func(args ...interface{}) {
				if len(args) == 1 {
					log.Printf("Disconnect client: %v", args[0])
				} else if len(args) > 1 {
					if s, ok := args[0].(string); ok {
						log.Printf(s, args[1:]...)
					} else {
						// Not an intended use case, but do
						// one's best to print something.
						log.Printf("Got a malformed exit: %v", args)
					}
				}

				panic(&exit)
			}

			// Recovers from panic and exits in an orderly manner if (and
			// only if) exit() is called; otherwise propagate the panic
			// normally.
			defer func() {
				conn.Close()

				// &exit is used as a sentinel value.
				if r := recover(); r != nil && r != &exit {
					panic(r)
				}
			}()

			var msgInit msgInit
			msgInit = func(m *core.Message, exit exitFn) {
				err = stream.Next(m)
				if err == io.EOF {
					exit("postgres client disconnects")
				} else if err != nil {
					exit("could not read next message: %v", err)
				}
			}

			// Protocol start-up; packets that are only received once.
			processVerMsg(msgInit, exit)
			ident := processIdentMsg(msgInit, exit)
			log.Printf("client connects with identifier %q", ident)

			// Resolve the identifier to a serve
			if sr.I != ident {
				exit("got unexpected identifier for socket: "+
					"path %s, expected %s, got %s", sr.P, sr.I, ident)
			}

			// Set up client with serve
			client := func(cfg logplexc.Config, url *url.URL) *logplexc.Client {
				cfg.Logplex = *url
				client, err := logplexc.NewClient(&cfg)
				if err != nil {
					exit(err)
				}

				return client
			}

			primary := client(cfg, &sr.u)

			var audit *logplexc.Client

			if sr.audit != nil {
				audit = client(cfg, sr.audit)
			}

			defer func() {
				primary.Close()

				if audit != nil {
					audit.Close()
				}
			}()

			processLogMsg(die, primary, audit, msgInit, sr, exit)
		}()
	}
}