doip_tokio/
lib.rs

1//!
2//! DoIP - ISO13400-2 is a protocol for diagnostic communication over IP, used in the automotive domain.
3//!
4//! DoIP only handles the transmission of diagnostic packets.
5//! The actual diagnostic messages is encoded using the UDS (Unified Diagnostic Services) protocol, specified in ISO14229.
6//!
7//! # Client example
8//!
9//! ```no_run
10//! use std::net::Ipv4Addr;
11//! use doip::{ActivationType, RoutingActivationResponseCode};
12//! use doip_tokio::{DoIpClient, DoIpTokioError};
13//! use futures::StreamExt;
14//! use openssl::{
15//!     pkey::PKey,
16//!     ssl::{SslConnector, SslMethod},
17//!     x509::X509,
18//! };
19//! use tls_api::TlsConnectorBuilder;
20//! use tls_api_openssl::TlsConnector;
21//!
22//! #[tokio::main]
23//! async fn main() -> anyhow::Result<()> {
24//!     // Configure TLS setup
25//!     const CERT_PEM: &[u8] =  b"-----BEGIN CERTIFICATE-----...";
26//!     const CERT_PRIVATE_KEY: &[u8] = b"-----BEGIN RSA PRIVATE KEY-----...";
27//!
28//!     let x509 = X509::from_pem(CERT_PEM)?;
29//!     let pkey = PKey::private_key_from_pem(CERT_PRIVATE_KEY)?;
30//!
31//!     let mut builder = SslConnector::builder(SslMethod::tls())?;
32//!
33//!     builder.set_cipher_list(doip::TLS_V1_2_CIPHER_SUITES_OPENSSL)?;
34//!     // TLSv1.3
35//!     builder.set_ciphersuites(doip::TLS_V1_3_CIPHER_SUITES)?;
36//!     builder.set_private_key(&pkey)?;
37//!     builder.cert_store_mut().add_cert(x509)?;
38//!     let tls_connector = tls_api_openssl::TlsConnectorBuilder {
39//!         builder,
40//!         verify_hostname: false,
41//!     }
42//!     .build()?;
43//!
44//!     let addr = Ipv4Addr::new(127, 0, 0, 1);
45//!     let mut client = DoIpClient::connect(addr, 0x0E80, tls_connector, "localhost").await?;
46//!
47//!     let response = client
48//!         .routing_activation([0x00, 0x00], ActivationType::Default)
49//!         .await?;
50//!     Ok(())
51//! }
52//! ```
53//!
54
55use bytes::{Buf, BufMut, Bytes, BytesMut};
56use doip::*;
57use futures::Stream;
58use std::io::Cursor;
59use std::num::TryFromIntError;
60use std::{io, pin::Pin, task::Poll};
61use thiserror::Error;
62use tokio_util::{
63    codec::{Decoder, Encoder},
64    udp::UdpFramed,
65};
66
67mod client;
68mod server;
69
70pub use client::{DoIpClient, DoIpClientOptions};
71pub use server::{ClientContext, DoIpServer, DoIpServerHandler, ServerError};
72
73pub const UDP_DISCOVERY_PORT: u16 = 13400;
74pub const TCP_DATA_PORT: u16 = 13400;
75pub const TCP_DATA_TLS_PORT: u16 = 3496;
76
77#[derive(Error, Debug)]
78pub enum DoIpTokioError {
79    #[error(transparent)]
80    Io(#[from] io::Error),
81    #[error(transparent)]
82    TryFromInt(#[from] TryFromIntError),
83    #[error("The client logical address: {0:X} is not within the valid range 0x0E00 - 0x0FFF")]
84    InvalidClientLogicalAddr(u16),
85    #[error(transparent)]
86    Anyhow(#[from] anyhow::Error),
87    #[error(transparent)]
88    Parse(#[from] DoIpError),
89    #[error("Diagnostic message negative acknowledgement code: {0:?}")]
90    DiagnosticMessageNegativeAck(DiagnosticMessageNegativeAck),
91}
92
93/// Stream of vehicle streams / vehicle identification responses.
94pub struct VehicleIdentificationStream {
95    udp_framed: UdpFramed<DoIpCodec>,
96}
97
98impl Stream for VehicleIdentificationStream {
99    type Item = Result<VehicleIdentificationResponse, DoIpTokioError>;
100
101    fn poll_next(
102        mut self: std::pin::Pin<&mut Self>,
103        cx: &mut std::task::Context<'_>,
104    ) -> std::task::Poll<Option<Self::Item>> {
105        match Pin::new(&mut self.udp_framed).poll_next(cx) {
106            Poll::Ready(Some(Ok(((header, payload), _socket_addr)))) => {
107                if header.payload_type
108                    == PayloadType::VehicleAnnouncementMessageVehicleIdentificationResponse
109                {
110                    let announcement =
111                        VehicleIdentificationResponse::read(&mut Cursor::new(payload))
112                            .map_err(DoIpTokioError::Parse);
113                    Poll::Ready(Some(announcement))
114                } else {
115                    Poll::Pending
116                }
117            }
118            Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(err))),
119            Poll::Ready(None) => Poll::Ready(None),
120            Poll::Pending => Poll::Pending,
121        }
122    }
123}
124
125pub struct DoIpMessageStream {
126    udp_framed: UdpFramed<DoIpCodec>,
127}
128
129impl Stream for DoIpMessageStream {
130    type Item = Result<DoIpMessage, DoIpTokioError>;
131
132    fn poll_next(
133        mut self: std::pin::Pin<&mut Self>,
134        cx: &mut std::task::Context<'_>,
135    ) -> std::task::Poll<Option<Self::Item>> {
136        match Pin::new(&mut self.udp_framed).poll_next(cx) {
137            Poll::Ready(Some(Ok(((header, payload), _socket_addr)))) => {
138                Poll::Ready(Some(Ok(DoIpMessage {
139                    header,
140                    payload: payload.to_vec(),
141                })))
142            }
143            Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(err))),
144            Poll::Ready(None) => Poll::Ready(None),
145            Poll::Pending => Poll::Pending,
146        }
147    }
148}
149
150#[derive(Default)]
151pub struct DoIpCodec {}
152
153impl Decoder for DoIpCodec {
154    type Item = (DoIpHeader, Bytes);
155    type Error = DoIpTokioError;
156
157    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
158        let header = DoIpHeader::read(&mut src.reader())?;
159        let payload = src.copy_to_bytes(header.payload_length as usize);
160
161        Ok(Some((header, payload)))
162    }
163}
164
165impl Encoder<(&DoIpHeader, &[u8])> for DoIpCodec {
166    type Error = DoIpTokioError;
167
168    fn encode(
169        &mut self,
170        message: (&DoIpHeader, &[u8]),
171        dst: &mut BytesMut,
172    ) -> Result<(), Self::Error> {
173        let (header, payload) = message;
174        header.write(&mut dst.writer())?;
175        dst.put(payload);
176        Ok(())
177    }
178}