Skip to main content

scylla_proxy/
proxy.rs

1use crate::actions::{EvaluationContext, RequestRule, ResponseRule};
2use crate::errors::{DoorkeeperError, ProxyError, WorkerError};
3use crate::frame::{
4    self, FrameOpcode, FrameParams, RequestFrame, ResponseFrame, ResponseOpcode,
5    read_response_frame, write_frame,
6};
7use crate::{RequestOpcode, TargetShard};
8use bytes::Bytes;
9use compression::no_compression;
10use scylla_cql::frame::types::read_string_multimap;
11use std::collections::HashMap;
12use std::env::VarError;
13use std::fmt::Display;
14use std::future::Future;
15use std::net::{IpAddr, Ipv4Addr, SocketAddr};
16use std::sync::atomic::{AtomicBool, AtomicU8, AtomicU32, Ordering};
17use std::sync::{Arc, Mutex};
18use tokio::io::{AsyncRead, AsyncWrite};
19use tokio::net::{TcpListener, TcpSocket, TcpStream};
20use tokio::sync::mpsc::error::TryRecvError;
21use tokio::sync::{broadcast, mpsc};
22use tracing::{debug, error, info, trace, warn};
23
24// Used to notify the user that the proxy finished - this happens when all Senders are dropped.
25type FinishWaiter = mpsc::Receiver<()>;
26type FinishGuard = mpsc::Sender<()>;
27
28// Used to tell all the proxy workers to stop when the user requests that with [RunningProxy::finish()].
29type TerminateNotifier = tokio::sync::broadcast::Receiver<()>;
30type TerminateSignaler = tokio::sync::broadcast::Sender<()>;
31
32// Used to tell all proxy workers working on same connection to stop when
33// a rule being applied has connection drop set.
34type ConnectionCloseNotifier = tokio::sync::broadcast::Receiver<()>;
35type ConnectionCloseSignaler = tokio::sync::broadcast::Sender<()>;
36
37// Used to gather errors from all proxy workers and propagate them to the proxy user,
38// returning the first of them from [RunningProxy::finish()].
39type ErrorPropagator = mpsc::UnboundedSender<ProxyError>;
40type ErrorSink = mpsc::UnboundedReceiver<ProxyError>;
41
42static HARDCODED_OPTIONS_PARAMS: FrameParams = FrameParams {
43    flags: 0,
44    version: 0x04,
45    stream: 0,
46};
47
48/// Specifies proxy's behaviour regarding shard awareness.
49#[derive(Clone, Copy, Debug)]
50pub enum ShardAwareness {
51    /// Acts as if the connection was made to the shard-unaware port.
52    Unaware,
53    /// The first time the driver attempts to connect to the particular node (through proxy),
54    /// the related node is first queried on a temporary connection for its number of shards,
55    /// and only then establishes another connection for the driver's real communication with the node.
56    /// If the queried node does not provide sharding info (e.g. in case of a Cassandra node),
57    /// then this mode behaves as Unaware.
58    QueryNode,
59    /// Binds to the port that is the same as the driver's port modulo the provided number of shards.
60    FixedNum(u16),
61}
62
63impl ShardAwareness {
64    pub fn is_aware(&self) -> bool {
65        !matches!(self, Self::Unaware)
66    }
67}
68
69/// Node can be either Real (truly backed by a Scylla node) or Simulated
70/// (driver believes it's real, but we merely simulate it with the proxy).
71/// In Simulated mode, no node address is provided and proxy does not attempt
72/// to establish connection with a Scylla node.
73///
74/// For Real node, all workers are created, so such frame flow is possible:
75/// [driver] -> receiver_from_driver -> requests_processor -> sender_to_cluster -> [node] (ordinary request flow)
76///                                        |                    /\
77///     (forging response) ++--------------+      +-------------++ (forging request)
78///                        \/                     |
79/// [driver] <- sender_to_driver <- response_processor <- receiver_from_cluster <- [node] (ordinary response flow)
80///
81/// For Simulated node, it looks like this:
82/// [driver] -> receiver_from_driver -> requests_processor -+
83///                                                         |   (forging response)
84/// [driver] <- sender_to_driver <--------------------------+
85///
86/// For Real node, the default reaction to a frame is to pass it to its intended addresse.
87/// For Simulated node, the default reaction to a request is to drop it.
88enum NodeType {
89    Real {
90        real_addr: SocketAddr,
91        shard_awareness: ShardAwareness,
92        response_rules: Option<Vec<ResponseRule>>,
93    },
94    Simulated,
95}
96
97pub struct Node {
98    proxy_addr: SocketAddr,
99    request_rules: Option<Vec<RequestRule>>,
100    node_type: NodeType,
101}
102
103impl Node {
104    /// Creates an abstract node that is backed by a real Scylla node.
105    pub fn new(
106        real_addr: SocketAddr,
107        proxy_addr: SocketAddr,
108        shard_awareness: ShardAwareness,
109        request_rules: Option<Vec<RequestRule>>,
110        response_rules: Option<Vec<ResponseRule>>,
111    ) -> Self {
112        Self {
113            proxy_addr,
114            request_rules,
115            node_type: NodeType::Real {
116                real_addr,
117                shard_awareness,
118                response_rules,
119            },
120        }
121    }
122
123    /// Creates a simulated node that is not backed by any real Scylla node.
124    pub fn new_dry_mode(proxy_addr: SocketAddr, request_rules: Option<Vec<RequestRule>>) -> Self {
125        Self {
126            proxy_addr,
127            request_rules,
128            node_type: NodeType::Simulated,
129        }
130    }
131
132    pub fn builder() -> NodeBuilder {
133        NodeBuilder {
134            real_addr: None,
135            proxy_addr: None,
136            shard_awareness: None,
137            request_rules: None,
138            response_rules: None,
139        }
140    }
141}
142
143pub struct NodeBuilder {
144    real_addr: Option<SocketAddr>,
145    proxy_addr: Option<SocketAddr>,
146    shard_awareness: Option<ShardAwareness>,
147    request_rules: Option<Vec<RequestRule>>,
148    response_rules: Option<Vec<ResponseRule>>,
149}
150
151impl NodeBuilder {
152    pub fn real_address(mut self, real_addr: SocketAddr) -> Self {
153        self.real_addr = Some(real_addr);
154        self
155    }
156
157    pub fn proxy_address(mut self, proxy_addr: SocketAddr) -> Self {
158        self.proxy_addr = Some(proxy_addr);
159        self
160    }
161
162    pub fn shard_awareness(mut self, shard_awareness: ShardAwareness) -> Self {
163        self.shard_awareness = Some(shard_awareness);
164        self
165    }
166
167    pub fn request_rules(mut self, request_rules: Vec<RequestRule>) -> Self {
168        self.request_rules = Some(request_rules);
169        self
170    }
171
172    pub fn response_rules(mut self, response_rules: Vec<ResponseRule>) -> Self {
173        self.response_rules = Some(response_rules);
174        self
175    }
176
177    /// Creates an abstract node that is backed by a real Scylla node.
178    pub fn build(self) -> Node {
179        Node {
180            proxy_addr: self.proxy_addr.expect("Proxy addr is required!"),
181            request_rules: self.request_rules,
182            node_type: NodeType::Real {
183                real_addr: self.real_addr.expect("Real addr is required!"),
184                shard_awareness: self.shard_awareness.expect("Shard awareness is required!"),
185                response_rules: self.response_rules,
186            },
187        }
188    }
189
190    /// Creates a simulated node that is not backed by any real Scylla node.
191    pub fn build_dry_mode(self) -> Node {
192        Node {
193            proxy_addr: self.proxy_addr.expect("Proxy addr is required!"),
194            request_rules: self.request_rules,
195            node_type: NodeType::Simulated,
196        }
197    }
198}
199
200#[derive(Clone, Copy)]
201struct DisplayableRealAddrOption(Option<SocketAddr>);
202impl Display for DisplayableRealAddrOption {
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        if let Some(addr) = self.0 {
205            write!(f, "{addr}")
206        } else {
207            write!(f, "<dry mode>")
208        }
209    }
210}
211
212#[derive(Clone, Copy)]
213struct DisplayableShard(Option<TargetShard>);
214impl Display for DisplayableShard {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        if let Some(shard) = self.0 {
217            write!(f, "shard {shard}")
218        } else {
219            write!(f, "unknown shard")
220        }
221    }
222}
223
224enum InternalNode {
225    Real {
226        real_addr: SocketAddr,
227        proxy_addr: SocketAddr,
228        shard_awareness: ShardAwareness,
229        request_rules: Arc<Mutex<Vec<RequestRule>>>,
230        response_rules: Arc<Mutex<Vec<ResponseRule>>>,
231    },
232    Simulated {
233        proxy_addr: SocketAddr,
234        request_rules: Arc<Mutex<Vec<RequestRule>>>,
235    },
236}
237
238impl InternalNode {
239    fn proxy_addr(&self) -> SocketAddr {
240        match *self {
241            InternalNode::Real { proxy_addr, .. } => proxy_addr,
242            InternalNode::Simulated { proxy_addr, .. } => proxy_addr,
243        }
244    }
245    fn real_addr(&self) -> Option<SocketAddr> {
246        match *self {
247            InternalNode::Real { real_addr, .. } => Some(real_addr),
248            InternalNode::Simulated { .. } => None,
249        }
250    }
251    fn request_rules(&self) -> &Arc<Mutex<Vec<RequestRule>>> {
252        match self {
253            InternalNode::Real { request_rules, .. } => request_rules,
254            InternalNode::Simulated { request_rules, .. } => request_rules,
255        }
256    }
257}
258
259impl From<Node> for InternalNode {
260    fn from(node: Node) -> Self {
261        match node.node_type {
262            NodeType::Real {
263                real_addr,
264                shard_awareness,
265                response_rules,
266            } => InternalNode::Real {
267                real_addr,
268                proxy_addr: node.proxy_addr,
269                shard_awareness,
270                request_rules: node
271                    .request_rules
272                    .map(|rules| Arc::new(Mutex::new(rules)))
273                    .unwrap_or_default(),
274                response_rules: response_rules
275                    .map(|rules| Arc::new(Mutex::new(rules)))
276                    .unwrap_or_default(),
277            },
278            NodeType::Simulated => InternalNode::Simulated {
279                proxy_addr: node.proxy_addr,
280                request_rules: node
281                    .request_rules
282                    .map(|rules| Arc::new(Mutex::new(rules)))
283                    .unwrap_or_default(),
284            },
285        }
286    }
287}
288
289pub struct ProxyBuilder {
290    nodes: Vec<Node>,
291}
292
293impl ProxyBuilder {
294    pub fn with_node(mut self, node: Node) -> ProxyBuilder {
295        self.nodes.push(node);
296        self
297    }
298
299    pub fn build(self) -> Proxy {
300        Proxy::new(self.nodes)
301    }
302}
303
304pub struct Proxy {
305    nodes: Vec<InternalNode>,
306}
307
308impl Proxy {
309    pub fn new(nodes: impl IntoIterator<Item = Node>) -> Self {
310        Proxy {
311            nodes: nodes.into_iter().map(|node| node.into()).collect(),
312        }
313    }
314
315    pub fn builder() -> ProxyBuilder {
316        ProxyBuilder { nodes: vec![] }
317    }
318
319    /// Build a translation map based on provided proxy and node addresses.
320    /// The map can be passed to `Session` `address_translator()` to ensure
321    /// that the driver contacts the nodes through the proxy (and not directly).
322    pub fn translation_map(&self) -> HashMap<SocketAddr, SocketAddr> {
323        let mut translation_map = HashMap::new();
324        for node in self.nodes.iter() {
325            if let &InternalNode::Real {
326                real_addr,
327                proxy_addr,
328                ..
329            } = node
330            {
331                translation_map.insert(real_addr, proxy_addr);
332                let shard_aware_real_addr = SocketAddr::new(real_addr.ip(), 19042);
333                translation_map.insert(shard_aware_real_addr, proxy_addr);
334            }
335        }
336        translation_map
337    }
338
339    /// Runs the [Proxy], i.e. makes it ready for accepting drivers' connections.
340    /// Returns a [RunningProxy] handle that can be used to stop the proxy or change the rules.
341    pub async fn run(self) -> Result<RunningProxy, DoorkeeperError> {
342        let (terminate_signaler, _t) = tokio::sync::broadcast::channel(1);
343        let (finish_guard, finish_waiter) = mpsc::channel(1);
344
345        let (error_propagator, error_sink) = mpsc::unbounded_channel();
346        let (doorkeepers, running_nodes): (Vec<_>, Vec<RunningNode>) = self
347            .nodes
348            .into_iter()
349            .map(|node| {
350                let cc_event_sender = Arc::new(Mutex::new(HashMap::new()));
351                let running = {
352                    let (request_rules, response_rules) = match node {
353                        InternalNode::Real {
354                            ref request_rules,
355                            ref response_rules,
356                            ..
357                        } => (request_rules, Some(response_rules)),
358                        InternalNode::Simulated {
359                            ref request_rules, ..
360                        } => (request_rules, None),
361                    };
362                    RunningNode {
363                        request_rules: request_rules.clone(),
364                        response_rules: response_rules.cloned(),
365                        cc_event_sender: cc_event_sender.clone(),
366                    }
367                };
368                (
369                    Doorkeeper::spawn(
370                        node,
371                        terminate_signaler.clone(),
372                        finish_guard.clone(),
373                        error_propagator.clone(),
374                        cc_event_sender,
375                    ),
376                    running,
377                )
378            })
379            .unzip();
380
381        for doorkeeper in doorkeepers {
382            doorkeeper.await?; // await doorkeeper creation, including binding to a socket
383        }
384
385        Ok(RunningProxy {
386            terminate_signaler,
387            finish_waiter,
388            running_nodes,
389            error_sink,
390        })
391    }
392}
393
394/// A handle that can be used to change the rules regarding the particular node.
395pub struct RunningNode {
396    request_rules: Arc<Mutex<Vec<RequestRule>>>,
397    response_rules: Option<Arc<Mutex<Vec<ResponseRule>>>>,
398
399    /// Senders to the driver-facing sockets of all control connections (those
400    /// that sent REGISTER). Keyed by `connection_no` so that each connection
401    /// can be individually removed on close without affecting others.
402    ///
403    /// Populated by `request_processor` when it sees a REGISTER frame,
404    /// entries removed when the corresponding connection closes.
405    ///
406    /// Used by [`inject_event_to_cc`](Self::inject_event_to_cc) to push
407    /// unsolicited EVENT frames to every registered control connection.
408    cc_event_sender: Arc<Mutex<HashMap<usize, mpsc::UnboundedSender<ResponseFrame>>>>,
409}
410
411impl RunningNode {
412    /// Replaces the previous request rules with the new ones.
413    pub fn change_request_rules(&mut self, rules: Option<Vec<RequestRule>>) {
414        *self.request_rules.lock().unwrap() = rules.unwrap_or_default();
415    }
416
417    /// Adds new request rules to the end of the list (so with lowest priority)
418    pub fn append_request_rules(&mut self, mut rules: Vec<RequestRule>) {
419        self.request_rules.lock().unwrap().append(&mut rules);
420    }
421
422    /// Adds new request rules to the beginning of the list (so with highest priority)
423    pub fn prepend_request_rules(&mut self, rules: Vec<RequestRule>) {
424        let mut new_rules = rules;
425        let mut old_rules_guard = self.request_rules.lock().unwrap();
426        new_rules.append(&mut *old_rules_guard);
427        *old_rules_guard = new_rules;
428    }
429
430    /// Replaces the previous response rules with the new ones.
431    pub fn change_response_rules(&mut self, rules: Option<Vec<ResponseRule>>) {
432        *self
433            .response_rules
434            .as_ref()
435            .expect("No response rules on a simulated node!")
436            .lock()
437            .unwrap() = rules.unwrap_or_default();
438    }
439
440    /// Adds new response rules to the end of the list (so with lowest priority)
441    pub fn append_response_rules(&mut self, mut rules: Vec<ResponseRule>) {
442        self.response_rules
443            .as_ref()
444            .expect("No response rules on a simulated node!")
445            .lock()
446            .unwrap()
447            .append(&mut rules);
448    }
449
450    /// Adds new response rules to the beginning of the list (so with highest priority)
451    pub fn prepend_response_rules(&mut self, rules: Vec<ResponseRule>) {
452        let mut old_rules_guard = self
453            .response_rules
454            .as_ref()
455            .expect("No response rules on a simulated node!")
456            .lock()
457            .unwrap();
458        let mut new_rules = rules;
459        new_rules.append(&mut *old_rules_guard);
460        *old_rules_guard = new_rules;
461    }
462
463    /// Injects a CQL EVENT frame into all registered control connections.
464    ///
465    /// Builds an EVENT frame (stream = −1, flags = 0, opcode = Event) with the
466    /// supplied `body` and sends it to every driver that has sent REGISTER on
467    /// this node. Dead senders (closed connections) are pruned automatically.
468    ///
469    /// Returns `true` if the frame was successfully enqueued to at least one
470    /// control connection, `false` if no control connections are currently
471    /// registered or all sends failed.
472    pub fn inject_event_to_cc(&self, body: Bytes) -> bool {
473        let mut guard = self.cc_event_sender.lock().unwrap();
474        if guard.is_empty() {
475            return false;
476        }
477        let mut any_sent = false;
478        guard.retain(|_conn_no, tx| {
479            let frame = ResponseFrame {
480                params: FrameParams {
481                    version: 4,
482                    flags: 0,
483                    stream: -1,
484                }
485                .for_response(),
486                opcode: ResponseOpcode::Event,
487                body: body.clone(),
488            };
489            let ok = tx.send(frame).is_ok();
490            any_sent |= ok;
491            // Remove dead senders (connection already closed on the
492            // receiving end).
493            ok
494        });
495        any_sent
496    }
497}
498
499/// A handle that can be used to stop the proxy or change the rules.
500pub struct RunningProxy {
501    terminate_signaler: TerminateSignaler,
502    finish_waiter: FinishWaiter,
503    pub running_nodes: Vec<RunningNode>,
504    error_sink: ErrorSink,
505}
506
507impl RunningProxy {
508    /// Disables all the rules in the proxy, effectively making it a pass-through-only proxy.
509    pub fn turn_off_rules(&mut self) {
510        for (request_rules, response_rules) in self
511            .running_nodes
512            .iter_mut()
513            .map(|node| (&node.request_rules, &node.response_rules))
514        {
515            request_rules.lock().unwrap().clear();
516            if let Some(response_rules) = response_rules {
517                response_rules.lock().unwrap().clear();
518            }
519        }
520    }
521
522    /// Attempts to fetch the first error that has occurred in proxy since last check.
523    /// If no errors occurred, returns Ok(()).
524    pub fn sanity_check(&mut self) -> Result<(), ProxyError> {
525        match self.error_sink.try_recv() {
526            Ok(err) => Err(err),
527            Err(TryRecvError::Empty) => Ok(()),
528            Err(TryRecvError::Disconnected) => {
529                // As we haven't awaited finish of all workers yet, there must be a faulty case without proper error handling.
530                Err(ProxyError::SanityCheckFailure)
531            }
532        }
533    }
534
535    /// Waits until an error occurs in proxy. If proxy finishes with no errors occurred, returns Err(()).
536    pub async fn wait_for_error(&mut self) -> Option<ProxyError> {
537        self.error_sink.recv().await
538    }
539
540    /// Requests termination of all proxy workers and awaits its completion.
541    /// Returns the first error that occurred in proxy.
542    pub async fn finish(mut self) -> Result<(), ProxyError> {
543        self.terminate_signaler.send(()).map_err(|err| {
544            ProxyError::AwaitFinishFailure(format!(
545                "Send error in terminate_signaler: {err} (bug!)"
546            ))
547        })?;
548        info!("Sent finish signal to proxy workers.");
549
550        // This to make sure that also workers not-yet-spawned when terminate signal was sent will terminate.
551        std::mem::drop(self.terminate_signaler);
552
553        if self.finish_waiter.recv().await.is_some() {
554            unreachable!();
555        };
556        info!("All workers have finished.");
557
558        match self.error_sink.try_recv() {
559            Ok(err) => Err(err),
560            Err(TryRecvError::Disconnected) => Ok(()),
561            Err(TryRecvError::Empty) => {
562                // As we have already awaited finish of all workers, there must be a logic bug.
563                unreachable!("Worker await logic bug!");
564            }
565        }
566    }
567}
568
569/// A worker corresponding to a particular node. It listens in a loop for driver's connections
570/// on specified proxy bind address, respects ports regarding advanced shard-awareness (if set),
571/// to this end obtaining number of shards from the node (if set), then establishes connection
572/// to the node, spawns workers for this connection and continues to listen.
573struct Doorkeeper {
574    node: InternalNode,
575    listener: TcpListener,
576    terminate_signaler: TerminateSignaler,
577    finish_guard: FinishGuard,
578    shards_count: Option<u16>,
579    error_propagator: ErrorPropagator,
580    cc_event_sender: Arc<Mutex<HashMap<usize, mpsc::UnboundedSender<ResponseFrame>>>>,
581}
582
583impl Doorkeeper {
584    async fn spawn(
585        node: InternalNode,
586        terminate_signaler: TerminateSignaler,
587        finish_guard: FinishGuard,
588        error_propagator: ErrorPropagator,
589        cc_event_sender: Arc<Mutex<HashMap<usize, mpsc::UnboundedSender<ResponseFrame>>>>,
590    ) -> Result<(), DoorkeeperError> {
591        let listener = TcpListener::bind(node.proxy_addr())
592            .await
593            .map_err(|err| DoorkeeperError::DriverConnectionAttempt(node.proxy_addr(), err))?;
594
595        if let InternalNode::Real {
596            shard_awareness,
597            real_addr,
598            ..
599        } = node
600        {
601            info!(
602                "Spawned a {} doorkeeper for pair real:{} - proxy:{}.",
603                if shard_awareness.is_aware() {
604                    "shard-aware"
605                } else {
606                    "shard-unaware"
607                },
608                real_addr,
609                node.proxy_addr(),
610            );
611        } else {
612            info!(
613                "Spawned a dry-mode doorkeeper for proxy:{}.",
614                node.proxy_addr(),
615            )
616        };
617
618        let doorkeeper = Doorkeeper {
619            shards_count: None, // temporarily, until Doorkeeper examines its ShardAwareness
620            node,
621            listener,
622            terminate_signaler,
623            finish_guard,
624            error_propagator,
625            cc_event_sender,
626        };
627        tokio::task::spawn(doorkeeper.run());
628        Ok(())
629    }
630
631    async fn run(mut self) {
632        self.update_shards_count().await;
633        let mut own_terminate_notifier = self.terminate_signaler.subscribe();
634        let (connection_close_tx, _connection_close_rx) = broadcast::channel::<()>(2);
635        let mut connection_no: usize = 0;
636        loop {
637            tokio::select! {
638                res = self.accept_connection(&connection_close_tx, connection_no) => {
639                    match res {
640                        Ok(()) => connection_no += 1,
641                        Err(err) => {
642                            error!(
643                                "Error in doorkeeper with addr {} for node {}: {}",
644                                self.node.proxy_addr(),
645                                DisplayableRealAddrOption(self.node.real_addr()),
646                                err
647                            );
648                            let _ = self.error_propagator.send(err.into());
649                            break;
650                        },
651                    }
652                },
653                _terminate = own_terminate_notifier.recv() => break
654            }
655        }
656        debug!(
657            "Doorkeeper exits: proxy {}, node {}.",
658            self.node.proxy_addr(),
659            DisplayableRealAddrOption(self.node.real_addr())
660        );
661    }
662
663    async fn update_shards_count(&mut self) {
664        if let InternalNode::Real {
665            real_addr,
666            shard_awareness,
667            ..
668        } = self.node
669        {
670            self.shards_count = match shard_awareness {
671                ShardAwareness::Unaware => None,
672                ShardAwareness::FixedNum(shards_num) => Some(shards_num),
673                ShardAwareness::QueryNode => match self.obtain_shards_count(real_addr).await {
674                    Ok(shards) => Some(shards),
675                    // If a node offers no sharding info, change proxy ShardAwareness to Unaware.
676                    Err(DoorkeeperError::ObtainingShardNumberNoShardInfo) => {
677                        info!(
678                            "Doorkeeper with addr {} found no shard info in node {}; falling back to ShardAwareness::Unaware",
679                            self.node.proxy_addr(),
680                            DisplayableRealAddrOption(self.node.real_addr()),
681                        );
682                        None
683                    }
684                    Err(e) => {
685                        error!(
686                            "Error in doorkeeper with addr {} while querying shard info from node {}: {}",
687                            self.node.proxy_addr(),
688                            DisplayableRealAddrOption(self.node.real_addr()),
689                            e
690                        );
691                        None
692                    }
693                },
694            }
695        }
696    }
697
698    async fn spawn_workers(
699        &mut self,
700        driver_addr: SocketAddr,
701        connection_close_tx: &ConnectionCloseSignaler,
702        connection_no: usize,
703        driver_stream: TcpStream,
704        cluster_stream: Option<TcpStream>,
705        shard: Option<TargetShard>,
706    ) {
707        let (driver_read, driver_write) = driver_stream.into_split();
708
709        let new_worker = || ProxyWorker {
710            terminate_notifier: self.terminate_signaler.subscribe(),
711            finish_guard: self.finish_guard.clone(),
712            connection_close_notifier: connection_close_tx.subscribe(),
713            error_propagator: self.error_propagator.clone(),
714            driver_addr,
715            real_addr: self.node.real_addr(),
716            proxy_addr: self.node.proxy_addr(),
717            shard,
718        };
719
720        let (tx_request, rx_request) = mpsc::unbounded_channel::<RequestFrame>();
721        let (tx_response, rx_response) = mpsc::unbounded_channel::<ResponseFrame>();
722        let (tx_cluster, rx_cluster) = mpsc::unbounded_channel::<RequestFrame>();
723        let (tx_driver, rx_driver) = mpsc::unbounded_channel::<ResponseFrame>();
724        let event_register_flag = Arc::new(AtomicBool::new(false));
725
726        let (
727            compression_writer_request_processor,
728            compression_reader_receiver_from_driver,
729            compression_reader_receiver_from_cluster,
730            compression_reader_sender_to_driver,
731            compression_reader_sender_to_cluster,
732        ) = compression::make_compression_infra();
733
734        {
735            let worker = new_worker();
736            tokio::task::spawn(async move {
737                worker
738                    .receiver_from_driver(
739                        driver_read,
740                        tx_request,
741                        compression_reader_receiver_from_driver,
742                    )
743                    .await;
744            });
745        }
746        {
747            let worker = new_worker();
748            let conn_close_sub = connection_close_tx.subscribe();
749            let term_sub = self.terminate_signaler.subscribe();
750            tokio::task::spawn(async move {
751                worker
752                    .sender_to_driver(
753                        driver_write,
754                        rx_driver,
755                        conn_close_sub,
756                        term_sub,
757                        compression_reader_sender_to_driver,
758                    )
759                    .await;
760            });
761        }
762        {
763            let worker = new_worker();
764            let request_rules = Arc::clone(self.node.request_rules());
765            let conn_close = connection_close_tx.clone();
766            let event_flag = Arc::clone(&event_register_flag);
767            let tx_driver_clone = tx_driver.clone();
768            let tx_cluster_clone = tx_cluster.clone();
769            let cc_sender = Arc::clone(&self.cc_event_sender);
770            tokio::task::spawn(async move {
771                worker
772                    .request_processor(
773                        rx_request,
774                        tx_driver_clone,
775                        tx_cluster_clone,
776                        connection_no,
777                        request_rules,
778                        conn_close,
779                        event_flag,
780                        compression_writer_request_processor,
781                        cc_sender,
782                    )
783                    .await;
784            });
785        }
786        if let InternalNode::Real {
787            ref response_rules, ..
788        } = self.node
789        {
790            let (cluster_read, cluster_write) = cluster_stream.unwrap().into_split();
791            {
792                let worker = new_worker();
793                let conn_close_sub = connection_close_tx.subscribe();
794                let term_sub = self.terminate_signaler.subscribe();
795                tokio::task::spawn(async move {
796                    worker
797                        .sender_to_cluster(
798                            cluster_write,
799                            rx_cluster,
800                            conn_close_sub,
801                            term_sub,
802                            compression_reader_sender_to_cluster,
803                        )
804                        .await;
805                });
806            }
807            {
808                let worker = new_worker();
809                tokio::task::spawn(async move {
810                    worker
811                        .receiver_from_cluster(
812                            cluster_read,
813                            tx_response,
814                            compression_reader_receiver_from_cluster,
815                        )
816                        .await;
817                });
818            }
819            {
820                let worker = new_worker();
821                let response_rules = Arc::clone(response_rules);
822                let conn_close = connection_close_tx.clone();
823                let event_flag = Arc::clone(&event_register_flag);
824                tokio::task::spawn(async move {
825                    worker
826                        .response_processor(
827                            rx_response,
828                            tx_driver,
829                            tx_cluster,
830                            connection_no,
831                            response_rules,
832                            conn_close,
833                            event_flag,
834                        )
835                        .await;
836                });
837            }
838        }
839        debug!(
840            "Doorkeeper with addr {} of node {} spawned workers.",
841            self.node.proxy_addr(),
842            DisplayableRealAddrOption(self.node.real_addr())
843        );
844    }
845
846    async fn accept_connection(
847        &mut self,
848        connection_close_tx: &ConnectionCloseSignaler,
849        connection_no: usize,
850    ) -> Result<(), DoorkeeperError> {
851        let (driver_stream, driver_addr) = self.make_driver_stream(connection_no).await?;
852        let (cluster_stream, shard) = match self.node {
853            InternalNode::Real { real_addr, .. } => {
854                let (cluster_stream, shard) =
855                    self.make_cluster_stream(driver_addr, real_addr).await?;
856                (Some(cluster_stream), shard)
857            }
858            InternalNode::Simulated { .. } => (None, None),
859        };
860
861        self.spawn_workers(
862            driver_addr,
863            connection_close_tx,
864            connection_no,
865            driver_stream,
866            cluster_stream,
867            shard,
868        )
869        .await;
870
871        Ok(())
872    }
873
874    async fn make_driver_stream(
875        &mut self,
876        connection_no: usize,
877    ) -> Result<(TcpStream, SocketAddr), DoorkeeperError> {
878        let (driver_stream, driver_addr) =
879            self.listener.accept().await.map_err(|err| {
880                DoorkeeperError::DriverConnectionAttempt(self.node.proxy_addr(), err)
881            })?;
882        info!(
883            "Connected driver from {} to {}, connection no={}.",
884            driver_addr,
885            self.node.proxy_addr(),
886            connection_no
887        );
888        Ok((driver_stream, driver_addr))
889    }
890
891    async fn make_cluster_stream(
892        &mut self,
893        driver_addr: SocketAddr,
894        real_addr: SocketAddr,
895    ) -> Result<(TcpStream, Option<TargetShard>), DoorkeeperError> {
896        let mut cluster_stream = if let Some(shards) = self.shards_count {
897            let socket = match self.node.proxy_addr().ip() {
898                std::net::IpAddr::V4(_) => TcpSocket::new_v4(),
899                std::net::IpAddr::V6(_) => TcpSocket::new_v6(),
900            }
901            .map_err(DoorkeeperError::SocketCreate)?;
902
903            let shard_preserving_addr = {
904                let mut desired_addr =
905                    SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), driver_addr.port());
906                while socket.bind(desired_addr).is_err() {
907                    // in search for a port that translates to the desired shard
908                    let next_port = self.next_port_to_same_shard(desired_addr.port());
909                    if next_port == driver_addr.port() {
910                        return Err(DoorkeeperError::NoMorePorts);
911                    }
912                    desired_addr.set_port(next_port);
913                }
914                desired_addr
915            };
916
917            let stream = socket.connect(real_addr).await;
918            if let Ok(ok) = &stream {
919                info!(
920                    "Connected to the cluster from {} at {}, intended shard {}.",
921                    ok.local_addr().unwrap(),
922                    real_addr,
923                    shard_preserving_addr.port() % shards
924                );
925            }
926            stream
927        } else {
928            let stream = TcpStream::connect(real_addr).await;
929            if stream.is_ok() {
930                info!("Connected to the cluster at {}.", real_addr);
931            }
932            stream
933        }
934        .map_err(|err| DoorkeeperError::NodeConnectionAttempt(real_addr, err))?;
935
936        // If ShardAwareness is aware (QueryNode or FixedNum variants) and the
937        // proxy succeeded to know the shards count (in FixedNum we get it for
938        // free, in QueryNode the initial Options query succeeded and Supported
939        // contained SCYLLA_SHARDS_NUM), then upon opening each connection to the
940        // node, the proxy issues another Options requests and acknowledges the
941        // shard it got connected to.
942        let shard = if self.shards_count.is_some() {
943            self.obtain_shard_number(real_addr, &mut cluster_stream)
944                .await?
945        } else {
946            None
947        };
948
949        Ok((cluster_stream, shard))
950    }
951
952    fn next_port_to_same_shard(&self, port: u16) -> u16 {
953        port.wrapping_add(self.shards_count.unwrap())
954    }
955
956    async fn get_supported_options(
957        connection: &mut TcpStream,
958    ) -> Result<HashMap<String, Vec<String>>, DoorkeeperError> {
959        write_frame(
960            HARDCODED_OPTIONS_PARAMS,
961            FrameOpcode::Request(RequestOpcode::Options),
962            &Bytes::new(),
963            connection,
964            &no_compression(),
965        )
966        .await
967        .map_err(DoorkeeperError::ObtainingShardNumber)?;
968
969        let supported_frame = read_response_frame(connection, &compression::no_compression())
970            .await
971            .map_err(DoorkeeperError::ObtainingShardNumberFrame)?;
972
973        let options = read_string_multimap(&mut supported_frame.body.as_ref())
974            .map_err(DoorkeeperError::ObtainingShardNumberParseOptions)?;
975
976        Ok(options)
977    }
978
979    async fn obtain_shards_count(&self, real_addr: SocketAddr) -> Result<u16, DoorkeeperError> {
980        let mut connection = TcpStream::connect(real_addr)
981            .await
982            .map_err(|err| DoorkeeperError::NodeConnectionAttempt(real_addr, err))?;
983        let options = Self::get_supported_options(&mut connection).await?;
984        let nr_shards_entry = options.get("SCYLLA_NR_SHARDS");
985        let shards = match nr_shards_entry
986            .and_then(|vec| vec.first())
987            .ok_or(DoorkeeperError::ObtainingShardNumberNoShardInfo)?
988            .parse::<u16>()
989            .map_err(DoorkeeperError::ObtainingShardNumberParseShardNumber)?
990        {
991            0u16 => Err(DoorkeeperError::ObtainingShardNumberGotZero),
992            num => Ok(num),
993        }?;
994        info!("Obtained shards number on node {}: {}", real_addr, shards);
995        Ok(shards)
996    }
997
998    async fn obtain_shard_number(
999        &self,
1000        real_addr: SocketAddr,
1001        connection: &mut TcpStream,
1002    ) -> Result<Option<TargetShard>, DoorkeeperError> {
1003        let options = Self::get_supported_options(connection).await?;
1004        let shard_entry = options.get("SCYLLA_SHARD");
1005        let shard = shard_entry
1006            .and_then(|vec| vec.first())
1007            .map(|s| {
1008                s.parse::<u16>()
1009                    .map_err(DoorkeeperError::ObtainingShardNumberParseShardNumber)
1010            })
1011            .transpose()?;
1012        info!("Connected to node {}, shard {:?}", real_addr, shard);
1013        Ok(shard)
1014    }
1015}
1016
1017mod compression {
1018    use std::error::Error;
1019    use std::sync::{Arc, OnceLock};
1020
1021    use bytes::Bytes;
1022    use scylla_cql::frame::frame_errors::{
1023        CqlRequestSerializationError, FrameBodyExtensionsParseError,
1024    };
1025    use scylla_cql::frame::request::{
1026        DeserializableRequest as _, RequestDeserializationError, Startup, options,
1027    };
1028    use scylla_cql::frame::{Compression, compress_append, decompress, flag};
1029    use tracing::{error, warn};
1030
1031    #[derive(Debug, thiserror::Error)]
1032    pub(crate) enum CompressionError {
1033        /// Body Snap compression failed.
1034        #[error("Snap compression error: {0}")]
1035        SnapCompressError(Arc<dyn Error + Sync + Send>),
1036
1037        /// Frame is to be compressed, but no compression was negotiated for the connection.
1038        #[error("Frame is to be compressed, but no compression negotiated for connection.")]
1039        NoCompressionNegotiated,
1040    }
1041
1042    type CompressionInfo = Arc<OnceLock<Option<Compression>>>;
1043
1044    /// The write end of compression config for a connection.
1045    ///
1046    /// Used by the request processor upon STARTUP frame captured
1047    /// and compression setting retrieved from it.
1048    #[derive(Debug, Clone)]
1049    pub(crate) struct CompressionWriter(CompressionInfo);
1050    impl CompressionWriter {
1051        pub(crate) fn set(
1052            &self,
1053            compression: Option<Compression>,
1054        ) -> Result<(), Option<Compression>> {
1055            self.0.set(compression)
1056        }
1057
1058        pub(crate) fn set_from_startup(
1059            &self,
1060            mut body: &[u8],
1061        ) -> Result<Option<Compression>, RequestDeserializationError> {
1062            let startup = Startup::deserialize_with_features(&mut body, &Default::default())?;
1063            let maybe_compression = startup.options.get(options::COMPRESSION);
1064            let maybe_compression = maybe_compression.and_then(|compression| {
1065                compression
1066                    .parse::<Compression>()
1067                    .inspect_err(|err| error!("STARTUP compression error: {}", err))
1068                    .ok()
1069            });
1070            let _ = self.set(maybe_compression).inspect_err(|_| {
1071                warn!("Captured second or further STARTUP frame on the same connection")
1072            });
1073
1074            Ok(maybe_compression)
1075        }
1076    }
1077
1078    /// The read end of compression config for a connection.
1079    ///
1080    /// Used by frame (de)serializers.
1081    #[derive(Debug, Clone)]
1082    pub(crate) struct CompressionReader(CompressionInfo);
1083    impl CompressionReader {
1084        /// Return the compression negotiated for the connection.
1085        ///
1086        /// Outer Option signifies whether the negotiation took place,
1087        /// inner Option is the compression (or lack of it) negotiated.
1088        pub(crate) fn get(&self) -> Option<Option<Compression>> {
1089            self.0.get().copied()
1090        }
1091
1092        pub(crate) fn maybe_compress_body(
1093            &self,
1094            flags: u8,
1095            body: &[u8],
1096        ) -> Result<Option<Bytes>, CompressionError> {
1097            match (flags & flag::COMPRESSION != 0, self.get().flatten()) {
1098                (true, Some(compression)) => {
1099                    let mut buf = Vec::new();
1100                    compress_append(body, compression, &mut buf).map_err(|err| {
1101                        let CqlRequestSerializationError::SnapCompressError(err) = err else {
1102                            unreachable!("BUG: compress_append returned variant different than SnapCompressError")
1103                        };
1104                        CompressionError::SnapCompressError(err)
1105                    })?;
1106                    Ok(Some(Bytes::from(buf)))
1107                }
1108                (true, None) => Err(CompressionError::NoCompressionNegotiated),
1109                (false, _) => Ok(None),
1110            }
1111        }
1112
1113        pub(crate) fn maybe_decompress_body(
1114            &self,
1115            flags: u8,
1116            body: Bytes,
1117        ) -> Result<Bytes, FrameBodyExtensionsParseError> {
1118            match (flags & flag::COMPRESSION != 0, self.get().flatten()) {
1119                (true, Some(compression)) => decompress(&body, compression).map(Into::into),
1120                (true, None) => Err(FrameBodyExtensionsParseError::NoCompressionNegotiated),
1121                (false, _) => Ok(body),
1122            }
1123        }
1124    }
1125
1126    pub(crate) fn make_compression_infra() -> (
1127        CompressionWriter,
1128        CompressionReader,
1129        CompressionReader,
1130        CompressionReader,
1131        CompressionReader,
1132    ) {
1133        let info = Arc::new(OnceLock::new());
1134        (
1135            CompressionWriter(info.clone()),
1136            CompressionReader(info.clone()),
1137            CompressionReader(info.clone()),
1138            CompressionReader(info.clone()),
1139            CompressionReader(info),
1140        )
1141    }
1142
1143    fn mock_compression_reader(compression: Option<Compression>) -> CompressionReader {
1144        CompressionReader(Arc::new({
1145            let once = OnceLock::new();
1146            once.set(compression).unwrap();
1147            once
1148        }))
1149    }
1150
1151    // Compression explicitly turned off.
1152    pub(crate) fn no_compression() -> CompressionReader {
1153        mock_compression_reader(None)
1154    }
1155
1156    // Compression explicitly turned on.
1157    #[cfg(test)] // Currently only used for tests.
1158    pub(crate) fn with_compression(compression: Compression) -> CompressionReader {
1159        mock_compression_reader(Some(compression))
1160    }
1161}
1162pub(crate) use compression::{CompressionReader, CompressionWriter};
1163
1164struct ProxyWorker {
1165    terminate_notifier: TerminateNotifier,
1166    finish_guard: FinishGuard,
1167    connection_close_notifier: ConnectionCloseNotifier,
1168    error_propagator: ErrorPropagator,
1169    driver_addr: SocketAddr,
1170    real_addr: Option<SocketAddr>,
1171    proxy_addr: SocketAddr,
1172    shard: Option<TargetShard>,
1173}
1174
1175impl ProxyWorker {
1176    fn exit(self, duty: &'static str) {
1177        debug!(
1178            "Worker exits: [driver: {}, proxy: {}, node: {}, {}]::{}.",
1179            self.driver_addr,
1180            self.proxy_addr,
1181            DisplayableRealAddrOption(self.real_addr),
1182            DisplayableShard(self.shard),
1183            duty
1184        );
1185        std::mem::drop(self.finish_guard);
1186    }
1187
1188    async fn run_until_interrupted<F, Fut>(mut self, worker_name: &'static str, f: F)
1189    where
1190        F: FnOnce(SocketAddr, SocketAddr, Option<SocketAddr>) -> Fut,
1191        Fut: Future<Output = Result<(), ProxyError>>,
1192    {
1193        let fut = f(self.driver_addr, self.proxy_addr, self.real_addr);
1194
1195        tokio::select! {
1196            result = fut => {
1197                if let Err(err) = result {
1198                    // error_propagator could be a field
1199                    let _ = self.error_propagator.send(err);
1200                }
1201            }
1202            _ = self.terminate_notifier.recv() => (),
1203            _ = self.connection_close_notifier.recv() => (),
1204        }
1205        self.exit(worker_name);
1206    }
1207
1208    async fn receiver_from_driver(
1209        self,
1210        mut read_half: impl AsyncRead + Unpin,
1211        request_processor_tx: mpsc::UnboundedSender<RequestFrame>,
1212        compression: CompressionReader,
1213    ) {
1214        let shard = self.shard;
1215        self.run_until_interrupted(
1216            "receiver_from_driver",
1217            |driver_addr, proxy_addr, _real_addr| async move {
1218                loop {
1219                    let frame = frame::read_request_frame(&mut read_half, &compression)
1220                        .await
1221                        .map_err(|err| {
1222                            warn!("Request reception from {} error: {}", driver_addr, err);
1223                            WorkerError::DriverDisconnected(driver_addr)
1224                        })?;
1225
1226                    debug!(
1227                        "Intercepted Driver ({}) -> Cluster ({}) ({}) frame. opcode: {:?}.",
1228                        driver_addr,
1229                        proxy_addr,
1230                        DisplayableShard(shard),
1231                        &frame.opcode
1232                    );
1233                    if request_processor_tx.send(frame).is_err() {
1234                        warn!("request_processor had exited.");
1235                        return Result::<(), ProxyError>::Ok(());
1236                    }
1237                }
1238            },
1239        )
1240        .await
1241    }
1242
1243    async fn receiver_from_cluster(
1244        self,
1245        mut read_half: impl AsyncRead + Unpin,
1246        response_processor_tx: mpsc::UnboundedSender<ResponseFrame>,
1247        compression: CompressionReader,
1248    ) {
1249        let shard = self.shard;
1250        self.run_until_interrupted(
1251            "receiver_from_cluster",
1252            |driver_addr, _proxy_addr, real_addr| async move {
1253                let real_addr = real_addr.expect("BUG: no real_addr in cluster worker");
1254                loop {
1255                    let frame = frame::read_response_frame(&mut read_half, &compression)
1256                        .await
1257                        .map_err(|err| {
1258                            warn!("Response reception from {} error: {}", real_addr, err);
1259                            WorkerError::NodeDisconnected(real_addr)
1260                        })?;
1261
1262                    debug!(
1263                        "Intercepted Cluster ({}) ({}) -> Driver ({}) frame. opcode: {:?}.",
1264                        real_addr,
1265                        DisplayableShard(shard),
1266                        driver_addr,
1267                        &frame.opcode
1268                    );
1269
1270                    if response_processor_tx.send(frame).is_err() {
1271                        warn!("response_processor had exited.");
1272                        return Ok::<(), ProxyError>(());
1273                    }
1274                }
1275            },
1276        )
1277        .await;
1278    }
1279
1280    async fn sender_to_driver(
1281        self,
1282        mut write_half: impl AsyncWrite + Unpin,
1283        mut responses_rx: mpsc::UnboundedReceiver<ResponseFrame>,
1284        mut connection_close_notifier: ConnectionCloseNotifier,
1285        mut terminate_notifier: TerminateNotifier,
1286        compression: CompressionReader,
1287    ) {
1288        let shard = self.shard;
1289        self.run_until_interrupted(
1290            "sender_to_driver",
1291            |driver_addr, proxy_addr, _real_addr| async move {
1292                loop {
1293                    let response = match responses_rx.recv().await {
1294                        Some(response) => response,
1295                        None => {
1296                            if terminate_notifier.try_recv().is_err()
1297                                && connection_close_notifier.try_recv().is_err()
1298                            {
1299                                warn!("Response processor had exited");
1300                            }
1301                            return Ok(());
1302                        }
1303                    };
1304
1305                    debug!(
1306                        "Sending Proxy ({}) ({}) -> Driver ({}) frame. opcode: {:?}.",
1307                        proxy_addr,
1308                        DisplayableShard(shard),
1309                        driver_addr,
1310                        &response.opcode
1311                    );
1312                    if response.write(&mut write_half, &compression).await.is_err() {
1313                        if terminate_notifier.try_recv().is_err()
1314                            && connection_close_notifier.try_recv().is_err()
1315                        {
1316                            warn!("Driver dropped connection");
1317                            return Err(WorkerError::DriverDisconnected(driver_addr).into());
1318                        }
1319                        return Ok(());
1320                    }
1321                }
1322            },
1323        )
1324        .await;
1325    }
1326
1327    async fn sender_to_cluster(
1328        self,
1329        mut write_half: impl AsyncWrite + Unpin,
1330        mut requests_rx: mpsc::UnboundedReceiver<RequestFrame>,
1331        mut connection_close_notifier: ConnectionCloseNotifier,
1332        mut terminate_notifier: TerminateNotifier,
1333        compression: CompressionReader,
1334    ) {
1335        let shard = self.shard;
1336        self.run_until_interrupted(
1337            "sender_to_driver",
1338            |_driver_addr, proxy_addr, real_addr| async move {
1339                let real_addr = real_addr.expect("BUG: no real_addr in cluster worker");
1340                loop {
1341                    let request = match requests_rx.recv().await {
1342                        Some(request) => request,
1343                        None => {
1344                            if terminate_notifier.try_recv().is_err()
1345                                && connection_close_notifier.try_recv().is_err()
1346                            {
1347                                warn!("Request processor had exited");
1348                            }
1349                            return Ok(());
1350                        }
1351                    };
1352
1353                    debug!(
1354                        "Sending Proxy ({}) -> Cluster ({}) ({}) frame. opcode: {:?}.",
1355                        proxy_addr,
1356                        real_addr,
1357                        DisplayableShard(shard),
1358                        &request.opcode
1359                    );
1360
1361                    if request.write(&mut write_half, &compression).await.is_err() {
1362                        if terminate_notifier.try_recv().is_err()
1363                            && connection_close_notifier.try_recv().is_err()
1364                        {
1365                            warn!("Node {} dropped connection", real_addr);
1366                            return Err(WorkerError::NodeDisconnected(real_addr).into());
1367                        }
1368                        return Ok(());
1369                    }
1370                }
1371            },
1372        )
1373        .await;
1374    }
1375
1376    #[expect(clippy::too_many_arguments)]
1377    async fn request_processor(
1378        self,
1379        mut requests_rx: mpsc::UnboundedReceiver<RequestFrame>,
1380        driver_tx: mpsc::UnboundedSender<ResponseFrame>,
1381        cluster_tx: mpsc::UnboundedSender<RequestFrame>,
1382        connection_no: usize,
1383        request_rules: Arc<Mutex<Vec<RequestRule>>>,
1384        connection_close_signaler: ConnectionCloseSignaler,
1385        event_registered_flag: Arc<AtomicBool>,
1386        compression: CompressionWriter,
1387        cc_event_sender: Arc<Mutex<HashMap<usize, mpsc::UnboundedSender<ResponseFrame>>>>,
1388    ) {
1389        let shard = self.shard;
1390        self.run_until_interrupted("request_processor", |driver_addr, _, real_addr| async move {
1391            'mainloop: loop {
1392                match requests_rx.recv().await {
1393                    Some(request) => {
1394                        if request.opcode == RequestOpcode::Register {
1395                            event_registered_flag.store(true, Ordering::Relaxed);
1396                            // Expose this connection's driver-facing sender so
1397                            // that RunningNode::inject_event_to_cc() can push
1398                            // unsolicited EVENT frames to this control connection.
1399                            cc_event_sender.lock().unwrap().insert(connection_no, driver_tx.clone());
1400                            info!(
1401                                "REGISTER seen on connection {} ({} →  {} ({})); registered cc_event_sender",
1402                                connection_no,
1403                                driver_addr,
1404                                DisplayableRealAddrOption(real_addr),
1405                                DisplayableShard(shard),
1406                            );
1407                        } else if request.opcode == RequestOpcode::Startup {
1408                            match compression.set_from_startup(&request.body) {
1409                                Err(err) => error!("Failed to deserialize STARTUP frame: {}", err),
1410                                Ok(read_compression) => info!(
1411                                    "Intercepted STARTUP frame ({} -> {} ({})), so set compression accordingly to {:?}.",
1412                                    driver_addr,
1413                                    DisplayableRealAddrOption(real_addr),
1414                                    DisplayableShard(shard),
1415                                    read_compression
1416                                )
1417                            };
1418                        }
1419
1420                        let ctx = EvaluationContext {
1421                            connection_seq_no: connection_no,
1422                            opcode: FrameOpcode::Request(request.opcode),
1423                            frame_body: request.body.clone(),
1424                            connection_has_events: event_registered_flag.load(Ordering::Relaxed),
1425                        };
1426                        let mut guard = request_rules.lock().unwrap();
1427                        '_ruleloop: for (i, request_rule) in guard.iter_mut().enumerate() {
1428                            if request_rule.0.eval(&ctx) {
1429                                debug!("Applying rule no={} to request ({} -> {} ({})).", i, driver_addr, DisplayableRealAddrOption(real_addr), DisplayableShard(shard));
1430                                debug!("-> Applied rule: {:?}", request_rule);
1431                                debug!("-> To request: {:?}", ctx.opcode);
1432                                trace!("{:?}", request);
1433
1434                                if let Some(ref tx) = request_rule.1.feedback_channel {
1435                                    tx.send((request.clone(), shard)).unwrap_or_else(|err|
1436                                        warn!("Could not send received request as feedback: {}", err)
1437                                    );
1438                                }
1439
1440                                let request_rule = request_rule.clone();
1441                                let to_addressee_action = request_rule.1.to_addressee;
1442                                let to_sender_action = request_rule.1.to_sender;
1443                                let drop_connection_action = request_rule.1.drop_connection;
1444
1445                                let cluster_tx_clone = cluster_tx.clone();
1446                                let request_clone = request.clone();
1447                                let pass_action = async move {
1448                                    if let Some(ref pass_action) = to_addressee_action {
1449                                        if let Some(time) = pass_action.delay {
1450                                            tokio::time::sleep(time).await;
1451                                        }
1452                                        let passed_frame = match pass_action.msg_processor {
1453                                            Some(ref processor) => processor(request_clone),
1454                                            None => request_clone,
1455                                        };
1456                                        let _ = cluster_tx_clone.send(passed_frame);
1457                                    };
1458                                };
1459
1460                                let driver_tx_clone = driver_tx.clone();
1461                                let request_clone = request.clone();
1462                                let forge_action = async move {
1463                                    if let Some(ref forge_action) = to_sender_action {
1464                                        if let Some(time) = forge_action.delay {
1465                                            tokio::time::sleep(time).await;
1466                                        }
1467                                        let forged_frame = {
1468                                            let processor = forge_action.msg_processor.as_ref()
1469                                                .expect("Frame processor is required to forge a frame.");
1470                                            processor(request_clone)
1471                                        };
1472                                        let _ = driver_tx_clone.send(forged_frame);
1473                                    };
1474                                };
1475
1476                                let connection_close_signaler_clone =
1477                                    connection_close_signaler.clone();
1478                                let drop_action = async move {
1479                                    if let Some(ref delay) = drop_connection_action {
1480                                        if let Some(time) = delay {
1481                                            tokio::time::sleep(*time).await;
1482                                        }
1483                                        // close connection.
1484                                        info!(
1485                                            "Dropping connection between {} and {} ({}) (as requested by a proxy rule)!",
1486                                            driver_addr,
1487                                            DisplayableRealAddrOption(real_addr),
1488                                            DisplayableShard(shard),
1489                                        );
1490                                        let _ = connection_close_signaler_clone.send(());
1491                                    }
1492                                };
1493
1494                                tokio::task::spawn(async {
1495                                    futures::join!(pass_action, forge_action, drop_action);
1496                                });
1497
1498                                continue 'mainloop; // only one rule can be applied to one frame
1499                            }
1500                        }
1501                        let _ = cluster_tx.send(request); // default action
1502                    }
1503                    None => {
1504                        // Connection closed. If this was the control
1505                        // connection (REGISTER was seen), remove only this
1506                        // connection's sender from the shared map.
1507                        if event_registered_flag.load(Ordering::Relaxed) {
1508                            cc_event_sender.lock().unwrap().remove(&connection_no);
1509                            info!(
1510                                "Control connection {} ({} →  {} ({})) closed; removed cc_event_sender",
1511                                connection_no,
1512                                driver_addr,
1513                                DisplayableRealAddrOption(real_addr),
1514                                DisplayableShard(shard),
1515                            );
1516                        }
1517                        return Ok(());
1518                    }
1519                }
1520            }
1521        })
1522        .await;
1523    }
1524
1525    #[expect(clippy::too_many_arguments)]
1526    async fn response_processor(
1527        self,
1528        mut responses_rx: mpsc::UnboundedReceiver<ResponseFrame>,
1529        driver_tx: mpsc::UnboundedSender<ResponseFrame>,
1530        cluster_tx: mpsc::UnboundedSender<RequestFrame>,
1531        connection_no: usize,
1532        response_rules: Arc<Mutex<Vec<ResponseRule>>>,
1533        connection_close_signaler: ConnectionCloseSignaler,
1534        event_registered_flag: Arc<AtomicBool>,
1535    ) {
1536        let shard = self.shard;
1537        self.run_until_interrupted("response_processor", |driver_addr, _, real_addr| async move {
1538            'mainloop: loop {
1539                match responses_rx.recv().await {
1540                    Some(response) => {
1541                        let ctx = EvaluationContext {
1542                            connection_seq_no: connection_no,
1543                            opcode: FrameOpcode::Response(response.opcode),
1544                            frame_body: response.body.clone(),
1545                            connection_has_events: event_registered_flag.load(Ordering::Relaxed),
1546                        };
1547                        let mut guard = response_rules.lock().unwrap();
1548                        '_ruleloop: for (i, response_rule) in guard.iter_mut().enumerate() {
1549                            if response_rule.0.eval(&ctx) {
1550                                debug!("Applying rule no={} to response ({} -> {} ({})).", i, DisplayableRealAddrOption(real_addr), driver_addr, DisplayableShard(shard));
1551                                debug!("-> Applied rule: {:?}", response_rule);
1552                                debug!("-> To response: {:?}", ctx.opcode);
1553                                trace!("{:?}", response);
1554
1555                                if let Some(ref tx) = response_rule.1.feedback_channel {
1556                                    tx.send((response.clone(), shard)).unwrap_or_else(|err| warn!(
1557                                        "Could not send received response as feedback: {}", err
1558                                    ));
1559                                }
1560
1561                                let response_rule = response_rule.clone();
1562                                let to_addressee_action = response_rule.1.to_addressee;
1563                                let to_sender_action = response_rule.1.to_sender;
1564                                let drop_connection_action = response_rule.1.drop_connection;
1565
1566                                let response_clone = response.clone();
1567                                let driver_tx_clone = driver_tx.clone();
1568                                let pass_action = async move {
1569                                    if let Some(ref pass_action) = to_addressee_action {
1570                                        if let Some(time) = pass_action.delay {
1571                                            tokio::time::sleep(time).await;
1572                                        }
1573                                        let passed_frame = match pass_action.msg_processor {
1574                                            Some(ref processor) => processor(response_clone),
1575                                            None => response_clone,
1576                                        };
1577                                        let _ = driver_tx_clone.send(passed_frame);
1578                                    };
1579                                };
1580
1581                                let response_clone = response.clone();
1582                                let cluster_tx_clone = cluster_tx.clone();
1583                                let forge_action = async move {
1584                                    if let Some(ref forge_action) = to_sender_action {
1585                                        if let Some(time) = forge_action.delay {
1586                                            tokio::time::sleep(time).await;
1587                                        }
1588                                        let forged_frame = {
1589                                            let processor = forge_action.msg_processor.as_ref()
1590                                                .expect("Frame processor is required to forge a frame.");
1591                                            processor(response_clone)
1592                                        };
1593                                        let _ = cluster_tx_clone.send(forged_frame);
1594                                    };
1595                                };
1596
1597                                let connection_close_signaler_clone =
1598                                    connection_close_signaler.clone();
1599                                let drop_action = async move {
1600                                    if let Some(ref delay) = drop_connection_action {
1601                                        if let Some(time) = delay {
1602                                            tokio::time::sleep(*time).await;
1603                                        }
1604                                        // close connection.
1605                                        info!(
1606                                            "Dropping connection between {} and {} ({}) (as requested by a proxy rule)!",
1607                                            driver_addr,
1608                                            real_addr.expect("BUG: response rules are unavailable for dry-mode proxy!"),
1609                                            DisplayableShard(shard)
1610                                        );
1611                                        let _ = connection_close_signaler_clone.send(());
1612                                    }
1613                                };
1614
1615                                tokio::task::spawn(async {
1616                                    futures::join!(pass_action, forge_action, drop_action);
1617                                });
1618
1619                                continue 'mainloop;
1620                            }
1621                        }
1622                        let _ = driver_tx.send(response); // default action
1623                    }
1624                    None => return Ok(()),
1625                }
1626            }
1627        })
1628        .await
1629    }
1630}
1631
1632// Returns next free IP address for another proxy instance.
1633// Useful for concurrent testing.
1634pub fn get_exclusive_local_address() -> IpAddr {
1635    match std::env::var("NEXTEST_TEST_GLOBAL_SLOT") {
1636        Ok(slot) => {
1637            let slot: u16 = slot
1638                .parse()
1639                .unwrap_or_else(|e| panic!("Invalid slot {e:?}"));
1640            get_exclusive_local_address_nextest(slot)
1641        }
1642        Err(VarError::NotPresent) => get_exclusive_local_address_libtest(),
1643        Err(VarError::NotUnicode(e)) => panic!("Invalid slot {e:?}"),
1644    }
1645}
1646
1647fn get_exclusive_local_address_libtest() -> IpAddr {
1648    // A big enough number reduces possibility of clashes with user-taken addresses:
1649    static ADDRESS_LOWER_THREE_OCTETS: AtomicU32 = AtomicU32::new(4242);
1650    let next_addr = ADDRESS_LOWER_THREE_OCTETS.fetch_add(1, Ordering::Relaxed);
1651    if next_addr > (u32::MAX >> 8) {
1652        panic!("Loopback address pool for tests depleted");
1653    }
1654    let next_addr_bytes = next_addr.to_le_bytes();
1655    IpAddr::V4(Ipv4Addr::new(
1656        127,
1657        next_addr_bytes[2],
1658        next_addr_bytes[1],
1659        next_addr_bytes[0],
1660    ))
1661}
1662
1663fn get_exclusive_local_address_nextest(slot: u16) -> IpAddr {
1664    static ADDRESS_LOWER_OCTET: AtomicU8 = AtomicU8::new(255);
1665    // This is a heuristic to avoid using low addresses, which I think have
1666    // a higher chance of being taken.
1667    const FREE_RANGES: u16 = 16;
1668    let next_address_lower = ADDRESS_LOWER_OCTET.fetch_sub(1, Ordering::Relaxed);
1669    if next_address_lower == 0 {
1670        panic!("Loopback address pool for this test depleted");
1671    }
1672
1673    let next_range_bytes: [u8; 2] = slot
1674        .checked_add(FREE_RANGES)
1675        .unwrap_or_else(|| panic!("Loopback address pool for tests depleted"))
1676        .to_le_bytes();
1677
1678    IpAddr::V4(Ipv4Addr::new(
1679        127,
1680        next_range_bytes[1],
1681        next_range_bytes[0],
1682        next_address_lower,
1683    ))
1684}
1685
1686#[cfg(test)]
1687mod tests {
1688    use super::compression::no_compression;
1689    use super::*;
1690    use crate::errors::ReadFrameError;
1691    use crate::frame::{FrameType, read_frame, read_request_frame, read_response_frame};
1692    use crate::proxy::compression::with_compression;
1693    use crate::{
1694        Condition, Reaction as _, RequestReaction, ResponseOpcode, ResponseReaction, setup_tracing,
1695    };
1696    use assert_matches::assert_matches;
1697    use bytes::{BufMut, BytesMut};
1698    use futures::future::{join, join3};
1699    use rand::RngCore;
1700    use scylla_cql::frame::request::options;
1701    use scylla_cql::frame::request::{SerializableRequest as _, Startup};
1702    use scylla_cql::frame::types::write_string_multimap;
1703    use scylla_cql::frame::{Compression, flag};
1704    use std::collections::HashMap;
1705    use std::mem;
1706    use std::str::FromStr;
1707    use std::time::Duration;
1708    use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
1709    use tokio::sync::oneshot;
1710
1711    fn random_body() -> Bytes {
1712        let body_len = (rand::random::<u32>() % 1000) as usize;
1713        let mut body = BytesMut::zeroed(body_len);
1714        rand::rng().fill_bytes(body.as_mut());
1715        body.freeze()
1716    }
1717
1718    async fn respond_with_supported(
1719        conn: &mut TcpStream,
1720        supported_options: &HashMap<String, Vec<String>>,
1721        compression: &CompressionReader,
1722    ) {
1723        let RequestFrame {
1724            params: recvd_params,
1725            opcode: recvd_opcode,
1726            body: recvd_body,
1727        } = read_request_frame(conn, compression).await.unwrap();
1728        assert_eq!(recvd_params, HARDCODED_OPTIONS_PARAMS);
1729        assert_eq!(recvd_opcode, RequestOpcode::Options);
1730        assert_eq!(recvd_body, Bytes::new()); // body should be empty
1731
1732        let mut body = BytesMut::new();
1733        write_string_multimap(supported_options, &mut body).unwrap();
1734
1735        let body = body.freeze();
1736
1737        write_frame(
1738            HARDCODED_OPTIONS_PARAMS.for_response(),
1739            FrameOpcode::Response(ResponseOpcode::Supported),
1740            &body,
1741            conn,
1742            &no_compression(),
1743        )
1744        .await
1745        .unwrap();
1746    }
1747
1748    fn supported_shards_count(shards_count: u16) -> HashMap<String, Vec<String>> {
1749        let mut sharded_info = HashMap::new();
1750        sharded_info.insert(
1751            String::from("SCYLLA_NR_SHARDS"),
1752            vec![shards_count.to_string()],
1753        );
1754        sharded_info
1755    }
1756
1757    fn supported_shard_number(shard_num: TargetShard) -> HashMap<String, Vec<String>> {
1758        let mut sharded_info = HashMap::new();
1759        sharded_info.insert(String::from("SCYLLA_SHARD"), vec![shard_num.to_string()]);
1760        sharded_info
1761    }
1762
1763    async fn respond_with_shards_count(
1764        conn: &mut TcpStream,
1765        shards_count: u16,
1766        compression: &CompressionReader,
1767    ) {
1768        respond_with_supported(conn, &supported_shards_count(shards_count), compression).await;
1769    }
1770
1771    async fn respond_with_shard_num(
1772        conn: &mut TcpStream,
1773        shard_num: TargetShard,
1774        compression: &CompressionReader,
1775    ) {
1776        respond_with_supported(conn, &supported_shard_number(shard_num), compression).await;
1777    }
1778
1779    fn next_local_address_with_port(port: u16) -> SocketAddr {
1780        SocketAddr::new(get_exclusive_local_address(), port)
1781    }
1782
1783    async fn identity_proxy_does_not_mutate_frames(shard_awareness: ShardAwareness) {
1784        let node1_real_addr = next_local_address_with_port(9876);
1785        let node1_proxy_addr = next_local_address_with_port(9876);
1786        let proxy = Proxy::new([Node::new(
1787            node1_real_addr,
1788            node1_proxy_addr,
1789            shard_awareness,
1790            None,
1791            None,
1792        )]);
1793        let running_proxy = proxy.run().await.unwrap();
1794
1795        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
1796
1797        let params = FrameParams {
1798            flags: 0,
1799            version: 0x04,
1800            stream: 0,
1801        };
1802        let opcode = FrameOpcode::Request(RequestOpcode::Options);
1803
1804        let body = random_body();
1805
1806        let send_frame_to_shard = async {
1807            let mut conn = TcpStream::connect(node1_proxy_addr).await.unwrap();
1808
1809            write_frame(params, opcode, &body, &mut conn, &no_compression())
1810                .await
1811                .unwrap();
1812            conn
1813        };
1814
1815        let mock_node_action = async {
1816            if let ShardAwareness::QueryNode = shard_awareness {
1817                respond_with_shards_count(
1818                    &mut mock_node_listener.accept().await.unwrap().0,
1819                    1,
1820                    &no_compression(),
1821                )
1822                .await;
1823            }
1824            let (mut conn, _) = mock_node_listener.accept().await.unwrap();
1825            if shard_awareness.is_aware() {
1826                respond_with_shard_num(&mut conn, 1, &no_compression()).await;
1827            }
1828            let RequestFrame {
1829                params: recvd_params,
1830                opcode: recvd_opcode,
1831                body: recvd_body,
1832            } = read_request_frame(&mut conn, &no_compression())
1833                .await
1834                .unwrap();
1835            assert_eq!(recvd_params, params);
1836            assert_eq!(FrameOpcode::Request(recvd_opcode), opcode);
1837            assert_eq!(recvd_body, body);
1838            conn
1839        };
1840
1841        // we keep the connections open until proxy finishes to let it perform clean exit with no disconnects
1842        let (_node_conn, _driver_conn) = join(mock_node_action, send_frame_to_shard).await;
1843        running_proxy.finish().await.unwrap();
1844    }
1845
1846    #[tokio::test]
1847    async fn identity_shard_unaware_proxy_does_not_mutate_frames() {
1848        setup_tracing();
1849        identity_proxy_does_not_mutate_frames(ShardAwareness::Unaware).await
1850    }
1851
1852    #[tokio::test]
1853    async fn identity_shard_aware_proxy_does_not_mutate_frames() {
1854        setup_tracing();
1855        identity_proxy_does_not_mutate_frames(ShardAwareness::QueryNode).await
1856    }
1857
1858    #[tokio::test]
1859    async fn shard_aware_proxy_is_transparent_for_connection_to_shards() {
1860        setup_tracing();
1861        async fn test_for_shards_num(shards_num: u16) {
1862            let node1_real_addr = next_local_address_with_port(9876);
1863            let node1_proxy_addr = next_local_address_with_port(9876);
1864            let proxy = Proxy::new([Node::new(
1865                node1_real_addr,
1866                node1_proxy_addr,
1867                ShardAwareness::FixedNum(shards_num),
1868                None,
1869                None,
1870            )]);
1871            let running_proxy = proxy.run().await.unwrap();
1872
1873            let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
1874
1875            let (driver_addr_tx, driver_addr_rx) = oneshot::channel::<SocketAddr>();
1876
1877            let send_frame_to_shard = async {
1878                let socket = TcpSocket::new_v4().unwrap();
1879                socket
1880                    .bind(SocketAddr::from_str("0.0.0.0:0").unwrap())
1881                    .unwrap();
1882                let conn = socket.connect(node1_proxy_addr).await.unwrap();
1883                driver_addr_tx.send(conn.local_addr().unwrap()).unwrap();
1884                conn
1885            };
1886
1887            let mock_node_action = async {
1888                let (conn, remote_addr) = mock_node_listener.accept().await.unwrap();
1889                let driver_addr = driver_addr_rx.await.unwrap();
1890                assert_eq!(
1891                    driver_addr.port() % shards_num,
1892                    remote_addr.port() % shards_num
1893                );
1894                conn
1895            };
1896
1897            // we keep the connections open until proxy finishes to let it perform clean exit with no disconnects
1898            let (_node_conn, _driver_conn) = join(mock_node_action, send_frame_to_shard).await;
1899            running_proxy.finish().await.unwrap();
1900        }
1901
1902        for shard_num in 1..6 {
1903            test_for_shards_num(shard_num).await;
1904        }
1905    }
1906
1907    #[tokio::test]
1908    async fn shard_aware_proxy_queries_shards_number() {
1909        setup_tracing();
1910        async fn test_for_shards_num(shards_num: u16) {
1911            for shard_num in 0..shards_num {
1912                let node1_real_addr = next_local_address_with_port(9876);
1913                let node1_proxy_addr = next_local_address_with_port(9876);
1914                let proxy = Proxy::new([Node::new(
1915                    node1_real_addr,
1916                    node1_proxy_addr,
1917                    ShardAwareness::QueryNode,
1918                    None,
1919                    None,
1920                )]);
1921                let running_proxy = proxy.run().await.unwrap();
1922
1923                let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
1924
1925                let (driver_addr_tx, driver_addr_rx) = oneshot::channel::<SocketAddr>();
1926
1927                let mock_driver_addr = next_local_address_with_port(shards_num * 1234 + shard_num);
1928                let send_frame_to_shard = async {
1929                    let socket = TcpSocket::new_v4().unwrap();
1930                    socket
1931                        .bind(mock_driver_addr)
1932                        .unwrap_or_else(|_| panic!("driver_addr failed: {mock_driver_addr}"));
1933                    driver_addr_tx.send(socket.local_addr().unwrap()).unwrap();
1934                    socket.connect(node1_proxy_addr).await.unwrap()
1935                };
1936
1937                let mock_node_action = async {
1938                    respond_with_shards_count(
1939                        &mut mock_node_listener.accept().await.unwrap().0,
1940                        shards_num,
1941                        &no_compression(),
1942                    )
1943                    .await;
1944                    let (conn, remote_addr) = mock_node_listener.accept().await.unwrap();
1945                    let driver_addr = driver_addr_rx.await.unwrap();
1946                    assert_eq!(
1947                        driver_addr.port() % shards_num,
1948                        remote_addr.port() % shards_num
1949                    );
1950                    conn
1951                };
1952
1953                let (_node_conn, _driver_conn) = join(mock_node_action, send_frame_to_shard).await;
1954                running_proxy.finish().await.unwrap();
1955            }
1956        }
1957
1958        for shard_num in 1..6 {
1959            test_for_shards_num(shard_num).await;
1960        }
1961    }
1962
1963    #[tokio::test]
1964    async fn forger_proxy_forges_response() {
1965        setup_tracing();
1966        let node1_real_addr = next_local_address_with_port(9876);
1967        let node1_proxy_addr = next_local_address_with_port(9876);
1968
1969        let this_shall_pass = b"This.Shall.Pass.";
1970        let test_msg = b"Test";
1971
1972        let proxy = Proxy::new([Node::new(
1973            node1_real_addr,
1974            node1_proxy_addr,
1975            ShardAwareness::Unaware,
1976            Some(vec![
1977                RequestRule(
1978                    Condition::RequestOpcode(RequestOpcode::Register),
1979                    RequestReaction::forge_response(Arc::new(|RequestFrame { params, .. }| {
1980                        ResponseFrame {
1981                            params: params.for_response(),
1982                            opcode: ResponseOpcode::Event,
1983                            body: Bytes::from_static(test_msg),
1984                        }
1985                    })),
1986                ),
1987                RequestRule(
1988                    Condition::BodyContainsCaseSensitive(Box::new(*this_shall_pass)),
1989                    RequestReaction::noop(),
1990                ),
1991                RequestRule(
1992                    Condition::True, // only the first matching rule is applied, so "True" covers all remaining cases
1993                    RequestReaction::forge_response(Arc::new(|RequestFrame { params, .. }| {
1994                        ResponseFrame {
1995                            params: params.for_response(),
1996                            opcode: ResponseOpcode::Ready,
1997                            body: Bytes::new(),
1998                        }
1999                    })),
2000                ),
2001            ]),
2002            None,
2003        )]);
2004        let running_proxy = proxy.run().await.unwrap();
2005
2006        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2007
2008        let params1 = FrameParams {
2009            flags: 2,
2010            version: 0x42,
2011            stream: 42,
2012        };
2013        let opcode1 = FrameOpcode::Request(RequestOpcode::Startup);
2014
2015        let params2 = FrameParams {
2016            flags: 4,
2017            version: 0x04,
2018            stream: 17,
2019        };
2020        let opcode2 = FrameOpcode::Request(RequestOpcode::Register);
2021
2022        let params3 = FrameParams {
2023            flags: 8,
2024            version: 0x04,
2025            stream: 11,
2026        };
2027        let opcode3 = FrameOpcode::Request(RequestOpcode::Execute);
2028
2029        let body1 = random_body();
2030        let body2 = random_body();
2031        let body3 = {
2032            let mut body = BytesMut::new();
2033            body.put(&b"uSeLeSs JuNk"[..]);
2034            body.put(&this_shall_pass[..]);
2035            body.freeze()
2036        };
2037
2038        let send_frame_to_shard = async {
2039            let mut conn = TcpStream::connect(node1_proxy_addr).await.unwrap();
2040
2041            write_frame(params1, opcode1, &body1, &mut conn, &no_compression())
2042                .await
2043                .unwrap();
2044            write_frame(params2, opcode2, &body2, &mut conn, &no_compression())
2045                .await
2046                .unwrap();
2047            write_frame(params3, opcode3, &body3, &mut conn, &no_compression())
2048                .await
2049                .unwrap();
2050
2051            let ResponseFrame {
2052                params: recvd_params,
2053                opcode: recvd_opcode,
2054                body: recvd_body,
2055            } = read_response_frame(&mut conn, &no_compression())
2056                .await
2057                .unwrap();
2058            assert_eq!(recvd_params, params1.for_response());
2059            assert_eq!(recvd_opcode, ResponseOpcode::Ready);
2060            assert_eq!(recvd_body, Bytes::new());
2061
2062            let ResponseFrame {
2063                params: recvd_params,
2064                opcode: recvd_opcode,
2065                body: recvd_body,
2066            } = read_response_frame(&mut conn, &no_compression())
2067                .await
2068                .unwrap();
2069            assert_eq!(recvd_params, params2.for_response());
2070            assert_eq!(recvd_opcode, ResponseOpcode::Event);
2071            assert_eq!(recvd_body, Bytes::from_static(test_msg));
2072
2073            conn
2074        };
2075
2076        let mock_node_action = async {
2077            let (mut conn, _) = mock_node_listener.accept().await.unwrap();
2078            let RequestFrame {
2079                params: recvd_params,
2080                opcode: recvd_opcode,
2081                body: recvd_body,
2082            } = read_request_frame(&mut conn, &no_compression())
2083                .await
2084                .unwrap();
2085            assert_eq!(recvd_params, params3);
2086            assert_eq!(FrameOpcode::Request(recvd_opcode), opcode3);
2087            assert_eq!(recvd_body, body3);
2088
2089            conn
2090        };
2091
2092        let (mut node_conn, mut driver_conn) = join(mock_node_action, send_frame_to_shard).await;
2093
2094        running_proxy.finish().await.unwrap();
2095
2096        assert_matches!(driver_conn.read(&mut [0u8; 1]).await, Ok(0));
2097        assert_matches!(node_conn.read(&mut [0u8; 1]).await, Ok(0));
2098    }
2099
2100    #[tokio::test]
2101    async fn ad_hoc_rules_changing() {
2102        setup_tracing();
2103        let node1_real_addr = next_local_address_with_port(9876);
2104        let node1_proxy_addr = next_local_address_with_port(9876);
2105        let proxy = Proxy::new([Node::new(
2106            node1_real_addr,
2107            node1_proxy_addr,
2108            ShardAwareness::Unaware,
2109            None,
2110            None,
2111        )]);
2112        let mut running_proxy = proxy.run().await.unwrap();
2113
2114        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2115
2116        let params = FrameParams {
2117            flags: 0,
2118            version: 0x04,
2119            stream: 0,
2120        };
2121        let opcode = FrameOpcode::Request(RequestOpcode::Options);
2122
2123        let body = random_body();
2124
2125        let (mut driver, mut node) = {
2126            let results = join(
2127                TcpStream::connect(node1_proxy_addr),
2128                mock_node_listener.accept(),
2129            )
2130            .await;
2131            (results.0.unwrap(), results.1.unwrap().0)
2132        };
2133
2134        async fn request(
2135            driver: &mut TcpStream,
2136            node: &mut TcpStream,
2137            params: FrameParams,
2138            opcode: FrameOpcode,
2139            body: &Bytes,
2140        ) -> Result<RequestFrame, ReadFrameError> {
2141            let (send_res, recv_res) = join(
2142                write_frame(params, opcode, &body.clone(), driver, &no_compression()),
2143                read_request_frame(node, &no_compression()),
2144            )
2145            .await;
2146            send_res.unwrap();
2147            recv_res
2148        }
2149        {
2150            // one run still without custom rules
2151            let RequestFrame {
2152                params: recvd_params,
2153                opcode: recvd_opcode,
2154                body: recvd_body,
2155            } = request(&mut driver, &mut node, params, opcode, &body)
2156                .await
2157                .unwrap();
2158            assert_eq!(recvd_params, params);
2159            assert_eq!(FrameOpcode::Request(recvd_opcode), opcode);
2160            assert_eq!(recvd_body, body);
2161        }
2162        running_proxy.running_nodes[0].change_request_rules(Some(vec![RequestRule(
2163            Condition::True,
2164            RequestReaction::drop_frame(),
2165        )]));
2166
2167        {
2168            // one run with custom rules
2169            tokio::select! {
2170                res = request(&mut driver, &mut node, params, opcode, &body) => panic!("Rules did not work: received response {:?}", res),
2171                _ = tokio::time::sleep(std::time::Duration::from_millis(20)) => (),
2172            };
2173        }
2174
2175        running_proxy.turn_off_rules();
2176
2177        {
2178            // one run already without custom rules
2179            let RequestFrame {
2180                params: recvd_params,
2181                opcode: recvd_opcode,
2182                body: recvd_body,
2183            } = request(&mut driver, &mut node, params, opcode, &body)
2184                .await
2185                .unwrap();
2186            assert_eq!(recvd_params, params);
2187            assert_eq!(FrameOpcode::Request(recvd_opcode), opcode);
2188            assert_eq!(recvd_body, body);
2189        }
2190
2191        running_proxy.finish().await.unwrap();
2192    }
2193
2194    #[tokio::test]
2195    async fn limited_times_condition_expires() {
2196        setup_tracing();
2197        const FAILING_TRIES: usize = 4;
2198        const PASSING_TRIES: usize = 5;
2199
2200        let node1_real_addr = next_local_address_with_port(9876);
2201        let node1_proxy_addr = next_local_address_with_port(9876);
2202        let proxy = Proxy::new([Node::new(
2203            node1_real_addr,
2204            node1_proxy_addr,
2205            ShardAwareness::Unaware,
2206            Some(vec![
2207                RequestRule(
2208                    // this will be always fired after first PASSING_TRIES + FAILING_TRIES
2209                    Condition::not(Condition::TrueForLimitedTimes(
2210                        FAILING_TRIES + PASSING_TRIES,
2211                    )),
2212                    RequestReaction::drop_frame(),
2213                ),
2214                RequestRule(
2215                    // this will be fired for PASSING_TRIES after first FAILING_TRIES
2216                    Condition::not(Condition::TrueForLimitedTimes(FAILING_TRIES)),
2217                    RequestReaction::noop(),
2218                ),
2219                RequestRule(
2220                    // this will be fired for first FAILING_TRIES
2221                    Condition::True,
2222                    RequestReaction::drop_frame(),
2223                ),
2224            ]),
2225            None,
2226        )]);
2227        let running_proxy = proxy.run().await.unwrap();
2228
2229        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2230
2231        let params = FrameParams {
2232            flags: 0,
2233            version: 0x04,
2234            stream: 0,
2235        };
2236        let opcode = FrameOpcode::Request(RequestOpcode::Options);
2237        let body = random_body();
2238
2239        let (mut driver, mut node) = {
2240            let results = join(
2241                TcpStream::connect(node1_proxy_addr),
2242                mock_node_listener.accept(),
2243            )
2244            .await;
2245            (results.0.unwrap(), results.1.unwrap().0)
2246        };
2247
2248        async fn request(
2249            driver: &mut TcpStream,
2250            node: &mut TcpStream,
2251            params: FrameParams,
2252            opcode: FrameOpcode,
2253            body: &Bytes,
2254        ) -> Result<RequestFrame, ReadFrameError> {
2255            let (send_res, recv_res) = join(
2256                write_frame(params, opcode, &body.clone(), driver, &no_compression()),
2257                read_request_frame(node, &no_compression()),
2258            )
2259            .await;
2260            send_res.unwrap();
2261            recv_res
2262        }
2263
2264        for _ in 0..FAILING_TRIES {
2265            tokio::select! {
2266                res = request(&mut driver, &mut node, params, opcode, &body) => panic!("Rules did not work: received response {:?}", res),
2267                _ = tokio::time::sleep(std::time::Duration::from_millis(10)) => (),
2268            };
2269        }
2270
2271        for _ in 0..PASSING_TRIES {
2272            let RequestFrame {
2273                params: recvd_params,
2274                opcode: recvd_opcode,
2275                body: recvd_body,
2276            } = request(&mut driver, &mut node, params, opcode, &body)
2277                .await
2278                .unwrap();
2279            assert_eq!(recvd_params, params);
2280            assert_eq!(FrameOpcode::Request(recvd_opcode), opcode);
2281            assert_eq!(recvd_body, body);
2282        }
2283
2284        for _ in 0..3 {
2285            // any further number of requests should fail
2286            tokio::select! {
2287                res = request(&mut driver, &mut node, params, opcode, &body) => panic!("Rules did not work: received response {:?}", res),
2288                _ = tokio::time::sleep(std::time::Duration::from_millis(10)) => (),
2289            };
2290        }
2291
2292        running_proxy.finish().await.unwrap();
2293    }
2294
2295    #[tokio::test]
2296    async fn proxy_reports_requests_and_responses_as_feedback() {
2297        setup_tracing();
2298        let node1_real_addr = next_local_address_with_port(9876);
2299        let node1_proxy_addr = next_local_address_with_port(9876);
2300
2301        let (request_feedback_tx, mut request_feedback_rx) = mpsc::unbounded_channel();
2302        let (response_feedback_tx, mut response_feedback_rx) = mpsc::unbounded_channel();
2303        let proxy = Proxy::new([Node::new(
2304            node1_real_addr,
2305            node1_proxy_addr,
2306            ShardAwareness::Unaware,
2307            Some(vec![RequestRule(
2308                Condition::True,
2309                RequestReaction::drop_frame().with_feedback_when_performed(request_feedback_tx),
2310            )]),
2311            Some(vec![ResponseRule(
2312                Condition::True,
2313                ResponseReaction::drop_frame().with_feedback_when_performed(response_feedback_tx),
2314            )]),
2315        )]);
2316        let running_proxy = proxy.run().await.unwrap();
2317
2318        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2319
2320        let params = FrameParams {
2321            flags: 0,
2322            version: 0x04,
2323            stream: 0,
2324        };
2325        let request_opcode = FrameOpcode::Request(RequestOpcode::Options);
2326        let response_opcode = FrameOpcode::Response(ResponseOpcode::Ready);
2327
2328        let body = random_body();
2329
2330        let send_frame_to_shard = async {
2331            let mut conn = TcpStream::connect(node1_proxy_addr).await.unwrap();
2332            write_frame(params, request_opcode, &body, &mut conn, &no_compression())
2333                .await
2334                .unwrap();
2335            conn
2336        };
2337
2338        let mock_node_action = async {
2339            let (mut conn, _) = mock_node_listener.accept().await.unwrap();
2340            write_frame(
2341                params.for_response(),
2342                response_opcode,
2343                &body,
2344                &mut conn,
2345                &no_compression(),
2346            )
2347            .await
2348            .unwrap();
2349            conn
2350        };
2351
2352        // we keep the connections open until proxy finishes to let it perform clean exit with no disconnects
2353        let (_node_conn, _driver_conn) = join(mock_node_action, send_frame_to_shard).await;
2354
2355        let (feedback_request, _shard) = request_feedback_rx.recv().await.unwrap();
2356        assert_eq!(feedback_request.params, params);
2357        assert_eq!(
2358            FrameOpcode::Request(feedback_request.opcode),
2359            request_opcode
2360        );
2361        assert_eq!(feedback_request.body, body);
2362        let (feedback_response, _shard) = response_feedback_rx.recv().await.unwrap();
2363        assert_eq!(feedback_response.params, params.for_response());
2364        assert_eq!(
2365            FrameOpcode::Response(feedback_response.opcode),
2366            response_opcode
2367        );
2368        assert_eq!(feedback_response.body, body);
2369
2370        running_proxy.finish().await.unwrap();
2371    }
2372
2373    #[tokio::test]
2374    async fn sanity_check_reports_errors() {
2375        setup_tracing();
2376        let node1_real_addr = next_local_address_with_port(9876);
2377        let node1_proxy_addr = next_local_address_with_port(9876);
2378        let proxy = Proxy::new([Node::new(
2379            node1_real_addr,
2380            node1_proxy_addr,
2381            ShardAwareness::Unaware,
2382            None,
2383            None,
2384        )]);
2385        let mut running_proxy = proxy.run().await.unwrap();
2386
2387        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2388
2389        let send_frame_to_shard = async {
2390            let mut conn = TcpStream::connect(node1_proxy_addr).await.unwrap();
2391
2392            conn.write_all(b"uselessJunk").await.unwrap();
2393            conn
2394        };
2395
2396        let mock_node_action = async {
2397            let (conn, _) = mock_node_listener.accept().await.unwrap();
2398            conn
2399        };
2400
2401        let (node_conn, driver_conn) = join(mock_node_action, send_frame_to_shard).await;
2402
2403        running_proxy.sanity_check().unwrap();
2404
2405        mem::drop(driver_conn);
2406        assert_matches!(
2407            running_proxy.wait_for_error().await,
2408            Some(ProxyError::Worker(WorkerError::DriverDisconnected(_)))
2409        );
2410        running_proxy.sanity_check().unwrap();
2411
2412        mem::drop(node_conn);
2413        assert_matches!(
2414            running_proxy.wait_for_error().await,
2415            Some(ProxyError::Worker(WorkerError::NodeDisconnected(_)))
2416        );
2417        running_proxy.sanity_check().unwrap();
2418
2419        // we keep the connections open until proxy finishes to let it perform clean exit with no disconnects
2420        let _ = running_proxy.finish().await;
2421    }
2422
2423    #[tokio::test]
2424    async fn proxy_processes_requests_concurrently() {
2425        setup_tracing();
2426        let node1_real_addr = next_local_address_with_port(9876);
2427        let node1_proxy_addr = next_local_address_with_port(9876);
2428
2429        let delay = Duration::from_millis(60);
2430
2431        let proxy = Proxy::new([Node::new(
2432            node1_real_addr,
2433            node1_proxy_addr,
2434            ShardAwareness::Unaware,
2435            Some(vec![RequestRule(
2436                Condition::TrueForLimitedTimes(1),
2437                RequestReaction::delay(delay),
2438            )]),
2439            None,
2440        )]);
2441        let running_proxy = proxy.run().await.unwrap();
2442
2443        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2444
2445        let params1 = FrameParams {
2446            flags: 0,
2447            version: 0x04,
2448            stream: 0,
2449        };
2450        let opcode1 = FrameOpcode::Request(RequestOpcode::Options);
2451
2452        let body1 = random_body();
2453
2454        let params2 = FrameParams {
2455            flags: 0,
2456            version: 0x04,
2457            stream: 0,
2458        };
2459        let opcode2 = FrameOpcode::Request(RequestOpcode::Register);
2460
2461        let body2 = random_body();
2462
2463        let send_frame_to_shard = async {
2464            let mut conn = TcpStream::connect(node1_proxy_addr).await.unwrap();
2465
2466            write_frame(params1, opcode1, &body1, &mut conn, &no_compression())
2467                .await
2468                .unwrap();
2469            write_frame(params2, opcode2, &body2, &mut conn, &no_compression())
2470                .await
2471                .unwrap();
2472            conn
2473        };
2474
2475        let mock_node_action = async {
2476            let (mut conn, _) = mock_node_listener.accept().await.unwrap();
2477            let RequestFrame {
2478                params: recvd_params,
2479                opcode: recvd_opcode,
2480                body: recvd_body,
2481            } = read_request_frame(&mut conn, &no_compression())
2482                .await
2483                .unwrap();
2484            assert_eq!(recvd_params, params2);
2485            assert_eq!(FrameOpcode::Request(recvd_opcode), opcode2);
2486            assert_eq!(recvd_body, body2);
2487            conn
2488        };
2489
2490        // we keep the connections open until proxy finishes to let it perform clean exit with no disconnects
2491        let (_node_conn, _driver_conn) =
2492            tokio::time::timeout(delay, join(mock_node_action, send_frame_to_shard))
2493                .await
2494                .expect("Request processing was not concurrent");
2495        running_proxy.finish().await.unwrap();
2496    }
2497
2498    #[tokio::test]
2499    async fn dry_mode_proxy_drops_incoming_frames() {
2500        setup_tracing();
2501        let node1_proxy_addr = next_local_address_with_port(9876);
2502        let proxy = Proxy::new([Node::new_dry_mode(node1_proxy_addr, None)]);
2503        let running_proxy = proxy.run().await.unwrap();
2504
2505        let params = FrameParams {
2506            flags: 0,
2507            version: 0x04,
2508            stream: 0,
2509        };
2510        let opcode = FrameOpcode::Request(RequestOpcode::Options);
2511
2512        let body = random_body();
2513
2514        let mut conn = TcpStream::connect(node1_proxy_addr).await.unwrap();
2515
2516        write_frame(params, opcode, &body, &mut conn, &no_compression())
2517            .await
2518            .unwrap();
2519        // We assert that after sufficiently long time, no error happens inside proxy.
2520        tokio::time::sleep(Duration::from_millis(3)).await;
2521        running_proxy.finish().await.unwrap();
2522    }
2523
2524    #[tokio::test]
2525    async fn dry_mode_forger_proxy_forges_response() {
2526        setup_tracing();
2527        let node1_proxy_addr = next_local_address_with_port(9876);
2528
2529        let this_shall_pass = b"This.Shall.Pass.";
2530        let test_msg = b"Test";
2531
2532        let proxy = Proxy::new([Node::new_dry_mode(
2533            node1_proxy_addr,
2534            Some(vec![
2535                RequestRule(
2536                    Condition::RequestOpcode(RequestOpcode::Register),
2537                    RequestReaction::forge_response(Arc::new(|RequestFrame { params, .. }| {
2538                        ResponseFrame {
2539                            params: params.for_response(),
2540                            opcode: ResponseOpcode::Event,
2541                            body: Bytes::from_static(test_msg),
2542                        }
2543                    })),
2544                ),
2545                RequestRule(
2546                    Condition::BodyContainsCaseSensitive(Box::new(*this_shall_pass)),
2547                    RequestReaction::noop(),
2548                ),
2549                RequestRule(
2550                    Condition::True, // only the first matching rule is applied, so "True" covers all remaining cases
2551                    RequestReaction::forge_response(Arc::new(|RequestFrame { params, .. }| {
2552                        ResponseFrame {
2553                            params: params.for_response(),
2554                            opcode: ResponseOpcode::Ready,
2555                            body: Bytes::new(),
2556                        }
2557                    })),
2558                ),
2559            ]),
2560        )]);
2561        let running_proxy = proxy.run().await.unwrap();
2562
2563        let params1 = FrameParams {
2564            flags: 2,
2565            version: 0x42,
2566            stream: 42,
2567        };
2568        let opcode1 = FrameOpcode::Request(RequestOpcode::Startup);
2569
2570        let params2 = FrameParams {
2571            flags: 4,
2572            version: 0x04,
2573            stream: 17,
2574        };
2575        let opcode2 = FrameOpcode::Request(RequestOpcode::Register);
2576
2577        let params3 = FrameParams {
2578            flags: 8,
2579            version: 0x04,
2580            stream: 11,
2581        };
2582        let opcode3 = FrameOpcode::Request(RequestOpcode::Execute);
2583
2584        let body1 = random_body();
2585        let body2 = random_body();
2586        let body3 = {
2587            let mut body = BytesMut::new();
2588            body.put(&b"uSeLeSs JuNk"[..]);
2589            body.put(&this_shall_pass[..]);
2590            body.freeze()
2591        };
2592
2593        let mut conn = TcpStream::connect(node1_proxy_addr).await.unwrap();
2594
2595        write_frame(params1, opcode1, &body1, &mut conn, &no_compression())
2596            .await
2597            .unwrap();
2598        write_frame(params2, opcode2, &body2, &mut conn, &no_compression())
2599            .await
2600            .unwrap();
2601        write_frame(params3, opcode3, &body3, &mut conn, &no_compression())
2602            .await
2603            .unwrap();
2604
2605        let ResponseFrame {
2606            params: recvd_params,
2607            opcode: recvd_opcode,
2608            body: recvd_body,
2609        } = read_response_frame(&mut conn, &no_compression())
2610            .await
2611            .unwrap();
2612        assert_eq!(recvd_params, params1.for_response());
2613        assert_eq!(recvd_opcode, ResponseOpcode::Ready);
2614        assert_eq!(recvd_body, Bytes::new());
2615
2616        let ResponseFrame {
2617            params: recvd_params,
2618            opcode: recvd_opcode,
2619            body: recvd_body,
2620        } = read_response_frame(&mut conn, &no_compression())
2621            .await
2622            .unwrap();
2623        assert_eq!(recvd_params, params2.for_response());
2624        assert_eq!(recvd_opcode, ResponseOpcode::Event);
2625        assert_eq!(recvd_body, Bytes::from_static(test_msg));
2626
2627        running_proxy.finish().await.unwrap();
2628
2629        assert_matches!(conn.read(&mut [0u8; 1]).await, Ok(0));
2630    }
2631
2632    // The test asserts that once a (mock) driver connects to the proxy from some port,
2633    // the proxy will connect to a shard corresponding to that port and that the target
2634    // shard number will be sent through the feedback channel.
2635    #[tokio::test]
2636    async fn proxy_reports_target_shard_as_feedback() {
2637        setup_tracing();
2638
2639        let node_port = 10101;
2640        let node_real_addr = next_local_address_with_port(node_port);
2641        let mock_node_listener = TcpListener::bind(node_real_addr).await.unwrap();
2642
2643        let params = FrameParams {
2644            flags: 0,
2645            version: 0x04,
2646            stream: 0,
2647        };
2648        let request_opcode = FrameOpcode::Request(RequestOpcode::Options);
2649        let response_opcode = FrameOpcode::Response(ResponseOpcode::Ready);
2650
2651        let body = random_body();
2652
2653        for shards_count in 2..9 {
2654            // Two driver connections are simulated, each to a different shard.
2655            let driver1_shard = shards_count - 1;
2656            let driver2_shard = shards_count - 2;
2657            let node_proxy_addr = next_local_address_with_port(node_port);
2658
2659            let (request_feedback_tx, mut request_feedback_rx) = mpsc::unbounded_channel();
2660            let (response_feedback_tx, mut response_feedback_rx) = mpsc::unbounded_channel();
2661
2662            let proxy = Proxy::new([Node::new(
2663                node_real_addr,
2664                node_proxy_addr,
2665                ShardAwareness::FixedNum(shards_count),
2666                Some(vec![RequestRule(
2667                    Condition::True,
2668                    RequestReaction::drop_frame().with_feedback_when_performed(request_feedback_tx),
2669                )]),
2670                Some(vec![ResponseRule(
2671                    Condition::True,
2672                    ResponseReaction::drop_frame()
2673                        .with_feedback_when_performed(response_feedback_tx),
2674                )]),
2675            )]);
2676            let running_proxy = proxy.run().await.unwrap();
2677
2678            /// Choose a source port `p` such that `shard == shard_of_source_port(p)`.
2679            fn draw_source_port_for_shard(shards_count: u16, shard: u16) -> u16 {
2680                assert!(shard < shards_count);
2681                49152u16.next_multiple_of(shards_count) + shard
2682            }
2683
2684            async fn bind_socket_for_shard(shards_count: u16, shard: u16) -> TcpSocket {
2685                let socket = TcpSocket::new_v4().unwrap();
2686                let initial_port = draw_source_port_for_shard(shards_count, shard);
2687
2688                let mut desired_addr =
2689                    SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), initial_port);
2690                while socket.bind(desired_addr).is_err() {
2691                    // in search for a port that translates to the desired shard
2692                    let next_port = desired_addr.port().wrapping_add(shards_count);
2693                    if next_port == initial_port {
2694                        panic!("No more ports left");
2695                    }
2696                    desired_addr.set_port(next_port);
2697                }
2698
2699                socket
2700            }
2701
2702            let body_ref = &body;
2703            let send_frame_to_shard = |driver_shard: u16| async move {
2704                let socket = bind_socket_for_shard(shards_count, driver_shard).await;
2705                let mut conn = socket.connect(node_proxy_addr).await.unwrap();
2706
2707                write_frame(
2708                    params,
2709                    request_opcode,
2710                    body_ref,
2711                    &mut conn,
2712                    &no_compression(),
2713                )
2714                .await
2715                .unwrap();
2716                conn
2717            };
2718
2719            let mock_driver1_action = send_frame_to_shard(driver1_shard);
2720            let mock_driver2_action = send_frame_to_shard(driver2_shard);
2721
2722            // Accepts two connections and sends a response to each of them.
2723            let mock_node_action = async {
2724                let mut conns_futs = (0..2)
2725                    .map(|_| async {
2726                        let (mut conn, driver_addr) = mock_node_listener.accept().await.unwrap();
2727                        respond_with_shard_num(
2728                            &mut conn,
2729                            driver_addr.port() % shards_count,
2730                            &no_compression(),
2731                        )
2732                        .await;
2733                        write_frame(
2734                            params.for_response(),
2735                            response_opcode,
2736                            body_ref,
2737                            &mut conn,
2738                            &no_compression(),
2739                        )
2740                        .await
2741                        .unwrap();
2742                        conn
2743                    })
2744                    .collect::<Vec<_>>();
2745                let conn2 = conns_futs.pop().unwrap().await;
2746                let conn1 = conns_futs.pop().unwrap().await;
2747                (conn1, conn2)
2748            };
2749
2750            // we keep the connections open until proxy finishes to let it perform clean exit with no disconnects
2751            let (_node_conns, _driver1_conn, _driver2_conn) =
2752                join3(mock_node_action, mock_driver1_action, mock_driver2_action).await;
2753
2754            let assert_feedback_request = |feedback_request: RequestFrame| {
2755                assert_eq!(feedback_request.params, params);
2756                assert_eq!(
2757                    FrameOpcode::Request(feedback_request.opcode),
2758                    request_opcode
2759                );
2760                assert_eq!(feedback_request.body, body);
2761            };
2762
2763            let assert_feedback_response = |feedback_response: ResponseFrame| {
2764                assert_eq!(feedback_response.params, params.for_response());
2765                assert_eq!(
2766                    FrameOpcode::Response(feedback_response.opcode),
2767                    response_opcode
2768                );
2769                assert_eq!(feedback_response.body, body);
2770            };
2771
2772            let (feedback_request, shard1) = request_feedback_rx.recv().await.unwrap();
2773            assert_feedback_request(feedback_request);
2774            let (feedback_request, shard2) = request_feedback_rx.recv().await.unwrap();
2775            assert_feedback_request(feedback_request);
2776            let (feedback_response, shard3) = response_feedback_rx.recv().await.unwrap();
2777            assert_feedback_response(feedback_response);
2778            let (feedback_response, shard4) = response_feedback_rx.recv().await.unwrap();
2779            assert_feedback_response(feedback_response);
2780
2781            // expected: {driver1_shard request, driver1_shard response, driver2_shard request, driver2_shard response}
2782            let mut expected_shards = [driver1_shard, driver1_shard, driver2_shard, driver2_shard];
2783            expected_shards.sort_unstable();
2784
2785            let mut got_shards = [
2786                shard1.unwrap(),
2787                shard2.unwrap(),
2788                shard3.unwrap(),
2789                shard4.unwrap(),
2790            ];
2791            got_shards.sort_unstable();
2792
2793            assert_eq!(expected_shards, got_shards);
2794
2795            running_proxy.finish().await.unwrap();
2796        }
2797    }
2798
2799    #[tokio::test]
2800    async fn proxy_ignores_control_connection_messages() {
2801        setup_tracing();
2802        let node1_real_addr = next_local_address_with_port(9876);
2803        let node1_proxy_addr = next_local_address_with_port(9876);
2804
2805        let (request_feedback_tx, mut request_feedback_rx) = mpsc::unbounded_channel();
2806        let (response_feedback_tx, mut response_feedback_rx) = mpsc::unbounded_channel();
2807        let proxy = Proxy::new([Node::new(
2808            node1_real_addr,
2809            node1_proxy_addr,
2810            ShardAwareness::Unaware,
2811            Some(vec![RequestRule(
2812                Condition::not(Condition::ConnectionRegisteredAnyEvent),
2813                RequestReaction::noop().with_feedback_when_performed(request_feedback_tx),
2814            )]),
2815            Some(vec![ResponseRule(
2816                Condition::not(Condition::ConnectionRegisteredAnyEvent),
2817                ResponseReaction::noop().with_feedback_when_performed(response_feedback_tx),
2818            )]),
2819        )]);
2820        let running_proxy = proxy.run().await.unwrap();
2821
2822        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2823
2824        let (mut client_socket, mut server_socket) = join(
2825            async { TcpStream::connect(node1_proxy_addr).await.unwrap() },
2826            async { mock_node_listener.accept().await.unwrap().0 },
2827        )
2828        .await;
2829
2830        async fn perform_reqest_response<'a>(
2831            req_opcode: RequestOpcode,
2832            resp_opcode: ResponseOpcode,
2833            client_socket_ref: &'a mut TcpStream,
2834            server_socket_ref: &'a mut TcpStream,
2835            body_base: &'a str,
2836        ) {
2837            let params = FrameParams {
2838                flags: 0,
2839                version: 0x04,
2840                stream: 0,
2841            };
2842
2843            write_frame(
2844                params,
2845                FrameOpcode::Request(req_opcode),
2846                (body_base.to_string() + "|request|").as_bytes(),
2847                client_socket_ref,
2848                &no_compression(),
2849            )
2850            .await
2851            .unwrap();
2852
2853            let received_request =
2854                read_frame(server_socket_ref, FrameType::Request, &no_compression())
2855                    .await
2856                    .unwrap();
2857            assert_eq!(received_request.1, FrameOpcode::Request(req_opcode));
2858
2859            write_frame(
2860                params.for_response(),
2861                FrameOpcode::Response(resp_opcode),
2862                (body_base.to_string() + "|response|").as_bytes(),
2863                server_socket_ref,
2864                &no_compression(),
2865            )
2866            .await
2867            .unwrap();
2868
2869            let received_response =
2870                read_frame(client_socket_ref, FrameType::Response, &no_compression())
2871                    .await
2872                    .unwrap();
2873            assert_eq!(received_response.1, FrameOpcode::Response(resp_opcode));
2874        }
2875
2876        // Messages before REGISTER should be fed back to channels
2877        for i in 0..5 {
2878            perform_reqest_response(
2879                RequestOpcode::Query,
2880                ResponseOpcode::Result,
2881                &mut client_socket,
2882                &mut server_socket,
2883                &format!("message_before_{i}"),
2884            )
2885            .await
2886        }
2887
2888        perform_reqest_response(
2889            RequestOpcode::Register,
2890            ResponseOpcode::Result,
2891            &mut client_socket,
2892            &mut server_socket,
2893            "message_register",
2894        )
2895        .await;
2896
2897        // Messages after REGISTER should be passed through without feedback
2898        for i in 0..5 {
2899            perform_reqest_response(
2900                RequestOpcode::Query,
2901                ResponseOpcode::Result,
2902                &mut client_socket,
2903                &mut server_socket,
2904                &format!("message_after_{i}"),
2905            )
2906            .await
2907        }
2908
2909        running_proxy.finish().await.unwrap();
2910
2911        for _ in 0..5 {
2912            let (feedback_request, _shard) = request_feedback_rx.recv().await.unwrap();
2913            assert_eq!(feedback_request.opcode, RequestOpcode::Query);
2914            let (feedback_response, _shard) = response_feedback_rx.recv().await.unwrap();
2915            assert_eq!(feedback_response.opcode, ResponseOpcode::Result);
2916        }
2917
2918        // Response to REGISTER and further requests / responses should be ignored
2919        let _ = request_feedback_rx.try_recv().unwrap_err();
2920        let _ = response_feedback_rx.try_recv().unwrap_err();
2921    }
2922
2923    #[tokio::test]
2924    async fn proxy_compresses_and_decompresses_frames_iff_compression_negotiated() {
2925        setup_tracing();
2926        let node1_real_addr = next_local_address_with_port(9876);
2927        let node1_proxy_addr = next_local_address_with_port(9876);
2928
2929        let (request_feedback_tx, mut request_feedback_rx) = mpsc::unbounded_channel();
2930        let (response_feedback_tx, mut response_feedback_rx) = mpsc::unbounded_channel();
2931        let proxy = Proxy::builder()
2932            .with_node(
2933                Node::builder()
2934                    .real_address(node1_real_addr)
2935                    .proxy_address(node1_proxy_addr)
2936                    .shard_awareness(ShardAwareness::Unaware)
2937                    .request_rules(vec![RequestRule(
2938                        Condition::True,
2939                        RequestReaction::noop().with_feedback_when_performed(request_feedback_tx),
2940                    )])
2941                    .response_rules(vec![ResponseRule(
2942                        Condition::True,
2943                        ResponseReaction::noop().with_feedback_when_performed(response_feedback_tx),
2944                    )])
2945                    .build(),
2946            )
2947            .build();
2948        let running_proxy = proxy.run().await.unwrap();
2949
2950        let mock_node_listener = TcpListener::bind(node1_real_addr).await.unwrap();
2951
2952        const PARAMS_REQUEST_NO_COMPRESSION: FrameParams = FrameParams {
2953            flags: 0,
2954            version: 0x04,
2955            stream: 0,
2956        };
2957        const PARAMS_REQUEST_COMPRESSION: FrameParams = FrameParams {
2958            flags: flag::COMPRESSION,
2959            ..PARAMS_REQUEST_NO_COMPRESSION
2960        };
2961        const PARAMS_RESPONSE_NO_COMPRESSION: FrameParams =
2962            PARAMS_REQUEST_NO_COMPRESSION.for_response();
2963        const PARAMS_RESPONSE_COMPRESSION: FrameParams =
2964            PARAMS_REQUEST_NO_COMPRESSION.for_response();
2965
2966        let make_driver_conn = async { TcpStream::connect(node1_proxy_addr).await.unwrap() };
2967        let make_node_conn = async { mock_node_listener.accept().await.unwrap() };
2968
2969        let (mut driver_conn, (mut node_conn, _)) = join(make_driver_conn, make_node_conn).await;
2970
2971        /* Outline of the test:
2972         * 1. "driver" sends an uncompressed, e.g., QUERY frame, feedback returns its uncompressed body,
2973         *    and "node" receives the uncompressed frame.
2974         * 2. "node" responds with an uncompressed RESULT frame, feedback returns its uncompressed body,
2975         *    and "driver" receives the uncompressed frame.
2976         * 3. "driver" sends an uncompressed STARTUP frame, feedback returns its uncompressed body,
2977         *    and "node" receives the uncompressed frame. This step also triggers `CompressionWriter::set()`
2978         *    in the proxy, so the associated `CompressionReader`s are notified about it (and can use
2979         *    the negotiated compression algorithm to (de)compress the frames sent in steps 4. and 5.).
2980         * 4. "driver" sends a compressed, e.g., QUERY frame, feedback returns its uncompressed body,
2981         *    and "node" receives the compressed frame.
2982         * 5. "node" responds with a compressed RESULT frame, feedback returns its uncompressed body,
2983         *    and "driver" receives the compressed frame.
2984         */
2985
2986        // 1. "driver" sends an uncompressed, e.g., QUERY frame, feedback returns its uncompressed body,
2987        //    and "node" receives the uncompressed frame.
2988        {
2989            let sent_frame = RequestFrame {
2990                params: PARAMS_REQUEST_NO_COMPRESSION,
2991                opcode: RequestOpcode::Query,
2992                body: random_body(),
2993            };
2994
2995            sent_frame
2996                .write(&mut driver_conn, &no_compression())
2997                .await
2998                .unwrap();
2999
3000            let (captured_frame, _) = request_feedback_rx.recv().await.unwrap();
3001            assert_eq!(captured_frame, sent_frame);
3002
3003            let received_frame = read_request_frame(&mut node_conn, &no_compression())
3004                .await
3005                .unwrap();
3006            assert_eq!(received_frame, sent_frame);
3007        }
3008
3009        // 2. "node" responds with an uncompressed RESULT frame, feedback returns its uncompressed body,
3010        //    and "driver" receives the uncompressed frame.
3011        {
3012            let sent_frame = ResponseFrame {
3013                params: PARAMS_RESPONSE_NO_COMPRESSION,
3014                opcode: ResponseOpcode::Result,
3015                body: random_body(),
3016            };
3017
3018            sent_frame
3019                .write(&mut node_conn, &no_compression())
3020                .await
3021                .unwrap();
3022
3023            let (captured_frame, _) = response_feedback_rx.recv().await.unwrap();
3024            assert_eq!(captured_frame, sent_frame);
3025
3026            let received_frame = read_response_frame(&mut driver_conn, &no_compression())
3027                .await
3028                .unwrap();
3029            assert_eq!(received_frame, sent_frame);
3030        }
3031
3032        // 3. "driver" sends an uncompressed STARTUP frame, feedback returns its uncompressed body,
3033        //    and "node" receives the uncompressed frame. This step also triggers `CompressionWriter::set()`
3034        //    in the proxy, so the associated `CompressionReader`s are notified about it (and can use
3035        //    the negotiated compression algorithm to (de)compress the frames sent in steps 4. and 5.).
3036        {
3037            let startup_body = Startup {
3038                options: std::iter::once((
3039                    options::COMPRESSION.into(),
3040                    Compression::Lz4.as_str().into(),
3041                ))
3042                .collect(),
3043            }
3044            .to_bytes()
3045            .unwrap();
3046
3047            let sent_frame = RequestFrame {
3048                params: PARAMS_REQUEST_NO_COMPRESSION,
3049                opcode: RequestOpcode::Startup,
3050                body: startup_body,
3051            };
3052
3053            sent_frame
3054                .write(&mut driver_conn, &no_compression())
3055                .await
3056                .unwrap();
3057
3058            let (captured_frame, _) = request_feedback_rx.recv().await.unwrap();
3059            assert_eq!(captured_frame, sent_frame);
3060
3061            let received_frame = read_request_frame(&mut node_conn, &no_compression())
3062                .await
3063                .unwrap();
3064            assert_eq!(received_frame, sent_frame);
3065        }
3066
3067        // 4. "driver" sends a compressed, e.g., QUERY frame, feedback returns its uncompressed body,
3068        //    and "node" receives the compressed frame.
3069        {
3070            let sent_frame = RequestFrame {
3071                params: PARAMS_REQUEST_COMPRESSION,
3072                opcode: RequestOpcode::Query,
3073                body: random_body(),
3074            };
3075
3076            sent_frame
3077                .write(&mut driver_conn, &with_compression(Compression::Lz4))
3078                .await
3079                .unwrap();
3080
3081            let (captured_frame, _) = request_feedback_rx.recv().await.unwrap();
3082            assert_eq!(captured_frame, sent_frame);
3083
3084            let received_frame =
3085                read_request_frame(&mut node_conn, &with_compression(Compression::Lz4))
3086                    .await
3087                    .unwrap();
3088            assert_eq!(received_frame, sent_frame);
3089        }
3090
3091        // 5. "node" responds with a compressed RESULT frame, feedback returns its uncompressed body,
3092        //    and "driver" receives the compressed frame.
3093        {
3094            let sent_frame = ResponseFrame {
3095                params: PARAMS_RESPONSE_COMPRESSION,
3096                opcode: ResponseOpcode::Result,
3097                body: random_body(),
3098            };
3099
3100            sent_frame
3101                .write(&mut node_conn, &with_compression(Compression::Lz4))
3102                .await
3103                .unwrap();
3104
3105            let (captured_frame, _) = response_feedback_rx.recv().await.unwrap();
3106            assert_eq!(captured_frame, sent_frame);
3107
3108            let received_frame =
3109                read_response_frame(&mut driver_conn, &with_compression(Compression::Lz4))
3110                    .await
3111                    .unwrap();
3112            assert_eq!(received_frame, sent_frame);
3113        }
3114
3115        running_proxy.finish().await.unwrap();
3116    }
3117
3118    /// Helper: send a REGISTER frame from the driver side and wait until
3119    /// the mock node receives it. This is enough for the proxy's
3120    /// request_processor to register the cc_event_sender for that
3121    /// connection — no response is needed.
3122    async fn send_register(driver_conn: &mut TcpStream, node_conn: &mut TcpStream) {
3123        let params = FrameParams {
3124            flags: 0,
3125            version: 0x04,
3126            stream: 0,
3127        };
3128        write_frame(
3129            params,
3130            FrameOpcode::Request(RequestOpcode::Register),
3131            b"",
3132            driver_conn,
3133            &no_compression(),
3134        )
3135        .await
3136        .unwrap();
3137
3138        // Wait until the mock node receives the REGISTER so we know the
3139        // proxy has already processed it and registered the sender.
3140        let _req = read_request_frame(node_conn, &no_compression())
3141            .await
3142            .unwrap();
3143    }
3144
3145    #[tokio::test]
3146    async fn inject_event_to_cc_returns_false_when_no_control_connections() {
3147        setup_tracing();
3148        let node_real_addr = next_local_address_with_port(9876);
3149        let node_proxy_addr = next_local_address_with_port(9876);
3150        let proxy = Proxy::new([Node::new(
3151            node_real_addr,
3152            node_proxy_addr,
3153            ShardAwareness::Unaware,
3154            None,
3155            None,
3156        )]);
3157        let running_proxy = proxy.run().await.unwrap();
3158        let _mock_node_listener = TcpListener::bind(node_real_addr).await.unwrap();
3159
3160        // No connections at all — inject should return false.
3161        assert!(
3162            !running_proxy.running_nodes[0].inject_event_to_cc(Bytes::from_static(b"test")),
3163            "inject_event_to_cc should return false with no control connections"
3164        );
3165
3166        // finish() may report errors because no real node accepted connections.
3167        let _ = running_proxy.finish().await;
3168    }
3169
3170    #[tokio::test]
3171    async fn inject_event_to_cc_returns_false_when_connection_did_not_register() {
3172        setup_tracing();
3173        let node_real_addr = next_local_address_with_port(9876);
3174        let node_proxy_addr = next_local_address_with_port(9876);
3175        let proxy = Proxy::new([Node::new(
3176            node_real_addr,
3177            node_proxy_addr,
3178            ShardAwareness::Unaware,
3179            None,
3180            None,
3181        )]);
3182        let running_proxy = proxy.run().await.unwrap();
3183        let mock_node_listener = TcpListener::bind(node_real_addr).await.unwrap();
3184
3185        // Connect but do NOT send REGISTER.
3186        let _driver_conn = TcpStream::connect(node_proxy_addr).await.unwrap();
3187        let (_node_conn, _) = mock_node_listener.accept().await.unwrap();
3188
3189        // Connection exists but hasn't sent REGISTER — inject should return false.
3190        assert!(
3191            !running_proxy.running_nodes[0].inject_event_to_cc(Bytes::from_static(b"test")),
3192            "inject_event_to_cc should return false when no REGISTER was sent"
3193        );
3194
3195        running_proxy.finish().await.unwrap();
3196    }
3197
3198    #[tokio::test]
3199    async fn inject_event_to_cc_delivers_event_after_register() {
3200        setup_tracing();
3201        let node_real_addr = next_local_address_with_port(9876);
3202        let node_proxy_addr = next_local_address_with_port(9876);
3203        let proxy = Proxy::new([Node::new(
3204            node_real_addr,
3205            node_proxy_addr,
3206            ShardAwareness::Unaware,
3207            None,
3208            None,
3209        )]);
3210        let running_proxy = proxy.run().await.unwrap();
3211        let mock_node_listener = TcpListener::bind(node_real_addr).await.unwrap();
3212
3213        let (mut driver_conn, mut node_conn) = join(
3214            async { TcpStream::connect(node_proxy_addr).await.unwrap() },
3215            async { mock_node_listener.accept().await.unwrap().0 },
3216        )
3217        .await;
3218
3219        // Complete the REGISTER handshake so the proxy registers the cc sender.
3220        send_register(&mut driver_conn, &mut node_conn).await;
3221
3222        // Inject an event.
3223        let event_body = Bytes::from_static(b"injected_event_payload");
3224        assert!(
3225            running_proxy.running_nodes[0].inject_event_to_cc(event_body.clone()),
3226            "inject_event_to_cc should return true after REGISTER"
3227        );
3228
3229        // Read the injected frame on the driver side.
3230        let frame = tokio::time::timeout(
3231            Duration::from_millis(100),
3232            read_response_frame(&mut driver_conn, &no_compression()),
3233        )
3234        .await
3235        .expect("timed out waiting for injected event")
3236        .expect("failed to read injected event frame");
3237
3238        assert_eq!(frame.opcode, ResponseOpcode::Event);
3239        assert_eq!(frame.body, event_body);
3240        assert_eq!(frame.params.stream, -1);
3241
3242        running_proxy.finish().await.unwrap();
3243    }
3244
3245    #[tokio::test]
3246    async fn inject_event_to_cc_prunes_closed_connections() {
3247        setup_tracing();
3248        let node_real_addr = next_local_address_with_port(9876);
3249        let node_proxy_addr = next_local_address_with_port(9876);
3250        let proxy = Proxy::new([Node::new(
3251            node_real_addr,
3252            node_proxy_addr,
3253            ShardAwareness::Unaware,
3254            None,
3255            None,
3256        )]);
3257        let running_proxy = proxy.run().await.unwrap();
3258        let mock_node_listener = TcpListener::bind(node_real_addr).await.unwrap();
3259
3260        // Establish first control connection.
3261        let (mut driver_conn1, mut node_conn1) = join(
3262            async { TcpStream::connect(node_proxy_addr).await.unwrap() },
3263            async { mock_node_listener.accept().await.unwrap().0 },
3264        )
3265        .await;
3266        send_register(&mut driver_conn1, &mut node_conn1).await;
3267
3268        // Establish second control connection.
3269        let (mut driver_conn2, mut node_conn2) = join(
3270            async { TcpStream::connect(node_proxy_addr).await.unwrap() },
3271            async { mock_node_listener.accept().await.unwrap().0 },
3272        )
3273        .await;
3274        send_register(&mut driver_conn2, &mut node_conn2).await;
3275
3276        // Both connections registered — inject should succeed.
3277        assert!(running_proxy.running_nodes[0].inject_event_to_cc(Bytes::from_static(b"ev1")));
3278
3279        // Read event from both.
3280        let f1 = read_response_frame(&mut driver_conn1, &no_compression())
3281            .await
3282            .unwrap();
3283        let f2 = read_response_frame(&mut driver_conn2, &no_compression())
3284            .await
3285            .unwrap();
3286        assert_eq!(f1.body, Bytes::from_static(b"ev1"));
3287        assert_eq!(f2.body, Bytes::from_static(b"ev1"));
3288
3289        // Close connection 1 (both sides).
3290        drop(driver_conn1);
3291        drop(node_conn1);
3292
3293        // Give the proxy a moment to detect the closed connection and clean up
3294        // its cc_event_sender entry.
3295        tokio::time::sleep(Duration::from_millis(100)).await;
3296
3297        // Inject again — should still succeed via connection 2, and prune
3298        // the dead sender for connection 1.
3299        assert!(running_proxy.running_nodes[0].inject_event_to_cc(Bytes::from_static(b"ev2")));
3300
3301        let f2 = read_response_frame(&mut driver_conn2, &no_compression())
3302            .await
3303            .unwrap();
3304        assert_eq!(f2.body, Bytes::from_static(b"ev2"));
3305
3306        // Close connection 2 as well.
3307        drop(driver_conn2);
3308        drop(node_conn2);
3309
3310        tokio::time::sleep(Duration::from_millis(100)).await;
3311
3312        // Now all control connections are gone — inject should return false.
3313        assert!(
3314            !running_proxy.running_nodes[0].inject_event_to_cc(Bytes::from_static(b"ev3")),
3315            "inject_event_to_cc should return false after all control connections closed"
3316        );
3317
3318        // finish() may report DriverDisconnected errors from the intentionally
3319        // dropped connections — that's expected.
3320        let _ = running_proxy.finish().await;
3321    }
3322}