Server-side O5LOGON termination
OxGate plays the role of an Oracle server during the client's auth: ACCEPT, NSP, TTIPRO/TTIDTY, AUTH_PHASE_ONE/TWO, AUTH_OK template — including OCI 12.1 and IC 11.2 byte-perfect mimic. What only libclntsh.so does normally.
Authenticated backend pool
Pre-opens authenticated backend sessions via a service account. Acquires from idle on the hot path; opens new sessions up to max_total under burst; replenishes idle in the background. Caps captured from the first connect, echoed to clients to prevent cap drift.
Multi-flavor wire support
Detects client flavor from CONNECT caps (sqlplus OCI 12.1, ODP.NET Unmanaged 12.1, ODP.NET Managed 23.x, JDBC Thin, ODP.NET Unmanaged + IC 11.2). Each flavor uses its own template set — TTIDTY catalog, AUTH_SESSKEY chunked encoding, framing width — so clients see exactly what their library expects.
Multi-pool with mixed dialects
A single listener can serve OCI 12.1 clients and IC 11.2 thick clients side by side. Per-user pools are configured with a use_oci_11 yaml flag selecting the backend handshake (proto::oci_mimic vs proto::oci_mimic_11). The bridge routes pool_map.get(user) after server-side auth so each client lands on a backend authenticated as the same user.
N → M multiplex (Phase 3b)
Statement-level swap: when a client closes a transaction and BridgeState reports is_safe_to_release(), the current backend session is returned to the pool and a fresh one is acquired for the next statement. N concurrent client connections multiplex onto M backend sessions where M ≪ N. Validated 20/20 mixed parallel against IC 11.2 + OCI 12.1 backends, zero auth_fail.
Idle-clean backend parking
Legacy clients (old Oracle drivers, client-side pools) keep TNS sessions open through user think-time. When a bridge is clean (is_safe_to_release()) and silent past OXGATE_IDLE_PARK_SECS, OxGate returns its backend to the pool and re-acquires one on the next client packet — re-running lb_ports rotation + quarantine. Many idle clients share few backends instead of pinning 1:1. Same safety gate as the swap; never closes or rolls back the session. Prod soak: parked 13/15 sessions, reuse 38% → 82%, zero ORA-01001/03137.
Try-multiple combo_key (O3LOGON)
ODP.NET Managed and JDBC Thin family share a wire fingerprint across versions but differ in combo_key derivation (PBKDF2-SHA512 vs MD5(server[16..32] XOR client[16..32])). The validator tries each candidate per flavor and accepts the first that yields valid PKCS7 padding AND a matching password — no logonCompatibility flag parsing, no version detection brittleness.
Transactional isolation on reuse
Before returning a session to the pool: rollback() + ping() under a 1.5s hard cap. Uncommitted DML from the prior client cannot leak. If cleanup times out, the session is discarded and the replenisher mints a fresh one.
Full session audit trail
Every session emits structured JSON events to the oxgate_audit stream: client_accept, auth_ok/auth_fail, backend_acquired/released, multiplex_swap, and the close — either client_logoff (clean LOGOFF) or client_disconnect with reason=client_eof | backend_eof | zombie_timeout. No invisible closures: any FIN on the proxy side is logged for SIEM/HIPAA.
Session identity enrichment
client_accept captures os_user and program (e.g. wsGestionVenta / w3wp.exe) from the CONNECT packet. A server-side map keyed by session_id then backfills those fields onto every later same-session event (backend_acquired/released, client_logoff) at read time — so the dashboard names the responsible app without a fragile client-side join.
Read-only in-flight observability
GET /v1/inflight lists every session currently holding (or parked) a backend with idle_secs (silence, not lifetime), tx_active, open_cursors, last statement class (never SQL text), and parked. GET /v1/clients rolls it up by (os_user, ip): who holds how many, how many idle-in-txn, over threshold. The proxy observes — it never kills or rolls back a client.
Long-idle + cursor-leak alerts
A background scanner fires long_inflight once per session that stays silent past OXGATE_INFLIGHT_ALERT_SECS (re-armed when traffic resumes — based on idle, so reused long-lived connections never false-alarm), and cursor_leak when a session holds ≥ OXGATE_CURSOR_LEAK_THRESHOLD open cursors (the ORA-01000 pattern). Both are read-only signals + WARN lines for ops; OxGate takes no action.
Listener load-balance with per-port quarantine
Round-robin every fresh backend connect across N Oracle listener ports (typically N RAC nodes or dispatcher groups). Each port tracks consecutive failures: after 3 fails in a row, that port is quarantined out of rotation for 30 s. Any single success clears the state. If every port is quarantined, fall back to the primary oracle_port — never out of options.
Reactive listener failover (post-PH1 mismatch)
If the primary listener hands off a TCP socket to a backend that is mid-OPI (DCB column metadata instead of AUTH_PHASE_ONE — observed in production 2026-05-25), the bridge fallback walks targets[*].failover_ports in order until one returns a valid AUTH. Audit listener_failover_recovered records every save. Distinct from load_balance_ports (active distribution).
TCP keepalive on client sockets
SO_KEEPALIVE 30 s / 10 s × 3 retries enabled in the accept() loop. Half-open clients (kill -9, NAT/VPN state lost, laptop suspend) are reaped in ~60 s instead of inflating /v1/apps active counters forever.
Mars mode — never falls
Lazy boot (Oracle unreachable on start), circuit breaker on backend connect, validate-on-acquire ping (catches dead idles), drain timeout on abrupt disconnect, acquire timeout on saturation. Every layer answers within bounded time.