ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
ssh_flow_control.h File Reference

SSH channel flow control - the RFC 4254 sec 5.2 window pair and nothing else. More...

#include <stddef.h>
#include <stdint.h>

Go to the source code of this file.

Classes

struct  SshFlow
 One channel's flow-control state (RFC 4254 sec 5.2). More...
 

Functions

void pc_ssh_flow_init (SshFlow *f, uint32_t local_window, uint32_t peer_window, uint32_t peer_max_pkt)
 Start a channel's windows: ours at local_window, the peer's at what it advertised.
 
bool pc_ssh_flow_recv_take (SshFlow *f, uint32_t n)
 Account n inbound bytes against our window.
 
bool pc_ssh_flow_replenish_due (const SshFlow *f, uint32_t *add)
 Decide whether a WINDOW_ADJUST is due, and for how much. Does not mutate.
 
void pc_ssh_flow_local_credit (SshFlow *f, uint32_t add)
 Credit our window by add, once that WINDOW_ADJUST has actually been sent.
 
bool pc_ssh_flow_send_allows (const SshFlow *f, size_t len)
 True if len bytes fit both the peer's remaining window and its maximum packet size.
 
uint32_t pc_ssh_flow_send_cap (const SshFlow *f, uint32_t want)
 Clamp a would-be send to what the peer currently permits.
 
void pc_ssh_flow_send_take (SshFlow *f, uint32_t n)
 Account n outbound bytes against the peer's window (call only after send_allows()).
 
void pc_ssh_flow_peer_add (SshFlow *f, uint32_t add)
 Credit the peer's window from an inbound WINDOW_ADJUST.
 
uint32_t pc_ssh_flow_peer_window (const SshFlow *f)
 Bytes we may still send the peer - the bound a producer sizes its next read to.
 
int32_t pc_ssh_sig_build_open_failure (uint8_t *out, size_t cap, uint32_t peer_id, uint32_t reason, size_t *out_len)
 CHANNEL_OPEN_FAILURE. reason: 1 admin-prohibited, 2 connect-failed, 3 unknown-type, 4 resource.
 
int32_t pc_ssh_sig_build_open_confirm (const SshFlow *f, uint32_t peer_id, uint32_t local_id, uint8_t *out, size_t cap, size_t *out_len)
 CHANNEL_OPEN_CONFIRMATION, advertising our current window and maximum packet size.
 
int32_t pc_ssh_sig_build_data (SshFlow *f, uint32_t peer_id, const uint8_t *data, size_t len, uint8_t *out, size_t cap, size_t *out_len)
 CHANNEL_DATA carrying len bytes, and account them against the peer's window.
 
int32_t pc_ssh_sig_build_window_adjust (uint32_t peer_id, uint32_t add, uint8_t *out, size_t cap, size_t *out_len)
 CHANNEL_WINDOW_ADJUST granting add more bytes. Credit the window only once this is sent.
 
int32_t pc_ssh_sig_build_close (uint32_t peer_id, uint8_t *out, size_t cap, size_t *out_len)
 CHANNEL_EOF followed by CHANNEL_CLOSE, as one 10-byte pair.
 

Detailed Description

SSH channel flow control - the RFC 4254 sec 5.2 window pair and nothing else.

Every channel carries two independent counters: how many bytes the peer may still send us before we replenish (local), and how many we may still send it (peer). Getting either wrong desynchronizes the session - overrun the peer's window and it drops the channel, forget to replenish ours and the transfer stalls forever with both sides waiting.

The accounting lived in four places before this file existed: ssh_channel.cpp held the counters and the rules, ssh_forward.cpp read peer_window directly to size its reads, ssh_server.cpp routed the adjust message, and ssh_client.cpp carried a second implementation of the same arithmetic. One concern, one owner: the counters are only correct if a single piece of code decides what they mean.

Channel multiplexing stays in ssh_channel.* - this file knows nothing about channel ids, types, or the pool. It is the arithmetic and the rules, over one channel's pair of counters.

