Terminacion O5LOGON server-side
OxGate juega el rol de un servidor Oracle durante la autenticacion del cliente: ACCEPT, NSP, TTIPRO/TTIDTY, AUTH_PHASE_ONE/TWO, AUTH_OK — con mimic byte-perfect tanto de OCI 12.1 como de IC 11.2. Lo que solo libclntsh.so hace normalmente.
Pool backend autenticado
Pre-abre sesiones backend autenticadas via service account. Toma de idle en hot path; abre nuevas hasta max_total bajo rafaga; reabastece idle en background. Caps capturadas del primer connect, ecoadas a los clientes para evitar drift.
Soporte multi-flavor del wire
Detecta el flavor del cliente desde las caps del CONNECT (sqlplus OCI 12.1, ODP.NET Unmanaged 12.1, ODP.NET Managed 23.x, JDBC Thin, ODP.NET Unmanaged + IC 11.2). Cada flavor usa su propio set de templates — catalogo TTIDTY, encoding chunked de AUTH_SESSKEY, ancho de framing — para que el cliente reciba exactamente lo que su libreria espera.
Multi-pool con dialectos mezclados
Un mismo listener puede servir clientes OCI 12.1 y clientes IC 11.2 thick lado a lado. Los pools por usuario se configuran con un flag yaml use_oci_11 que selecciona el handshake del backend (proto::oci_mimic vs proto::oci_mimic_11). El bridge enruta pool_map.get(user) tras la auth server-side, asi cada cliente cae en una conn backend autenticada como su mismo usuario.
Multiplex N → M (Phase 3b)
Swap a nivel de statement: cuando un cliente cierra una transaccion y BridgeState reporta is_safe_to_release(), la sesion backend actual vuelve al pool y se acquire una fresca para el siguiente statement. N clientes logicos multiplexan sobre M sesiones backend con M ≪ N. Validado 20/20 mixed paralelos contra IC 11.2 + OCI 12.1, cero auth_fail.
Parking de backend idle-limpio
Los clientes legacy (drivers Oracle viejos, pools client-side) mantienen sesiones TNS abiertas durante el think-time del usuario. Cuando un bridge esta limpio (is_safe_to_release()) y en silencio mas alla de OXGATE_IDLE_PARK_SECS, OxGate devuelve su backend al pool y re-adquiere uno en el proximo paquete — re-corriendo la rotacion lb_ports + cuarentena. Muchos clientes idle comparten pocos backends en vez de pinear 1:1. Mismo gate de seguridad que el swap; nunca cierra ni hace rollback. Soak en prod: 13/15 sesiones parqueadas, reuse 38% → 82%, cero ORA-01001/03137.
Combo_key try-multiple (O3LOGON)
ODP.NET Managed y la familia JDBC Thin comparten fingerprint del wire entre versiones pero difieren en la derivacion del combo_key (PBKDF2-SHA512 vs MD5(server[16..32] XOR client[16..32])). El validador prueba cada candidato por flavor y acepta el primero que produce padding PKCS7 valido Y password match — sin parsear el flag logonCompatibility, sin frialdad por deteccion de version.
Aislamiento transaccional al reusar
Antes de devolver una sesion al pool: rollback() + ping() bajo cap duro de 1.5s. DML no commiteado del cliente anterior no leakea. Si el cleanup expira, la sesion se descarta y el replenisher mintea una fresca.
Audit trail de sesion completo
Cada sesion emite eventos JSON estructurados al stream oxgate_audit: client_accept, auth_ok/auth_fail, backend_acquired/released, multiplex_swap, y el cierre — sea client_logoff (LOGOFF limpio) o client_disconnect con reason=client_eof | backend_eof | zombie_timeout. Cero cierres invisibles: cualquier FIN del lado proxy queda registrado para SIEM/HIPAA.
Enriquecimiento de identidad de sesion
client_accept captura os_user y program (ej. wsGestionVenta / w3wp.exe) del paquete CONNECT. Un mapa server-side por session_id rellena esos campos en cada evento posterior de la misma sesion (backend_acquired/released, client_logoff) en tiempo de lectura — la consola nombra a la app responsable sin un join fragil del lado cliente.
Observabilidad in-flight read-only
GET /v1/inflight lista cada sesion que tiene (o parquea) un backend con idle_secs (silencio, no tiempo de vida), tx_active, open_cursors, clase del ultimo statement (nunca texto SQL) y parked. GET /v1/clients lo agrega por (os_user, ip): quien retiene cuantas, cuantas idle-in-txn, sobre umbral. El proxy observa — nunca mata ni hace rollback a un cliente.
Alertas de idle-largo + cursor-leak
Un scanner en background emite long_inflight una vez por sesion que queda en silencio mas alla de OXGATE_INFLIGHT_ALERT_SECS (re-armado cuando vuelve el trafico — basado en idle, asi las conexiones reusadas de larga vida no dan falsas alarmas), y cursor_leak cuando una sesion tiene ≥ OXGATE_CURSOR_LEAK_THRESHOLD cursores abiertos (el patron ORA-01000). Ambas son señales read-only + lineas WARN para ops; OxGate no toma accion.
Load-balance de listeners con cuarentena por puerto
Round-robin de cada handshake nuevo entre N listeners Oracle (tipicamente N nodos RAC o dispatcher groups). Cada puerto trackea fallos consecutivos: tras 3 fails en linea, ese puerto sale de rotacion 30 s. Cualquier success limpia el estado. Si todos quedan en cuarentena, fallback al primary oracle_port — modo marte: nunca sin opciones.
Failover reactivo de listener (post-PH1 mismatch)
Si el listener primario entrega un socket TCP a un backend mid-OPI (responde DCB column metadata en lugar de AUTH_PHASE_ONE — observado en produccion 2026-05-25), el bridge recorre targets[*].failover_ports hasta encontrar uno que devuelva AUTH valido. Audit listener_failover_recovered queda registrado en cada save. Distinto de load_balance_ports (distribucion activa).
TCP keepalive en sockets cliente
SO_KEEPALIVE 30 s / 10 s × 3 retries activado en el accept() loop. Half-open clients (kill -9, NAT/VPN sin estado, laptop suspendida) se reapean en ~60 s en vez de inflar contadores /v1/apps active para siempre.
Modo Marte — nunca cae
Lazy boot (Oracle inalcanzable al arrancar), circuit breaker en backend connect, ping de validate-on-acquire (atrapa idles muertos), drain timeout en desconexion abrupta, acquire timeout en saturacion. Cada capa responde en tiempo acotado.