sqlx_core_oldapi/mssql/protocol/packet.rs
1use bitflags::bitflags;
2use bytes::{Buf, Bytes};
3
4use crate::error::Error;
5use crate::io::{Decode, Encode};
6
7pub(crate) const PACKET_HEADER_SIZE: usize = 8;
8
9#[derive(Debug)]
10pub(crate) struct PacketHeader {
11 // Type defines the type of message. Type is a 1-byte unsigned char.
12 pub(crate) r#type: PacketType,
13
14 // Status is a bit field used to indicate the message state. Status is a 1-byte unsigned char.
15 pub(crate) status: Status,
16
17 // Length is the size of the packet including the 8 bytes in the packet header.
18 pub(crate) length: u16,
19
20 // The process ID on the server, corresponding to the current connection.
21 pub(crate) server_process_id: u16,
22
23 // Packet ID is used for numbering message packets that contain data in addition to the packet
24 // header. Packet ID is a 1-byte, unsigned char. Each time packet data is sent, the value of
25 // PacketID is incremented by 1, modulo 256. This allows the receiver to track the sequence
26 // of TDS packets for a given message. This value is currently ignored.
27 pub(crate) packet_id: u8,
28}
29
30impl PacketHeader {
31 fn to_array(&self) -> [u8; PACKET_HEADER_SIZE] {
32 let mut arr = [0u8; PACKET_HEADER_SIZE];
33 arr[0] = self.r#type as u8;
34 arr[1] = self.status.bits();
35 arr[2..4].copy_from_slice(&self.length.to_be_bytes());
36 arr[4..6].copy_from_slice(&self.server_process_id.to_be_bytes());
37 arr[6] = self.packet_id;
38 arr
39 }
40}
41
42impl<'s> Encode<'s, ()> for PacketHeader {
43 fn encode_with(&self, buf: &mut Vec<u8>, _: ()) {
44 buf.extend_from_slice(&self.to_array());
45 }
46}
47
48impl Decode<'_> for PacketHeader {
49 fn decode_with(mut buf: Bytes, _: ()) -> Result<Self, Error> {
50 Ok(Self {
51 r#type: PacketType::get(buf.get_u8())?,
52 status: Status::from_bits_truncate(buf.get_u8()),
53 length: buf.get_u16(),
54 server_process_id: buf.get_u16(),
55 packet_id: buf.get_u8(),
56 })
57 }
58}
59
60#[derive(Debug, Copy, PartialEq, Clone)]
61pub(crate) enum PacketType {
62 // Pre-login. Should always be #18 unless we decide to try and support pre 7.0 TDS
63 PreTds7Login = 2,
64 PreLogin = 18,
65
66 SqlBatch = 1,
67 Rpc = 3,
68 AttentionSignal = 6,
69 BulkLoadData = 7,
70 FederatedAuthToken = 8,
71 TransactionManagerRequest = 14,
72 Tds7Login = 16,
73 Sspi = 17,
74
75 TabularResult = 4,
76}
77
78impl PacketType {
79 pub fn get(value: u8) -> Result<Self, Error> {
80 Ok(match value {
81 1 => PacketType::SqlBatch,
82 2 => PacketType::PreTds7Login,
83 3 => PacketType::Rpc,
84 4 => PacketType::TabularResult,
85 6 => PacketType::AttentionSignal,
86 7 => PacketType::BulkLoadData,
87 8 => PacketType::FederatedAuthToken,
88 14 => PacketType::TransactionManagerRequest,
89 16 => PacketType::Tds7Login,
90 17 => PacketType::Sspi,
91 18 => PacketType::PreLogin,
92
93 ty => {
94 return Err(err_protocol!("unknown packet type: {}", ty));
95 }
96 })
97 }
98}
99
100// Status is a bit field used to indicate the message state. Status is a 1-byte unsigned char.
101// The following Status bit flags are defined.
102bitflags! {
103 #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
104 pub(crate) struct Status: u8 {
105 // "Normal" message.
106 const NORMAL = 0x00;
107
108 // End of message (EOM). The packet is the last packet in the whole request.
109 const END_OF_MESSAGE = 0x01;
110
111 // (From client to server) Ignore this event (0x01 MUST also be set).
112 const IGNORE_EVENT = 0x02;
113
114 // RESETCONNECTION
115 //
116 // (Introduced in TDS 7.1)
117 //
118 // (From client to server) Reset this connection
119 // before processing event. Only set for event types Batch, RPC, or Transaction Manager
120 // request. If clients want to set this bit, it MUST be part of the first packet of the
121 // message. This signals the server to clean up the environment state of the connection
122 // back to the default environment setting, effectively simulating a logout and a
123 // subsequent login, and provides server support for connection pooling. This bit SHOULD
124 // be ignored if it is set in a packet that is not the first packet of the message.
125 //
126 // This status bit MUST NOT be set in conjunction with the RESETCONNECTIONSKIPTRAN bit.
127 // Distributed transactions and isolation levels will not be reset.
128 const RESET_CONN = 0x08;
129
130 // RESETCONNECTIONSKIPTRAN
131 //
132 // (Introduced in TDS 7.3)
133 //
134 // (From client to server) Reset the
135 // connection before processing event but do not modify the transaction state (the
136 // state will remain the same before and after the reset). The transaction in the
137 // session can be a local transaction that is started from the session or it can
138 // be a distributed transaction in which the session is enlisted. This status bit
139 // MUST NOT be set in conjunction with the RESETCONNECTION bit.
140 // Otherwise identical to RESETCONNECTION.
141 const RESET_CONN_SKIP_TRAN = 0x10;
142 }
143}