Definition in file ssh_flow_control.h.

Function Documentation

◆ pc_ssh_flow_init()

void pc_ssh_flow_init ( SshFlow f,
uint32_t  local_window,
uint32_t  peer_window,
uint32_t  peer_max_pkt 
)

Start a channel's windows: ours at local_window, the peer's at what it advertised.

The local window is a parameter rather than a baked-in constant because the server and the client advertise different sizes, and the value we replenish to must be the value we told the peer about. Passing it here keeps the two from drifting apart.

Parameters
local_windowwhat we advertise in CHANNEL_OPEN / CONFIRMATION; also the replenish target.
peer_windowthe peer's initial window from CHANNEL_OPEN / CONFIRMATION.
peer_max_pktthe peer's maximum packet size from the same message.

Definition at line 15 of file ssh_flow_control.cpp.

References SshFlow::local_max, SshFlow::local_window, SshFlow::peer_max_pkt, and SshFlow::peer_window.

Referenced by pc_ssh_channel_handle_open(), and pc_ssh_channel_open_forwarded().

◆ pc_ssh_flow_recv_take()

bool pc_ssh_flow_recv_take ( SshFlow f,
uint32_t  n 
)

Account n inbound bytes against our window.

Returns
false if n exceeds what we advertised - the peer overran the window (RFC 4254 sec 5.2) and the caller must fail the channel. The window is left untouched on failure.

Definition at line 23 of file ssh_flow_control.cpp.

References SshFlow::local_window.

Referenced by pc_ssh_channel_handle_data().

◆ pc_ssh_flow_replenish_due()

bool pc_ssh_flow_replenish_due ( const SshFlow f,
uint32_t *  add 
)

Decide whether a WINDOW_ADJUST is due, and for how much. Does not mutate.

Replenishes once the window has drained past half, which keeps a bulk transfer from stalling without emitting an adjust per packet.

Pair it with pc_ssh_flow_local_credit() only after the adjust has actually gone out. Deciding and crediting are separate because on some paths the send can fail, and crediting first would leave us believing we advertised bytes the peer never heard about - the peer then stops at its smaller window while we wait for data, and the transfer deadlocks.

Returns
true if a WINDOW_ADJUST is due; *add receives the delta to advertise.

Definition at line 33 of file ssh_flow_control.cpp.

References SshFlow::local_max, and SshFlow::local_window.

Referenced by pc_ssh_channel_handle_data().

◆ pc_ssh_flow_local_credit()

void pc_ssh_flow_local_credit ( SshFlow f,
uint32_t  add 
)

Credit our window by add, once that WINDOW_ADJUST has actually been sent.

Definition at line 43 of file ssh_flow_control.cpp.

References SshFlow::local_window.

Referenced by pc_ssh_channel_handle_data().

◆ pc_ssh_flow_send_allows()

bool pc_ssh_flow_send_allows ( const SshFlow f,
size_t  len 
)

True if len bytes fit both the peer's remaining window and its maximum packet size.

Definition at line 48 of file ssh_flow_control.cpp.

References SshFlow::peer_max_pkt, and SshFlow::peer_window.

Referenced by pc_ssh_sig_build_data().

◆ pc_ssh_flow_send_cap()

uint32_t pc_ssh_flow_send_cap ( const SshFlow f,
uint32_t  want 
)

Clamp a would-be send to what the peer currently permits.

A producer that pulls from a local source sizes its read to this, so it never reads bytes it cannot legally forward. Returns 0 when the window is closed, which the caller treats as "stop pumping until a WINDOW_ADJUST arrives".

Returns
min(want, peer window, peer maximum packet size).

Definition at line 53 of file ssh_flow_control.cpp.

References SshFlow::peer_max_pkt, and SshFlow::peer_window.

◆ pc_ssh_flow_send_take()

void pc_ssh_flow_send_take ( SshFlow f,
uint32_t  n 
)

