1pub fn decode_bind_single(body: &[u8]) -> Result<(), String> {
26 const RPC_RESULT: u32 = 0xf35c6d01;
27 const BOOL_TRUE: u32 = 0x9972_75b5;
28 const BOOL_FALSE: u32 = 0xbc79_9737;
29 const RPC_ERROR: u32 = 0x2144_ca19;
30 const BAD_MSG: u32 = 0xa7ef_f811;
31 const BAD_SALT: u32 = 0xedab_447b;
32 const NEW_SESSION: u32 = 0x9ec2_0908;
33 const FUTURE_SALTS: u32 = 0xae50_0895;
34 const MSGS_ACK: u32 = 0x62d6_b459;
35 const PONG: u32 = 0x0347_73c5;
36
37 if body.len() < 4 {
38 return Err("skip".to_string());
39 }
40 let ctor = u32::from_le_bytes(body[..4].try_into().unwrap());
41
42 match ctor {
43 BOOL_TRUE => Ok(()),
44
45 BOOL_FALSE => Err("server returned boolFalse (binding rejected)".to_string()),
46
47 NEW_SESSION | FUTURE_SALTS | MSGS_ACK | PONG => Err("skip".to_string()),
48
49 RPC_RESULT if body.len() >= 16 => {
50 let inner = u32::from_le_bytes(body[12..16].try_into().unwrap());
51 match inner {
52 BOOL_TRUE => Ok(()),
53 BOOL_FALSE => Err("rpc_result{boolFalse} (server rejected binding)".to_string()),
54 RPC_ERROR if body.len() >= 20 => {
55 let code = i32::from_le_bytes(body[16..20].try_into().unwrap());
56 let msg = crate::util::tl_read_string(body.get(20..).unwrap_or(&[]))
57 .unwrap_or_default();
58 Err(format!("rpc_error code={code} message={msg:?}"))
59 }
60 _ => Err(format!("rpc_result inner ctor={inner:#010x}")),
61 }
62 }
63
64 BAD_MSG if body.len() >= 16 => {
65 let code = u32::from_le_bytes(body[12..16].try_into().unwrap());
66 let desc = match code {
67 16 => "msg_id too low (clock skew)",
68 17 => "msg_id too high (clock skew)",
69 18 => "incorrect lower 2 bits of msg_id",
70 19 => "duplicate msg_id",
71 20 => "message too old (>300s)",
72 32 => "msg_seqno too low",
73 33 => "msg_seqno too high",
74 34 => "even seqno expected, odd received",
75 35 => "odd seqno expected, even received",
76 48 => "incorrect server salt",
77 64 => "invalid container",
78 _ => "unknown code",
79 };
80 Err(format!("bad_msg_notification code={code} ({desc})"))
81 }
82
83 BAD_SALT if body.len() >= 24 => {
84 let new_salt = i64::from_le_bytes(body[16..24].try_into().unwrap());
85 Err(format!(
86 "bad_server_salt, server wants salt={new_salt:#018x}"
87 ))
88 }
89
90 _ => Err(format!("unknown ctor={ctor:#010x}")),
91 }
92}
93
94pub fn decode_bind_response(body: &[u8]) -> Result<(), String> {
100 const MSG_CONTAINER: u32 = 0x73f1f8dc;
101
102 if body.len() < 4 {
103 return Err(format!("response body too short ({} bytes)", body.len()));
104 }
105 let ctor = u32::from_le_bytes(body[..4].try_into().unwrap());
106
107 if ctor != MSG_CONTAINER {
108 return decode_bind_single(body).map_err(|e| {
109 if e == "skip" {
110 "__need_more__".to_string()
111 } else {
112 e
113 }
114 });
115 }
116
117 if body.len() < 8 {
118 return Err("msg_container too short to read count".to_string());
119 }
120 let count = u32::from_le_bytes(body[4..8].try_into().unwrap()) as usize;
121 let mut pos = 8usize;
122 let mut last_real_err: Option<String> = None;
123
124 for i in 0..count {
125 if pos + 16 > body.len() {
126 return Err(format!(
127 "msg_container truncated at message {i}/{count} (pos={pos} body_len={})",
128 body.len()
129 ));
130 }
131 let msg_bytes = u32::from_le_bytes(body[pos + 12..pos + 16].try_into().unwrap()) as usize;
132 pos += 16;
133
134 if pos + msg_bytes > body.len() {
135 return Err(format!(
136 "msg_container message {i} body overflows (need {msg_bytes}, have {})",
137 body.len() - pos
138 ));
139 }
140 let msg_body = &body[pos..pos + msg_bytes];
141 pos += msg_bytes;
142
143 match decode_bind_single(msg_body) {
144 Ok(()) => return Ok(()),
145 Err(e) if e == "skip" => continue,
146 Err(e) => {
147 last_real_err = Some(e);
148 }
149 }
150 }
151
152 Err(last_real_err.unwrap_or_else(|| "__need_more__".to_string()))
153}