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
24type FinishWaiter = mpsc::Receiver<()>;
26type FinishGuard = mpsc::Sender<()>;
27
28type TerminateNotifier = tokio::sync::broadcast::Receiver<()>;
30type TerminateSignaler = tokio::sync::broadcast::Sender<()>;
31
32type ConnectionCloseNotifier = tokio::sync::broadcast::Receiver<()>;
35type ConnectionCloseSignaler = tokio::sync::broadcast::Sender<()>;
36
37type 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#[derive(Clone, Copy, Debug)]
50pub enum ShardAwareness {
51 Unaware,
53 QueryNode,
59 FixedNum(u16),
61}
62
63impl ShardAwareness {
64 pub fn is_aware(&self) -> bool {
65 !matches!(self, Self::Unaware)
66 }
67}
68
69enum 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 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 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 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 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 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 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?; }
384
385 Ok(RunningProxy {
386 terminate_signaler,
387 finish_waiter,
388 running_nodes,
389 error_sink,
390 })
391 }
392}
393
394pub struct RunningNode {
396 request_rules: Arc<Mutex<Vec<RequestRule>>>,
397 response_rules: Option<Arc<Mutex<Vec<ResponseRule>>>>,
398
399 cc_event_sender: Arc<Mutex<HashMap<usize, mpsc::UnboundedSender<ResponseFrame>>>>,
409}
410
411impl RunningNode {
412 pub fn change_request_rules(&mut self, rules: Option<Vec<RequestRule>>) {
414 *self.request_rules.lock().unwrap() = rules.unwrap_or_default();
415 }
416
417 pub fn append_request_rules(&mut self, mut rules: Vec<RequestRule>) {
419 self.request_rules.lock().unwrap().append(&mut rules);
420 }
421
422 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 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 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 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 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 ok
494 });
495 any_sent
496 }
497}
498
499pub 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 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 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 Err(ProxyError::SanityCheckFailure)
531 }
532 }
533 }
534
535 pub async fn wait_for_error(&mut self) -> Option<ProxyError> {
537 self.error_sink.recv().await
538 }
539
540 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 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 unreachable!("Worker await logic bug!");
564 }
565 }
566 }
567}
568
569struct 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, 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 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 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 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 #[error("Snap compression error: {0}")]
1035 SnapCompressError(Arc<dyn Error + Sync + Send>),
1036
1037 #[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 #[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 #[derive(Debug, Clone)]
1082 pub(crate) struct CompressionReader(CompressionInfo);
1083 impl CompressionReader {
1084 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 pub(crate) fn no_compression() -> CompressionReader {
1153 mock_compression_reader(None)
1154 }
1155
1156 #[cfg(test)] 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 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 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 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; }
1500 }
1501 let _ = cluster_tx.send(request); }
1503 None => {
1504 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 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); }
1624 None => return Ok(()),
1625 }
1626 }
1627 })
1628 .await
1629 }
1630}
1631
1632pub 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 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 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()); 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 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 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, 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 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 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 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 Condition::not(Condition::TrueForLimitedTimes(
2210 FAILING_TRIES + PASSING_TRIES,
2211 )),
2212 RequestReaction::drop_frame(),
2213 ),
2214 RequestRule(
2215 Condition::not(Condition::TrueForLimitedTimes(FAILING_TRIES)),
2217 RequestReaction::noop(),
2218 ),
2219 RequestRule(
2220 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 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 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 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 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 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, 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 #[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 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 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 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 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 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 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 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 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 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 {
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 {
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 {
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 {
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 {
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 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 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 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 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 let _driver_conn = TcpStream::connect(node_proxy_addr).await.unwrap();
3187 let (_node_conn, _) = mock_node_listener.accept().await.unwrap();
3188
3189 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 send_register(&mut driver_conn, &mut node_conn).await;
3221
3222 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 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 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 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 assert!(running_proxy.running_nodes[0].inject_event_to_cc(Bytes::from_static(b"ev1")));
3278
3279 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 drop(driver_conn1);
3291 drop(node_conn1);
3292
3293 tokio::time::sleep(Duration::from_millis(100)).await;
3296
3297 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 drop(driver_conn2);
3308 drop(node_conn2);
3309
3310 tokio::time::sleep(Duration::from_millis(100)).await;
3311
3312 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 let _ = running_proxy.finish().await;
3321 }
3322}