docs: handshake documentation

This commit is contained in:
Jindřich Moravec 2023-12-31 18:45:50 +01:00
parent eb8410718d
commit c61b6021db
5 changed files with 28 additions and 3 deletions

View file

@ -7,15 +7,20 @@ use crate::reader::backend::BackendProtoReader;
use crate::writer::frontend::FrontendProtoWriter;
use crate::writer::protowriter::ProtoFlush;
/// Performs client-side handshake with the server until the `ReadyForQuery` message is received.
/// For more info visit the [`55.2.1. Start-up`](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-START-UP)
pub async fn do_client_handshake(
writer: &mut (impl FrontendProtoWriter + ProtoFlush),
reader: &mut impl BackendProtoReader,
request: HandshakeRequest,
) -> Result<HandshakeResponse, ClientHandshakeError> {
// Send StartupMessage without SSLRequest
let startup_message: StartupMessageData = request.into();
writer.write_startup_message(startup_message).await?;
writer.flush().await?;
// Wait for AuthenticationOk
let auth = reader.read_proto().await?;
if !matches!(
auth,
@ -24,6 +29,7 @@ pub async fn do_client_handshake(
return Err(ClientHandshakeError::UnexpectedAuthResponse(auth));
}
// Read server parameter messages until ReadyForQuery is received
let mut messages = Vec::new();
loop {
let msg = reader.read_proto().await?;

View file

@ -3,11 +3,14 @@ use crate::message::special::StartupMessageData;
#[derive(Debug)]
pub struct HandshakeRequest {
version: i32,
parameters: Vec<(PgString, PgString)>,
pub version: i32,
pub parameters: Vec<(PgString, PgString)>,
}
impl HandshakeRequest {
/// Creates a new `HandshakeRequest` with the specified version.
/// Expected `version` is 196608 (3.0).
pub fn new(version: i32) -> Self {
Self {
version,
@ -15,6 +18,9 @@ impl HandshakeRequest {
}
}
/// Adds a parameter to the startup message.
/// Generally recognized names are `user`, `database`, `option` and `replication` but others can be used.
/// For more info visit [`StartupMessage`](https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-STARTUPMESSAGE)
pub fn parameter(mut self, key: &str, value: &str) -> Self {
self.parameters.push((key.into(), value.into()));
self

View file

@ -11,7 +11,7 @@ pub struct HandshakeResponse {
impl HandshakeResponse {
pub fn new(name: &str, pid: i32, key: i32) -> Self {
Self {
version: format!("16.0 ({name})", name = name),
version: format!("16.0 ({name})"),
process_id: pid,
secret_key: key,
}
@ -37,6 +37,7 @@ impl TryFrom<&[BackendMessage]> for HandshakeResponse {
process_id = Some(data.process);
secret_key = Some(data.secret);
}
// Different messages are ignored during the handshake
_ => {}
}
}

View file

@ -7,11 +7,15 @@ use crate::reader::frontend::FrontendProtoReader;
use crate::writer::backend::BackendProtoWriter;
use crate::writer::protowriter::ProtoFlush;
/// Performs server-side handshake with the client until ending it with `ReadyForQuery` message.
/// For more info visit the [`55.2.1. Start-up`](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-START-UP)
pub async fn do_server_handshake(
writer: &mut (impl BackendProtoWriter + ProtoFlush),
reader: &mut impl FrontendProtoReader,
response: HandshakeResponse,
) -> Result<HandshakeRequest, ServerHandshakeError> {
// Check if client requested SSL
match &reader.peek_special_message().await? {
Some(msg @ SpecialMessage::SSLRequest) => {
reader.consume_special_message(msg).await?;
@ -23,6 +27,7 @@ pub async fn do_server_handshake(
}
}
// Wait for mandatory StartupMessage
let startup_message = match &reader.peek_special_message().await? {
Some(msg @ SpecialMessage::StartupMessage(data)) => {
reader.consume_special_message(msg).await?;
@ -33,15 +38,18 @@ pub async fn do_server_handshake(
}
};
// Authenticate client
writer
.write_proto(BackendMessage::from(AuthenticationOkData { status: 0 }))
.await?;
// Send server parameters
let messages: Vec<BackendMessage> = response.into();
for message in messages {
writer.write_proto(message).await?;
}
// Finish the handshake
writer
.write_proto(BackendMessage::from(ReadyForQueryData { status: b'I' }))
.await?;

View file

@ -1,3 +1,7 @@
//! # PostgreSQL 16 Protocol
//! Low-level PostgreSQL protocol implementation for the version 16, protocol version 3.0.
//! Includes server and client side handshake with no password authentication.
pub mod handshake;
pub mod message;
pub mod reader;