modbus_core/codec/tcp/
server.rs

1//! Modbus TCP server (slave) specific functions.
2use super::*;
3
4/// Decode an TCP request.
5pub fn decode_request(buf: &[u8]) -> Result<Option<RequestAdu>> {
6    if buf.is_empty() {
7        return Ok(None);
8    }
9    let frame = decode(DecoderType::Request, buf)?;
10    let Some((decoded_frame, _frame_pos)) = frame else {
11        return Ok(None);
12    };
13    let DecodedFrame {
14        transaction_id,
15        unit_id,
16        pdu,
17    } = decoded_frame;
18    let hdr = Header {
19        transaction_id,
20        unit_id,
21    };
22    // Decoding of the PDU should are unlikely to fail due
23    // to transmission errors, because the frame's bytes
24    // have already been verified at the TCP level.
25    Request::try_from(pdu)
26        .map(RequestPdu)
27        .map(|pdu| Some(RequestAdu { hdr, pdu }))
28        .map_err(|err| {
29            // Unrecoverable error
30            log::error!("Failed to decode request PDU: {err}");
31            err
32        })
33}
34
35// Decode a TCP response
36pub fn decode_response(buf: &[u8]) -> Result<Option<ResponseAdu>> {
37    if buf.is_empty() {
38        return Err(Error::BufferSize);
39    }
40    decode(DecoderType::Response, buf)
41        .and_then(|frame| {
42            let Some((decoded_frame, _frame_pos)) = frame else {
43                return Ok(None);
44            };
45            let DecodedFrame {
46                transaction_id,
47                unit_id,
48                pdu,
49            } = decoded_frame;
50            let hdr = Header {
51                transaction_id,
52                unit_id,
53            };
54            // Decoding of the PDU should are unlikely to fail due
55            // to transmission errors, because the frame's bytes
56            // have already been verified at the TCP level.
57
58            Response::try_from(pdu)
59                .map(Ok)
60                .or_else(|_| ExceptionResponse::try_from(pdu).map(Err))
61                .map(ResponsePdu)
62                .map(|pdu| Some(ResponseAdu { hdr, pdu }))
63                .map_err(|err| {
64                    // Unrecoverable error
65                    log::error!("Failed to decode response PDU: {err}");
66                    err
67                })
68        })
69        .map_err(|_| {
70            // Decoding the transport frame is non-destructive and must
71            // never fail!
72            unreachable!();
73        })
74}
75
76/// Encode an TCP response.
77pub fn encode_response(adu: ResponseAdu, buf: &mut [u8]) -> Result<usize> {
78    let ResponseAdu { hdr, pdu } = adu;
79    if buf.len() < 7 {
80        return Err(Error::BufferSize);
81    }
82    BigEndian::write_u16(&mut buf[0..2], hdr.transaction_id);
83    BigEndian::write_u16(&mut buf[2..4], 0); //MODBUS Protocol
84    buf[6] = hdr.unit_id;
85    let len = pdu.encode(&mut buf[7..])?;
86    if buf.len() < len + 7 {
87        return Err(Error::BufferSize);
88    }
89    BigEndian::write_u16(&mut buf[4..6], (len + 1) as u16);
90
91    Ok(len + 7)
92}
93
94pub fn encode_request(adu: RequestAdu, buf: &mut [u8]) -> Result<usize> {
95    let RequestAdu { hdr, pdu } = adu;
96    if buf.len() < 7 {
97        return Err(Error::BufferSize);
98    }
99    BigEndian::write_u16(&mut buf[0..2], hdr.transaction_id);
100    BigEndian::write_u16(&mut buf[2..4], 0); //MODBUS Protocol
101    buf[6] = hdr.unit_id;
102    let len = pdu.encode(&mut buf[7..])?;
103    if buf.len() < len + 7 {
104        return Err(Error::BufferSize);
105    }
106    BigEndian::write_u16(&mut buf[4..6], (len + 1) as u16);
107
108    Ok(len + 7)
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn decode_empty_request() {
117        let req = decode_request(&[]).unwrap();
118        assert!(req.is_none());
119    }
120
121    #[test]
122    fn decode_partly_received_request() {
123        let buf = &[
124            0x00, // garbage
125            0x01, //
126        ];
127        let req = decode_request(buf).unwrap();
128        assert!(req.is_none());
129    }
130
131    #[test]
132    fn decode_write_single_register_request() {
133        let buf = &[
134            0x00, // Transaction id
135            0x2a, // Transaction id
136            0x00, // Protocol id
137            0x00, // Protocol id
138            0x00, // length
139            0x06, // length
140            0x12, // unit id
141            0x06, // function code
142            0x22, // addr
143            0x22, // addr
144            0xAB, // value
145            0xCD, // value
146        ];
147        let adu = decode_request(buf).unwrap().unwrap();
148        let RequestAdu { hdr, pdu } = adu;
149        let RequestPdu(pdu) = pdu;
150        assert_eq!(hdr.transaction_id, 42);
151        assert_eq!(hdr.unit_id, 0x12);
152        assert_eq!(FunctionCode::from(pdu), FunctionCode::WriteSingleRegister);
153    }
154
155    #[test]
156    fn decode_wrong_protocol() {
157        let buf = &[
158            0x00, // Transaction id
159            0x2a, // Transaction id
160            0x00, // Protocol id
161            0x01, // Protocol id
162            0x00, // length
163            0x06, // length
164            0x12, // unit id
165            0x06, // function code
166            0x22, // addr
167            0x22, // addr
168            0xAB, // value
169            0xCD, // value
170        ];
171        assert!(decode_request(buf).unwrap().is_none());
172    }
173
174    #[test]
175    fn encode_write_single_register_response() {
176        let adu = ResponseAdu {
177            hdr: Header {
178                transaction_id: 42,
179                unit_id: 0x12,
180            },
181            pdu: ResponsePdu(Ok(Response::WriteSingleRegister(0x2222, 0xABCD))),
182        };
183        let buf = &mut [0; 100];
184        let len = encode_response(adu, buf).unwrap();
185        assert_eq!(len, 12);
186        assert_eq!(buf[0], 0x00);
187        assert_eq!(buf[1], 0x2a);
188        assert_eq!(buf[2], 0x00);
189        assert_eq!(buf[3], 0x00);
190        assert_eq!(buf[4], 0x00);
191        assert_eq!(buf[5], 0x06);
192        assert_eq!(buf[6], 0x12);
193        assert_eq!(buf[7], 0x06);
194        assert_eq!(buf[8], 0x22);
195        assert_eq!(buf[9], 0x22);
196        assert_eq!(buf[10], 0xAB);
197        assert_eq!(buf[11], 0xCD);
198    }
199
200    #[test]
201    fn response_buffer_too_small() {
202        let adu = ResponseAdu {
203            hdr: Header {
204                transaction_id: 42,
205                unit_id: 0x12,
206            },
207            pdu: ResponsePdu(Ok(Response::WriteSingleRegister(0x2222, 0xABCD))),
208        };
209        let buf = &mut [0; 11];
210        let res = encode_response(adu, buf).err().unwrap();
211        assert_eq!(res, Error::BufferSize);
212    }
213
214    #[test]
215    fn request_buffer_too_small() {
216        let adu = RequestAdu {
217            hdr: Header {
218                transaction_id: 42,
219                unit_id: 0x12,
220            },
221            pdu: RequestPdu(Request::WriteSingleRegister(0x2222, 0xABCD)),
222        };
223        let buf = &mut [0; 11];
224        let res = encode_request(adu, buf).err().unwrap();
225        assert_eq!(res, Error::BufferSize);
226    }
227}