autosar_data_abstraction/communication/physical_channel/ethernet/
socketaddress.rs

1use crate::communication::{
2    AbstractPhysicalChannel, ConsumedServiceInstanceV1, EthernetPhysicalChannel, NetworkEndpoint,
3    ProvidedServiceInstanceV1, SocketConnection, SocketConnectionBundle, StaticSocketConnection, TcpRole,
4};
5use crate::{
6    AbstractionElement, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement, abstraction_element,
7    get_reference_parents,
8};
9use autosar_data::{Element, ElementName};
10
11//##################################################################
12
13/// A socket address establishes the link between one or more ECUs and a `NetworkEndpoint`.
14/// It contains all settings that are relevant for this combination.
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub struct SocketAddress(Element);
17abstraction_element!(SocketAddress, SocketAddress);
18impl IdentifiableAbstractionElement for SocketAddress {}
19
20impl SocketAddress {
21    pub(crate) fn new(
22        name: &str,
23        channel: &EthernetPhysicalChannel,
24        network_endpoint: &NetworkEndpoint,
25        tp_config: &TpConfig,
26        sa_type: SocketAddressType,
27    ) -> Result<Self, AutosarAbstractionError> {
28        let channel_elem = channel.element();
29        let (unicast, ecu_instances) = match sa_type {
30            SocketAddressType::Unicast(Some(ecu_instance)) => (true, vec![ecu_instance]),
31            SocketAddressType::Unicast(None) => (true, vec![]),
32            SocketAddressType::Multicast(ecu_instances) => (false, ecu_instances),
33        };
34
35        // TCP connections don't work using multicast IP addresses
36        if !unicast && matches!(tp_config, TpConfig::TcpTp { .. }) {
37            return Err(AutosarAbstractionError::InvalidParameter(
38                "TCP is incomptible with multicasting".to_string(),
39            ));
40        }
41        // extension: check if the address is valid for multicasting?
42        // IPv4: 224.0.0.0 - 239.255.255.255
43        // IPv6: FFxx:/12
44
45        // get the connector for each ECU in advance, so that nothing needs to be cleaned up if there is a problem here
46        let connectors = ecu_instances
47            .iter()
48            .filter_map(|ecu_instance| channel.ecu_connector(ecu_instance).map(|conn| conn.element().clone()))
49            .collect::<Vec<_>>();
50        if connectors.len() != ecu_instances.len() {
51            return Err(AutosarAbstractionError::InvalidParameter(
52                "All EcuInstances must be connected to the EthernetPhysicalChannel".to_string(),
53            ));
54        }
55
56        let elem = channel_elem
57            .get_or_create_sub_element(ElementName::SoAdConfig)?
58            .get_or_create_sub_element(ElementName::SocketAddresss)?
59            .create_named_sub_element(ElementName::SocketAddress, name)?;
60
61        if unicast {
62            if !connectors.is_empty() {
63                elem.create_sub_element(ElementName::ConnectorRef)
64                    .unwrap()
65                    .set_reference_target(&connectors[0])
66                    .unwrap();
67            }
68        } else {
69            let mc_connectors = elem.create_sub_element(ElementName::MulticastConnectorRefs)?;
70            for conn in &connectors {
71                mc_connectors
72                    .create_sub_element(ElementName::MulticastConnectorRef)?
73                    .set_reference_target(conn)?;
74            }
75        }
76
77        let ae_name = format!("{name}_AE");
78        let ae = elem.create_named_sub_element(ElementName::ApplicationEndpoint, &ae_name)?;
79        ae.create_sub_element(ElementName::NetworkEndpointRef)?
80            .set_reference_target(network_endpoint.element())?;
81        let tp_configuration = ae.create_sub_element(ElementName::TpConfiguration)?;
82        match tp_config {
83            TpConfig::TcpTp {
84                port_number,
85                port_dynamically_assigned,
86            } => {
87                let tcptp = tp_configuration.create_sub_element(ElementName::TcpTp)?;
88                let tcptp_port = tcptp.create_sub_element(ElementName::TcpTpPort)?;
89                // PortNumber and DynamicallyAssigned are mutually exclusive.
90                // The attribute DynamicallyAssigned is deprecated starting in Autosar 4.5.0
91                if let Some(portnum) = port_number {
92                    tcptp_port
93                        .create_sub_element(ElementName::PortNumber)?
94                        .set_character_data(portnum.to_string())?;
95                } else if let Some(dyn_assign) = port_dynamically_assigned {
96                    tcptp_port
97                        .create_sub_element(ElementName::DynamicallyAssigned)?
98                        .set_character_data(*dyn_assign)?;
99                }
100            }
101            TpConfig::UdpTp {
102                port_number,
103                port_dynamically_assigned,
104            } => {
105                let udptp_port = tp_configuration
106                    .create_sub_element(ElementName::UdpTp)?
107                    .create_sub_element(ElementName::UdpTpPort)?;
108                // PortNumber and DynamicallyAssigned are mutually exclusive.
109                // The attribute DynamicallyAssigned is deprecated starting in Autosar 4.5.0
110                if let Some(portnum) = port_number {
111                    udptp_port
112                        .create_sub_element(ElementName::PortNumber)?
113                        .set_character_data(portnum.to_string())?;
114                } else if let Some(dyn_assign) = port_dynamically_assigned {
115                    let boolstr = if *dyn_assign { "true" } else { "false" };
116                    udptp_port
117                        .create_sub_element(ElementName::DynamicallyAssigned)?
118                        .set_character_data(boolstr)?;
119                }
120            }
121        }
122
123        Ok(Self(elem))
124    }
125
126    /// remove this `SocketAddress` from the model
127    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
128        for static_socket_connection in self.static_socket_connections() {
129            static_socket_connection.remove(deep)?;
130        }
131
132        for provided_service_instance in self.provided_service_instances() {
133            provided_service_instance.remove(deep)?;
134        }
135
136        for consumed_service_instance in self.consumed_service_instances() {
137            consumed_service_instance.remove(deep)?;
138        }
139
140        let ref_parents = get_reference_parents(self.element())?;
141
142        AbstractionElement::remove(self, deep)?;
143
144        for (named_parent, _parent) in ref_parents {
145            match named_parent.element_name() {
146                ElementName::SocketConnectionBundle => {
147                    if let Ok(socket_connection_bundle) = SocketConnectionBundle::try_from(named_parent) {
148                        socket_connection_bundle.remove(deep)?;
149                    }
150                }
151                ElementName::SocketConnection => {
152                    if let Ok(socket_connection) = SocketConnection::try_from(named_parent) {
153                        socket_connection.remove(deep)?;
154                    }
155                }
156                _ => {}
157            }
158        }
159
160        Ok(())
161    }
162
163    /// get the network endpoint of this `SocketAddress`
164    #[must_use]
165    pub fn network_endpoint(&self) -> Option<NetworkEndpoint> {
166        let ne = self
167            .element()
168            .get_sub_element(ElementName::ApplicationEndpoint)?
169            .get_sub_element(ElementName::NetworkEndpointRef)?
170            .get_reference_target()
171            .ok()?;
172        ne.try_into().ok()
173    }
174
175    /// get the socket address type: unicast / multicast, as well as the connected ecus
176    #[must_use]
177    pub fn socket_address_type(&self) -> Option<SocketAddressType> {
178        if let Some(connector_ref) = self.0.get_sub_element(ElementName::ConnectorRef) {
179            let ecu = EcuInstance::try_from(connector_ref.get_reference_target().ok()?.named_parent().ok()??).ok()?;
180            Some(SocketAddressType::Unicast(Some(ecu)))
181        } else if let Some(mcr) = self.0.get_sub_element(ElementName::MulticastConnectorRefs) {
182            let ecus = mcr
183                .sub_elements()
184                .filter_map(|cr| {
185                    cr.get_reference_target()
186                        .ok()
187                        .and_then(|conn| conn.named_parent().ok().flatten())
188                })
189                .filter_map(|ecu_elem| EcuInstance::try_from(ecu_elem).ok())
190                .collect::<Vec<_>>();
191            Some(SocketAddressType::Multicast(ecus))
192        } else {
193            None
194        }
195    }
196
197    /// add an `EcuInstance` to this multicast `SocketAddress`
198    pub fn add_multicast_ecu(&self, ecu: &EcuInstance) -> Result<(), AutosarAbstractionError> {
199        let socket_type = self.socket_address_type();
200        match socket_type {
201            Some(SocketAddressType::Multicast(multicast_ecus)) => {
202                // extend the list of multicast EcuInstances if needed
203                if !multicast_ecus.contains(ecu) {
204                    let Some(connector) = self.physical_channel()?.ecu_connector(ecu) else {
205                        return Err(AutosarAbstractionError::InvalidParameter(
206                            "EcuInstance is not connected to the EthernetPhysicalChannel".to_string(),
207                        ));
208                    };
209                    let mcr = self.0.get_or_create_sub_element(ElementName::MulticastConnectorRefs)?;
210                    let mc_ref = mcr.create_sub_element(ElementName::MulticastConnectorRef)?;
211                    mc_ref.set_reference_target(connector.element())?;
212                }
213            }
214            None => {
215                // add the first EcuInstance to this multicast SocketAddress
216                let Some(connector) = self.physical_channel()?.ecu_connector(ecu) else {
217                    return Err(AutosarAbstractionError::InvalidParameter(
218                        "EcuInstance is not connected to the EthernetPhysicalChannel".to_string(),
219                    ));
220                };
221                let mcr = self.0.get_or_create_sub_element(ElementName::MulticastConnectorRefs)?;
222                let mc_ref = mcr.create_sub_element(ElementName::MulticastConnectorRef)?;
223                mc_ref.set_reference_target(connector.element())?;
224            }
225            Some(SocketAddressType::Unicast(_)) => {
226                return Err(AutosarAbstractionError::InvalidParameter(
227                    "This SocketAddress is not a multicast socket".to_string(),
228                ));
229            }
230        }
231
232        Ok(())
233    }
234
235    /// set the `EcuInstance` for this unicast `SocketAddress`
236    pub fn set_unicast_ecu(&self, ecu: &EcuInstance) -> Result<(), AutosarAbstractionError> {
237        let socket_type = self.socket_address_type();
238        match socket_type {
239            None | Some(SocketAddressType::Unicast(_)) => {
240                let channel = self.physical_channel()?;
241                let Some(connector) = channel.ecu_connector(ecu) else {
242                    return Err(AutosarAbstractionError::InvalidParameter(
243                        "EcuInstance is not connected to the EthernetPhysicalChannel".to_string(),
244                    ));
245                };
246                self.0
247                    .get_or_create_sub_element(ElementName::ConnectorRef)?
248                    .set_reference_target(connector.element())?;
249            }
250            Some(SocketAddressType::Multicast(_)) => {
251                return Err(AutosarAbstractionError::InvalidParameter(
252                    "This SocketAddress is not a unicast socket".to_string(),
253                ));
254            }
255        }
256
257        Ok(())
258    }
259
260    /// get the transport protocol settings for this `SocketAddress`
261    #[must_use]
262    pub fn tp_config(&self) -> Option<TpConfig> {
263        let tp = self
264            .0
265            .get_sub_element(ElementName::ApplicationEndpoint)?
266            .get_sub_element(ElementName::TpConfiguration)?;
267
268        if let Some(tcp_tp) = tp.get_sub_element(ElementName::TcpTp) {
269            let port = tcp_tp.get_sub_element(ElementName::TcpTpPort)?;
270            let (port_number, port_dynamically_assigned) = Self::port_config(&port);
271            Some(TpConfig::TcpTp {
272                port_number,
273                port_dynamically_assigned,
274            })
275        } else if let Some(udp_tp) = tp.get_sub_element(ElementName::UdpTp) {
276            let port = udp_tp.get_sub_element(ElementName::UdpTpPort)?;
277            let (port_number, port_dynamically_assigned) = Self::port_config(&port);
278            Some(TpConfig::UdpTp {
279                port_number,
280                port_dynamically_assigned,
281            })
282        } else {
283            None
284        }
285    }
286
287    // get the port number and dynamic assignment setting from a port element
288    fn port_config(port_element: &Element) -> (Option<u16>, Option<bool>) {
289        let port_number = port_element
290            .get_sub_element(ElementName::PortNumber)
291            .and_then(|pn| pn.character_data())
292            .and_then(|cdata| cdata.parse_integer());
293        let port_dynamically_assigned = port_element
294            .get_sub_element(ElementName::DynamicallyAssigned)
295            .and_then(|da| da.character_data())
296            .and_then(|cdata| cdata.string_value())
297            .map(|val| val == "true" || val == "1");
298        (port_number, port_dynamically_assigned)
299    }
300
301    /// create a new `StaticSocketConnection` from this `SocketAddress` to a remote `SocketAddress`
302    pub fn create_static_socket_connection(
303        &self,
304        name: &str,
305        remote_address: &SocketAddress,
306        tcp_role: Option<TcpRole>,
307        tcp_connect_timeout: Option<f64>,
308    ) -> Result<StaticSocketConnection, AutosarAbstractionError> {
309        let own_tp_config = self.tp_config();
310        let remote_tp_config = remote_address.tp_config();
311        match (own_tp_config, remote_tp_config) {
312            (Some(TpConfig::TcpTp { .. }), Some(TpConfig::TcpTp { .. })) => {
313                StaticSocketConnection::new(name, self.element(), remote_address, tcp_role, tcp_connect_timeout)
314            }
315            (Some(TpConfig::UdpTp { .. }), Some(TpConfig::UdpTp { .. })) | (None, None) => {
316                StaticSocketConnection::new(name, self.element(), remote_address, None, None)
317            }
318            _ => Err(AutosarAbstractionError::InvalidParameter(
319                "Both SocketAddresses must use the same transport protocol".to_string(),
320            )),
321        }
322    }
323
324    /// get the `PhysicalChannel` containing this `SocketAddress`
325    pub fn physical_channel(&self) -> Result<EthernetPhysicalChannel, AutosarAbstractionError> {
326        let named_parent = self.0.named_parent()?.unwrap();
327        named_parent.try_into()
328    }
329
330    /// iterate over all `StaticSocketConnection`s in this `SocketAddress`
331    pub fn static_socket_connections(&self) -> impl Iterator<Item = StaticSocketConnection> + Send + use<> {
332        self.0
333            .get_sub_element(ElementName::StaticSocketConnections)
334            .into_iter()
335            .flat_map(|ssc| ssc.sub_elements())
336            .filter_map(|ssc| StaticSocketConnection::try_from(ssc).ok())
337    }
338
339    /// create a `ProvidedServiceInstanceV1` in this `SocketAddress`
340    ///
341    /// Creating a `ProvidedServiceInstanceV1` in a `SocketAddress` is part of the old way of defining services (<= Autosar 4.5.0).
342    /// It is obsolete in newer versions of the standard.
343    ///
344    /// When using the new way of defining services, a `ProvidedServiceInstance` should be created in a `ServiceInstanceCollectionSet` instead.
345    pub fn create_provided_service_instance(
346        &self,
347        name: &str,
348        service_identifier: u16,
349        instance_identifier: u16,
350    ) -> Result<ProvidedServiceInstanceV1, AutosarAbstractionError> {
351        let socket_name = self.name().unwrap_or_default();
352        let ae_name = format!("{socket_name}_AE");
353        let ae = self
354            .element()
355            .get_or_create_named_sub_element(ElementName::ApplicationEndpoint, &ae_name)?;
356        let psis = ae.get_or_create_sub_element(ElementName::ProvidedServiceInstances)?;
357
358        ProvidedServiceInstanceV1::new(name, &psis, service_identifier, instance_identifier)
359    }
360
361    /// get the `ProvidedServiceInstanceV1`s in this `SocketAddress`
362    pub fn provided_service_instances(&self) -> impl Iterator<Item = ProvidedServiceInstanceV1> + Send + use<> {
363        self.element()
364            .get_sub_element(ElementName::ApplicationEndpoint)
365            .and_then(|ae| ae.get_sub_element(ElementName::ProvidedServiceInstances))
366            .into_iter()
367            .flat_map(|psis| psis.sub_elements())
368            .filter_map(|psi| ProvidedServiceInstanceV1::try_from(psi).ok())
369    }
370
371    /// create a `ConsumedServiceInstanceV1` in this `SocketAddress`
372    ///
373    /// Creating a `ConsumedServiceInstanceV1` in a `SocketAddress` is part of the old way of defining services (<= Autosar 4.5.0).
374    /// It is obsolete in newer versions of the standard.
375    ///
376    /// When using the new way of defining services, a `ConsumedServiceInstance` should be created in a `ServiceInstanceCollectionSet` instead.
377    pub fn create_consumed_service_instance(
378        &self,
379        name: &str,
380        provided_service_instance: &ProvidedServiceInstanceV1,
381    ) -> Result<ConsumedServiceInstanceV1, AutosarAbstractionError> {
382        let socket_name = self.name().unwrap_or_default();
383        let ae_name = format!("{socket_name}_AE");
384        let ae = self
385            .element()
386            .get_or_create_named_sub_element(ElementName::ApplicationEndpoint, &ae_name)?;
387        let csis = ae.get_or_create_sub_element(ElementName::ConsumedServiceInstances)?;
388        ConsumedServiceInstanceV1::new(name, &csis, provided_service_instance)
389    }
390
391    /// get the `ConsumedServiceInstance`s in this `SocketAddress`
392    pub fn consumed_service_instances(&self) -> impl Iterator<Item = ConsumedServiceInstanceV1> + Send + use<> {
393        self.element()
394            .get_sub_element(ElementName::ApplicationEndpoint)
395            .and_then(|ae| ae.get_sub_element(ElementName::ConsumedServiceInstances))
396            .into_iter()
397            .flat_map(|csis| csis.sub_elements())
398            .filter_map(|csi| ConsumedServiceInstanceV1::try_from(csi).ok())
399    }
400}
401
402//##################################################################
403
404/// transport protocol settings of a [`SocketAddress`]
405#[derive(Debug, Clone, PartialEq, Eq)]
406pub enum TpConfig {
407    /// The socket uses TCP
408    TcpTp {
409        /// The port number used by the socket
410        port_number: Option<u16>,
411        /// If the port number is dynamically assigned. Obsolete; set the port number to None instead
412        port_dynamically_assigned: Option<bool>,
413        // additional TCP options: currently not supported
414    },
415    /// The socket uses UDP
416    UdpTp {
417        /// The port number used by the socket
418        port_number: Option<u16>,
419        /// If the port number is dynamically assigned. Obsolete; set the port number to None instead
420        port_dynamically_assigned: Option<bool>,
421    },
422    // RtpTp, Ieee1722Tp, HttpTp: currently not supported
423}
424
425//##################################################################
426
427/// Describes if a [`SocketAddress`] is used for unicast or multicast
428#[derive(Debug, Clone, PartialEq)]
429pub enum SocketAddressType {
430    /// The socket is used for unicast communication with a single ECU
431    Unicast(Option<EcuInstance>),
432    /// The socket is used for multicast communication with multiple ECUs
433    Multicast(Vec<EcuInstance>),
434}
435
436//##################################################################
437
438#[cfg(test)]
439mod test {
440    use super::*;
441    use crate::communication::{IPv4AddressSource, NetworkEndpointAddress};
442    use crate::{AutosarModelAbstraction, SystemCategory};
443    use autosar_data::AutosarVersion;
444
445    #[test]
446    fn socket_address() {
447        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_4_3_0);
448        let package = model.get_or_create_package("/pkg1").unwrap();
449        let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
450        let cluster = system.create_ethernet_cluster("Cluster", &package).unwrap();
451        let channel = cluster.create_physical_channel("Channel", None).unwrap();
452
453        let ecu_instance = system.create_ecu_instance("Ecu", &package).unwrap();
454        let controller = ecu_instance
455            .create_ethernet_communication_controller("EthCtrl", None)
456            .unwrap();
457        controller.connect_physical_channel("connection", &channel).unwrap();
458
459        let ecu_instance2 = system.create_ecu_instance("Ecu2", &package).unwrap();
460        let controller2 = ecu_instance2
461            .create_ethernet_communication_controller("EthCtrl", None)
462            .unwrap();
463        controller2.connect_physical_channel("connection", &channel).unwrap();
464
465        let ecu_instance3 = system.create_ecu_instance("Ecu3", &package).unwrap();
466        let controller3 = ecu_instance3
467            .create_ethernet_communication_controller("EthCtrl", None)
468            .unwrap();
469        controller3.connect_physical_channel("connection", &channel).unwrap();
470
471        let endpoint_address = NetworkEndpointAddress::IPv4 {
472            address: Some("192.168.0.1".to_string()),
473            address_source: Some(IPv4AddressSource::Fixed),
474            default_gateway: Some("192.168.0.2".to_string()),
475            network_mask: Some("255.255.255.0".to_string()),
476        };
477        let network_endpoint = channel
478            .create_network_endpoint("Address", endpoint_address, Some(&ecu_instance))
479            .unwrap();
480        let tcp_port = TpConfig::UdpTp {
481            port_number: Some(1234),
482            port_dynamically_assigned: None,
483        };
484
485        // create a unicast socket with an EcuInstance
486        let socket_type: SocketAddressType = SocketAddressType::Unicast(Some(ecu_instance.clone()));
487        let unicast_socket_address = channel
488            .create_socket_address("Socket", &network_endpoint, &tcp_port, socket_type.clone())
489            .unwrap();
490        assert_eq!(channel.socket_addresses().count(), 1);
491        assert_eq!(unicast_socket_address.network_endpoint().unwrap(), network_endpoint);
492        assert_eq!(unicast_socket_address.socket_address_type().unwrap(), socket_type);
493        // replace the EcuInstance in the socket
494        unicast_socket_address.set_unicast_ecu(&ecu_instance2).unwrap();
495        assert_eq!(
496            unicast_socket_address.socket_address_type().unwrap(),
497            SocketAddressType::Unicast(Some(ecu_instance2.clone()))
498        );
499
500        // create a unicast socket without an EcuInstance
501        let socket_type: SocketAddressType = SocketAddressType::Unicast(None);
502        let unicast_socket_address2 = channel
503            .create_socket_address("Socket2", &network_endpoint, &tcp_port, socket_type.clone())
504            .unwrap();
505        // set the EcuInstance and verify that it is set
506        unicast_socket_address2.set_unicast_ecu(&ecu_instance).unwrap();
507        assert_eq!(
508            unicast_socket_address2.socket_address_type().unwrap(),
509            SocketAddressType::Unicast(Some(ecu_instance.clone()))
510        );
511
512        // create a multicast socket with multiple EcuInstances
513        let socket_type: SocketAddressType =
514            SocketAddressType::Multicast(vec![ecu_instance.clone(), ecu_instance2.clone()]);
515        let multicast_socket_address = channel
516            .create_socket_address("Socket3", &network_endpoint, &tcp_port, socket_type.clone())
517            .unwrap();
518        assert_eq!(multicast_socket_address.socket_address_type().unwrap(), socket_type);
519        // add an EcuInstance to the multicast socket
520        multicast_socket_address.add_multicast_ecu(&ecu_instance3).unwrap();
521        assert_eq!(
522            multicast_socket_address.socket_address_type().unwrap(),
523            SocketAddressType::Multicast(vec![ecu_instance.clone(), ecu_instance2.clone(), ecu_instance3.clone()])
524        );
525    }
526
527    #[test]
528    fn socket_sd_config() {
529        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_4_3_0);
530        let package = model.get_or_create_package("/pkg1").unwrap();
531        let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
532        let cluster = system.create_ethernet_cluster("Cluster", &package).unwrap();
533        let channel = cluster.create_physical_channel("Channel", None).unwrap();
534
535        // let ecu_instance = system.create_ecu_instance("Ecu", &package).unwrap();
536        // let controller = ecu_instance
537        //     .create_ethernet_communication_controller("EthCtrl", None)
538        //     .unwrap();
539        // controller.connect_physical_channel("connection", &channel).unwrap();
540
541        let endpoint_address = NetworkEndpointAddress::IPv4 {
542            address: Some("192.168.0.1".to_string()),
543            address_source: Some(IPv4AddressSource::Fixed),
544            default_gateway: None,
545            network_mask: None,
546        };
547        let network_endpoint = channel
548            .create_network_endpoint("Address", endpoint_address, None)
549            .unwrap();
550        let tcp_port = TpConfig::TcpTp {
551            port_number: Some(1234),
552            port_dynamically_assigned: None,
553        };
554        let socket_type: SocketAddressType = SocketAddressType::Unicast(None);
555        let socket = channel
556            .create_socket_address("Socket", &network_endpoint, &tcp_port, socket_type.clone())
557            .unwrap();
558
559        let provided_service_instance = socket.create_provided_service_instance("psi", 1, 2).unwrap();
560        let consumed_service_instance = socket
561            .create_consumed_service_instance("csi", &provided_service_instance)
562            .unwrap();
563
564        assert_eq!(socket.provided_service_instances().count(), 1);
565        assert_eq!(
566            socket.provided_service_instances().next().unwrap(),
567            provided_service_instance
568        );
569        assert_eq!(socket.consumed_service_instances().count(), 1);
570        assert_eq!(
571            socket.consumed_service_instances().next().unwrap(),
572            consumed_service_instance
573        );
574    }
575}