Example #1
0
func (p *proxy) handleConnection(conn net.Conn, serverAddr string) {
	var err error
	defer func() {
		if p := recover(); p != nil {
			fmt.Printf("error in handling connection: %v", p)
			conn.Close()
		} else {
			// Log disconnections: right now, we still return EOF
			// errors for connections that are closed "cleanly"
			// (e.g., client disconnects or server crashes) rather
			// than due to any problems encountered during
			// protocol manipulation. We assume that any
			// connectivity errors are "clean" and we ignore them
			// for now.
			if err != nil && err != io.EOF {
				log.Print("Session exits with error: ", err)
			} else {
				log.Print("Session exits cleanly")
			}
		}
	}()

	feStream := core.NewFrontendStream(util.NewBufferedReadWriteCloser(conn))
	var m core.Message
	err = feStream.Next(&m)
	if err != nil {
		panic(fmt.Errorf("could not read client startup message: %v", err))
	}
	if proto.IsStartupMessage(&m) {
		startup, err := proto.ReadStartupMessage(&m)
		if err != nil {
			panic(fmt.Errorf("could not parse client startup message: %v", err))
		}
		connector := p.resolver.Resolve(startup.Params)
		beStream, err := connector.Startup()
		if err != nil {
			panic(fmt.Errorf("could not connect to backend: %v", err))
		}
		router := femebe.NewSimpleRouter(feStream, beStream)
		session := femebe.NewSimpleSession(router, connector)
		err = p.manager.RunSession(session)
	} else if proto.IsSSLRequest(&m) {
		log.Print("SSL not supported; try with PGSSLMODE=disable")
	} else if proto.IsCancelRequest(&m) {
		cancel, err := proto.ReadCancelRequest(&m)
		if err != nil {
			panic(fmt.Errorf("could not parse cancel message: %v", err))
		}
		err = p.manager.Cancel(cancel.BackendPid, cancel.SecretKey)
		if err != nil {
			panic(fmt.Errorf("could not process cancellation: %v", err))
		}
		err = conn.Close()
		if err != nil {
			fmt.Println(err)
		}
	} else {
		panic(fmt.Errorf("could not understand client"))
	}
}
func (c *FrontendConnection) startup(startupParameters map[string]string, dbcfg VirtualDatabaseConfiguration) bool {
	var message fbcore.Message
	var err error

	for {
		err = c.stream.Next(&message)
		if err != nil {
			elog.Logf("error while reading startup packet: %s", err)
			return false
		}
		if fbproto.IsStartupMessage(&message) {
			break
		} else if fbproto.IsSSLRequest(&message) {
			_, err = message.Force()
			if err != nil {
				elog.Logf("error while reading SSLRequest: %s", err)
				return false
			}
			err = c.stream.SendSSLRequestResponse(fbcore.RejectSSLRequest)
			if err != nil {
				elog.Logf("error during startup sequence: %s", err)
				return false
			}
			err = c.FlushStream()
			if err != nil {
				elog.Logf("error during startup sequence: %s", err)
			}
		} else if fbproto.IsCancelRequest(&message) {
			_ = c.stream.Close()
			return false
		} else {
			elog.Warningf("unrecognized frontend message type 0x%x during startup", message.MsgType())
			return false
		}
	}
	sm, err := fbproto.ReadStartupMessage(&message)
	if err != nil {
		elog.Logf("error while reading startup packet: %s", err)
		return false
	}

	if !c.auth(dbcfg, sm) {
		// error already logged
		_ = c.stream.Close()
		return false
	}

	fbproto.InitAuthenticationOk(&message)
	err = c.WriteMessage(&message)
	if err != nil {
		elog.Logf("error during startup sequence: %s", err)
		return false
	}

	for k, v := range startupParameters {
		buf := &bytes.Buffer{}
		fbbuf.WriteCString(buf, k)
		fbbuf.WriteCString(buf, v)
		message.InitFromBytes(fbproto.MsgParameterStatusS, buf.Bytes())
		err = c.WriteMessage(&message)
		if err != nil {
			elog.Logf("error during startup sequence: %s", err)
			return false
		}
	}

	fbproto.InitReadyForQuery(&message, fbproto.RfqIdle)
	err = c.WriteMessage(&message)
	if err != nil {
		elog.Logf("error during startup sequence: %s", err)
		return false
	}

	err = c.FlushStream()
	if err != nil {
		elog.Logf("error during startup sequence: %s", err)
		return false
	}
	return true
}