Account n outbound bytes against the peer's window (call only after send_allows()).

Definition at line 67 of file ssh_flow_control.cpp.

References SshFlow::peer_window.

Referenced by pc_ssh_sig_build_data().

◆ pc_ssh_flow_peer_add()

void pc_ssh_flow_peer_add ( SshFlow f,
uint32_t  add 
)

Credit the peer's window from an inbound WINDOW_ADJUST.

Saturates at UINT32_MAX rather than wrapping: a peer advertising a total past 2^32 is out of spec, and wrapping would hand us a tiny window and stall the transfer.

Definition at line 72 of file ssh_flow_control.cpp.

References SshFlow::peer_window.

Referenced by pc_ssh_channel_handle_open_confirm(), and pc_ssh_channel_handle_window_adjust().

◆ pc_ssh_flow_peer_window()

uint32_t pc_ssh_flow_peer_window ( const SshFlow f)

Bytes we may still send the peer - the bound a producer sizes its next read to.

Definition at line 78 of file ssh_flow_control.cpp.

References SshFlow::peer_window.

◆ pc_ssh_sig_build_open_failure()

int32_t pc_ssh_sig_build_open_failure ( uint8_t *  out,
size_t  cap,
uint32_t  peer_id,
uint32_t  reason,
size_t *  out_len 
)

CHANNEL_OPEN_FAILURE. reason: 1 admin-prohibited, 2 connect-failed, 3 unknown-type, 4 resource.

Definition at line 87 of file ssh_flow_control.cpp.

References pc_wr32be(), and SSH_MSG_CHANNEL_OPEN_FAILURE.

◆ pc_ssh_sig_build_open_confirm()

int32_t pc_ssh_sig_build_open_confirm ( const SshFlow f,
uint32_t  peer_id,
uint32_t  local_id,
uint8_t *  out,
size_t  cap,
size_t *  out_len 
)

CHANNEL_OPEN_CONFIRMATION, advertising our current window and maximum packet size.

Definition at line 102 of file ssh_flow_control.cpp.

References SshFlow::local_window, pc_wr32be(), SSH_CHAN_MAX_PACKET, and SSH_MSG_CHANNEL_OPEN_CONFIRM.

◆ pc_ssh_sig_build_data()

int32_t pc_ssh_sig_build_data ( SshFlow f,
uint32_t  peer_id,
const uint8_t *  data,
size_t  len,
uint8_t *  out,
size_t  cap,
size_t *  out_len 
)

CHANNEL_DATA carrying len bytes, and account them against the peer's window.

Refuses when the send would exceed the peer's window or its maximum packet size, so the RFC 4254 sec 5.2 limit cannot be violated by any caller - the check and the debit are one step here.

Definition at line 118 of file ssh_flow_control.cpp.

References pc_ssh_flow_send_allows(), pc_ssh_flow_send_take(), pc_wr32be(), and SSH_MSG_CHANNEL_DATA.

Referenced by pc_ssh_channel_build_data().

◆ pc_ssh_sig_build_window_adjust()

int32_t pc_ssh_sig_build_window_adjust ( uint32_t  peer_id,
uint32_t  add,
uint8_t *  out,
size_t  cap,
size_t *  out_len 
)

CHANNEL_WINDOW_ADJUST granting add more bytes. Credit the window only once this is sent.

Definition at line 138 of file ssh_flow_control.cpp.

References pc_wr32be(), and SSH_MSG_CHANNEL_WINDOW_ADJUST.

◆ pc_ssh_sig_build_close()

int32_t pc_ssh_sig_build_close ( uint32_t  peer_id,
uint8_t *  out,
size_t  cap,
size_t *  out_len 
)

CHANNEL_EOF followed by CHANNEL_CLOSE, as one 10-byte pair.

Definition at line 151 of file ssh_flow_control.cpp.

References pc_wr32be(), SSH_MSG_CHANNEL_CLOSE, and SSH_MSG_CHANNEL_EOF.