Skip to main content

opcua_client/session/services/
session.rs

1use std::{sync::Arc, time::Duration};
2
3use opcua_core::{
4    comms::url::hostname_from_url, sync::RwLock, trace_read_lock, trace_write_lock, ResponseMessage,
5};
6use opcua_crypto::{
7    self, legacy_encrypt_secret, random, CertificateStore, PKey, SecurityPolicy, X509,
8};
9use opcua_types::{
10    ActivateSessionRequest, ActivateSessionResponse, AnonymousIdentityToken,
11    ApplicationDescription, ByteString, CancelRequest, CancelResponse, CloseSessionRequest,
12    CloseSessionResponse, CreateSessionRequest, CreateSessionResponse, EndpointDescription, Error,
13    ExtensionObject, IntegerId, IssuedIdentityToken, MessageSecurityMode, NodeId, SignatureData,
14    SignedSoftwareCertificate, StatusCode, UAString, UserNameIdentityToken, UserTokenType,
15    X509IdentityToken,
16};
17use rsa::RsaPrivateKey;
18use tracing::{debug_span, error, info_span, Instrument};
19
20use crate::{
21    session::{
22        process_service_result, process_unexpected_response,
23        request_builder::{builder_base, builder_debug, builder_error, RequestHeaderBuilder},
24    },
25    AsyncSecureChannel, IdentityToken, Session, UARequest,
26};
27
28#[derive(Clone)]
29/// Sends a [`CreateSessionRequest`] to the server, returning the session id of the created
30/// session. Internally, the session will store the authentication token which is used for requests
31/// subsequent to this call.
32///
33/// See OPC UA Part 4 - Services 5.6.2 for complete description of the service and error responses.
34///
35/// Note that in order to use the session you will need to store the auth token and
36/// use that in subsequent requests.
37///
38/// Note: Avoid calling this on sessions managed by the [`Session`] type. Session creation
39/// is handled automatically as part of connect/reconnect logic.
40pub struct CreateSession<'a> {
41    client_description: ApplicationDescription,
42    server_uri: UAString,
43    endpoint_url: UAString,
44    session_name: UAString,
45    client_certificate: Option<X509>,
46    session_timeout: f64,
47    max_response_message_size: u32,
48    certificate_store: &'a RwLock<CertificateStore>,
49    endpoint: &'a EndpointDescription,
50    nonce_length: usize,
51
52    header: RequestHeaderBuilder,
53}
54
55builder_base!(CreateSession<'a>);
56
57impl<'a> CreateSession<'a> {
58    /// Create a new `CreateSession` request on the given session.
59    ///
60    /// Crate private since there is no way to safely use this.
61    pub(crate) fn new(session: &'a Session) -> Self {
62        Self {
63            endpoint_url: session.endpoint_info().endpoint.endpoint_url.clone(),
64            server_uri: UAString::null(),
65            client_description: session.application_description.clone(),
66            session_name: session.session_name.clone(),
67            client_certificate: session.channel.read_own_certificate(),
68            endpoint: &session.endpoint_info().endpoint,
69            certificate_store: session.channel.certificate_store(),
70            session_timeout: session.session_timeout,
71            max_response_message_size: 0,
72            nonce_length: session.session_nonce_length,
73            header: RequestHeaderBuilder::new_from_session(session),
74        }
75    }
76
77    /// Create a new `CreateSession` request with the given data.
78    pub fn new_manual(
79        certificate_store: &'a RwLock<CertificateStore>,
80        endpoint: &'a EndpointDescription,
81        session_id: u32,
82        timeout: Duration,
83        auth_token: NodeId,
84        request_handle: IntegerId,
85    ) -> Self {
86        Self {
87            endpoint_url: UAString::null(),
88            server_uri: UAString::null(),
89            client_description: ApplicationDescription::default(),
90            session_name: UAString::null(),
91            client_certificate: None,
92            session_timeout: 0.0,
93            max_response_message_size: 0,
94            certificate_store,
95            endpoint,
96            nonce_length: 32,
97            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
98        }
99    }
100
101    /// Set the client description.
102    pub fn client_description(mut self, desc: impl Into<ApplicationDescription>) -> Self {
103        self.client_description = desc.into();
104        self
105    }
106
107    /// Set the server URI.
108    pub fn server_uri(mut self, server_uri: impl Into<UAString>) -> Self {
109        self.server_uri = server_uri.into();
110        self
111    }
112
113    /// Set the target endpoint URL.
114    pub fn endpoint_url(mut self, endpoint_url: impl Into<UAString>) -> Self {
115        self.endpoint_url = endpoint_url.into();
116        self
117    }
118
119    /// Set the session name.
120    pub fn session_name(mut self, session_name: impl Into<UAString>) -> Self {
121        self.session_name = session_name.into();
122        self
123    }
124
125    /// Set the client certificate.
126    pub fn client_certificate(mut self, client_certificate: X509) -> Self {
127        self.client_certificate = Some(client_certificate);
128        self
129    }
130
131    /// Load the client certificate from the certificate store.
132    pub fn client_cert_from_store(mut self, certificate_store: &RwLock<CertificateStore>) -> Self {
133        let cert_store = trace_read_lock!(certificate_store);
134        self.client_certificate = cert_store.read_own_cert().ok();
135        self
136    }
137
138    /// Set the timeout for the session.
139    pub fn session_timeout(mut self, session_timeout: f64) -> Self {
140        self.session_timeout = session_timeout;
141        self
142    }
143
144    /// Set the requested maximum response message size.
145    pub fn max_response_message_size(mut self, max_response_message_size: u32) -> Self {
146        self.max_response_message_size = max_response_message_size;
147        self
148    }
149
150    /// Set the length of the client nonce used to generate this request.
151    pub fn nonce_length(mut self, nonce_length: usize) -> Self {
152        self.nonce_length = nonce_length;
153        self
154    }
155}
156
157impl UARequest for CreateSession<'_> {
158    type Out = CreateSessionResponse;
159
160    async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
161    where
162        Self: 'a,
163    {
164        let security_policy = channel.security_policy();
165
166        let span = info_span!(
167            "Sending CreateSession request",
168            endpoint = %self.endpoint_url,
169            server_uri = %self.server_uri,
170            requested_session_timeout = self.session_timeout,
171            max_response_message_size = self.max_response_message_size,
172            session_name = %self.session_name
173        );
174        let client_nonce = random::byte_string(self.nonce_length);
175
176        let request = {
177            let _h = span.enter();
178
179            CreateSessionRequest {
180                request_header: self.header.header,
181                client_description: self.client_description,
182                server_uri: self.server_uri,
183                endpoint_url: self.endpoint_url,
184                session_name: self.session_name,
185                client_nonce: client_nonce.clone(),
186                client_certificate: self
187                    .client_certificate
188                    .as_ref()
189                    .map(|v| v.as_byte_string())
190                    .unwrap_or_default(),
191                requested_session_timeout: self.session_timeout,
192                max_response_message_size: self.max_response_message_size,
193            }
194        };
195
196        let response = channel
197            .send(request, self.header.timeout)
198            .instrument(span.clone())
199            .await?;
200
201        let _h = span.enter();
202
203        if let ResponseMessage::CreateSession(response) = response {
204            builder_debug!(self, "create_session, success");
205            process_service_result(&response.response_header)?;
206
207            if security_policy != SecurityPolicy::None {
208                if self.endpoint.server_certificate != response.server_certificate {
209                    error!("Server certificate in CreateSession response does not match channel certificate");
210                    return Err(Error::new(StatusCode::BadCertificateInvalid, "Server certificate in CreateSession response does not match channel certificate"));
211                }
212                let server_certificate =
213                    opcua_crypto::X509::from_byte_string(&response.server_certificate)
214                        .inspect_err(|e| error!("Failed to parse server certificate: {e}"))?;
215                // Validate server certificate against hostname and application_uri
216                let hostname =
217                    hostname_from_url(self.endpoint.endpoint_url.as_ref()).map_err(|e| {
218                        Error::new(
219                            StatusCode::BadUnexpectedError,
220                            format!(
221                                "Failed to extract hostname from endpoint URL ({}): {e}",
222                                self.endpoint.endpoint_url
223                            ),
224                        )
225                    })?;
226                let application_uri = self.endpoint.server.application_uri.as_ref();
227
228                let certificate_store = trace_write_lock!(self.certificate_store);
229                certificate_store
230                    .validate_or_reject_application_instance_cert(
231                        &server_certificate,
232                        security_policy,
233                        Some(&hostname),
234                        Some(application_uri),
235                    )
236                    .inspect_err(|e| {
237                        error!("Rejected server certificate in create session response: {e}");
238                    })?;
239
240                opcua_crypto::verify_signature_data(
241                    &response.server_signature,
242                    security_policy,
243                    &server_certificate,
244                    self.client_certificate.as_ref().ok_or_else(|| {
245                        Error::new(
246                            StatusCode::BadCertificateInvalid,
247                            "Missing client certificate in request",
248                        )
249                    })?,
250                    client_nonce.as_ref(),
251                )
252                .inspect_err(|e| {
253                    error!("Failed to verify server signature in create session response: {e}");
254                })?;
255            }
256
257            tracing::debug!(
258                "Successfully created session, session_id = {}, max_request_message_size = {}, revised_session_timeout = {}",
259                response.session_id,
260                response.max_request_message_size,
261                response.revised_session_timeout
262            );
263
264            channel
265                .update_from_created_session(
266                    &response.server_nonce,
267                    &response.server_certificate,
268                    &response.authentication_token,
269                )
270                .inspect_err(|e| {
271                    error!("Failed to update channel from created session: {e}");
272                })?;
273
274            Ok(*response)
275        } else {
276            tracing::error!("create_session failed");
277            Err(process_unexpected_response(response))
278        }
279    }
280}
281
282#[derive(Debug, Clone)]
283/// Sends an [`ActivateSessionRequest`] to the server to activate the session tied to
284/// the secure channel.
285///
286/// See OPC UA Part 4 - Services 5.6.3 for complete description of the service and error responses.
287///
288/// Note: Avoid calling this on sessions managed by the [`Session`] type. Session activation
289/// is handled automatically as part of connect/reconnect logic.
290pub struct ActivateSession {
291    identity_token: IdentityToken,
292    private_key: Option<PKey<RsaPrivateKey>>,
293    locale_ids: Vec<UAString>,
294    client_software_certificates: Vec<SignedSoftwareCertificate>,
295    endpoint: EndpointDescription,
296
297    header: RequestHeaderBuilder,
298}
299
300builder_base!(ActivateSession);
301
302impl ActivateSession {
303    /// Create a new `ActivateSession` request.
304    ///
305    /// Crate private since there is no way to safely use this.
306    pub(crate) fn new(session: &Session) -> Self {
307        Self {
308            identity_token: session.endpoint_info().user_identity_token.clone(),
309            private_key: session.channel.read_own_private_key(),
310            locale_ids: session
311                .endpoint_info()
312                .preferred_locales
313                .iter()
314                .map(UAString::from)
315                .collect(),
316            client_software_certificates: Vec::new(),
317            endpoint: session.endpoint_info().endpoint.clone(),
318            header: RequestHeaderBuilder::new_from_session(session),
319        }
320    }
321
322    /// Create a new `ActivateSession` request.
323    pub fn new_manual(
324        endpoint: EndpointDescription,
325        session_id: u32,
326        timeout: Duration,
327        auth_token: NodeId,
328        request_handle: IntegerId,
329    ) -> Self {
330        Self {
331            identity_token: IdentityToken::Anonymous,
332            private_key: None,
333            locale_ids: Vec::new(),
334            client_software_certificates: Vec::new(),
335            endpoint,
336            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
337        }
338    }
339
340    /// Set the identity token.
341    pub fn identity_token(mut self, identity_token: IdentityToken) -> Self {
342        self.identity_token = identity_token;
343        self
344    }
345
346    /// Set the client private key.
347    pub fn private_key(mut self, private_key: PKey<RsaPrivateKey>) -> Self {
348        self.private_key = Some(private_key);
349        self
350    }
351
352    /// Set the requested list of locales.
353    pub fn locale_ids(mut self, locale_ids: Vec<UAString>) -> Self {
354        self.locale_ids = locale_ids;
355        self
356    }
357
358    /// Add a requested locale with the given ID.
359    pub fn locale_id(mut self, locale_id: impl Into<UAString>) -> Self {
360        self.locale_ids.push(locale_id.into());
361        self
362    }
363
364    /// Set the client software certificates.
365    pub fn client_software_certificates(
366        mut self,
367        certificates: Vec<SignedSoftwareCertificate>,
368    ) -> Self {
369        self.client_software_certificates = certificates;
370        self
371    }
372
373    /// Add a client software certificate.
374    pub fn client_software_certificate(mut self, certificate: SignedSoftwareCertificate) -> Self {
375        self.client_software_certificates.push(certificate);
376        self
377    }
378
379    async fn user_identity_token(
380        &self,
381        remote_nonce: &ByteString,
382        remote_cert: &Option<X509>,
383        security_mode: MessageSecurityMode,
384        channel_security_policy: SecurityPolicy,
385    ) -> Result<(ExtensionObject, SignatureData), Error> {
386        let user_token_type = match &self.identity_token {
387            IdentityToken::Anonymous => UserTokenType::Anonymous,
388            IdentityToken::UserName(_, _) => UserTokenType::UserName,
389            IdentityToken::X509(_, _) => UserTokenType::Certificate,
390            IdentityToken::IssuedToken(_) => UserTokenType::IssuedToken,
391        };
392        let Some(policy) = self.endpoint.find_policy(user_token_type) else {
393            builder_error!(
394                self,
395                "Cannot find user token type {:?} for this endpoint, cannot connect",
396                user_token_type
397            );
398            return Err(Error::new(
399                StatusCode::BadSecurityPolicyRejected,
400                format!(
401                    "Cannot find user token type {user_token_type:?} for this endpoint, cannot connect"
402                ),
403            ));
404        };
405        let security_policy = if policy.security_policy_uri.is_empty() {
406            // Assume None
407            SecurityPolicy::None
408        } else {
409            SecurityPolicy::from_uri(policy.security_policy_uri.as_ref())
410        };
411
412        if security_policy == SecurityPolicy::Unknown {
413            error!("Unknown security policy {}", policy.security_policy_uri);
414            return Err(Error::new(
415                StatusCode::BadSecurityPolicyRejected,
416                format!("Unknown security policy {}", policy.security_policy_uri),
417            ));
418        }
419
420        match &self.identity_token {
421            IdentityToken::Anonymous => {
422                let identity_token = AnonymousIdentityToken {
423                    policy_id: policy.policy_id.clone(),
424                };
425                let identity_token = ExtensionObject::from_message(identity_token);
426                Ok((identity_token, SignatureData::null()))
427            }
428            IdentityToken::UserName(user, pass) => {
429                let nonce = remote_nonce.as_ref();
430                let cert = remote_cert;
431                let secret = legacy_encrypt_secret(
432                    channel_security_policy,
433                    security_mode,
434                    policy,
435                    nonce,
436                    cert,
437                    pass.0.as_bytes(),
438                )?;
439                let identity_token = UserNameIdentityToken {
440                    policy_id: secret.policy,
441                    user_name: UAString::from(user.as_str()),
442                    password: secret.secret,
443                    encryption_algorithm: secret.encryption_algorithm,
444                };
445                Ok((
446                    ExtensionObject::from_message(identity_token),
447                    SignatureData::null(),
448                ))
449            }
450            IdentityToken::X509(cert, private_key) => {
451                let nonce = remote_nonce.as_ref();
452                let server_cert = remote_cert;
453                let Some(server_cert) = &server_cert else {
454                    error!("Cannot create an X509IdentityToken because the remote server has no cert with which to create a signature");
455                    return Err(Error::new(StatusCode::BadCertificateInvalid, "Cannot create an X509IdentityToken because the remote server has no cert with which to create a signature"));
456                };
457
458                let user_token_signature = opcua_crypto::create_signature_data(
459                    private_key,
460                    security_policy,
461                    &server_cert.as_byte_string(),
462                    &ByteString::from(&nonce),
463                )?;
464
465                // Create identity token
466                let identity_token = X509IdentityToken {
467                    policy_id: policy.policy_id.clone(),
468                    certificate_data: cert.as_byte_string(),
469                };
470
471                Ok((
472                    ExtensionObject::from_message(identity_token),
473                    user_token_signature,
474                ))
475            }
476            IdentityToken::IssuedToken(source) => {
477                let token = source.0.get_issued_token().await?;
478                let nonce = remote_nonce.as_ref();
479                let cert = remote_cert;
480                let secret = legacy_encrypt_secret(
481                    channel_security_policy,
482                    security_mode,
483                    policy,
484                    nonce,
485                    cert,
486                    token.as_ref(),
487                )?;
488                let identity_token = IssuedIdentityToken {
489                    policy_id: secret.policy,
490                    encryption_algorithm: secret.encryption_algorithm,
491                    token_data: secret.secret,
492                };
493                Ok((
494                    ExtensionObject::from_message(identity_token),
495                    SignatureData::null(),
496                ))
497            }
498        }
499    }
500
501    async fn build_request(
502        self,
503        channel: &AsyncSecureChannel,
504    ) -> Result<ActivateSessionRequest, Error> {
505        let (remote_cert, remote_nonce, security_policy, message_security_mode) = {
506            let secure_channel = trace_read_lock!(channel.secure_channel);
507            (
508                secure_channel.remote_cert(),
509                secure_channel.remote_nonce_as_byte_string(),
510                secure_channel.security_policy(),
511                secure_channel.security_mode(),
512            )
513        };
514        let (user_identity_token, user_token_signature) = self
515            .user_identity_token(
516                &remote_nonce,
517                &remote_cert,
518                message_security_mode,
519                security_policy,
520            )
521            .in_current_span()
522            .await?;
523        let client_signature = match security_policy {
524            SecurityPolicy::None => SignatureData::null(),
525            _ => {
526                let Some(client_pkey) = self.private_key else {
527                    error!("Cannot create client signature - no pkey!");
528                    return Err(Error::new(
529                        StatusCode::BadUnexpectedError,
530                        "Cannot sign request, no private key provided",
531                    ));
532                };
533
534                let Some(server_cert) = remote_cert else {
535                    error!("Cannot sign server certificate because server cert is null");
536                    return Err(Error::new(
537                        StatusCode::BadUnexpectedError,
538                        "Cannot sign request, missing server certificate",
539                    ));
540                };
541
542                let server_nonce = remote_nonce;
543                if server_nonce.is_null_or_empty() {
544                    error!("Cannot sign server certificate because server nonce is empty");
545                    return Err(Error::new(
546                        StatusCode::BadUnexpectedError,
547                        "Cannot sign request, empty remote nonce",
548                    ));
549                }
550
551                let server_cert = server_cert.as_byte_string();
552                opcua_crypto::create_signature_data(
553                    &client_pkey,
554                    security_policy,
555                    &server_cert,
556                    &server_nonce,
557                )?
558            }
559        };
560
561        Ok(ActivateSessionRequest {
562            request_header: self.header.header,
563            client_signature,
564            client_software_certificates: if self.client_software_certificates.is_empty() {
565                None
566            } else {
567                Some(self.client_software_certificates)
568            },
569            locale_ids: if self.locale_ids.is_empty() {
570                None
571            } else {
572                Some(self.locale_ids)
573            },
574            user_identity_token,
575            user_token_signature,
576        })
577    }
578}
579
580impl UARequest for ActivateSession {
581    type Out = ActivateSessionResponse;
582
583    async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
584    where
585        Self: 'a,
586    {
587        let timeout = self.header.timeout;
588        let span = info_span!("Sending ActivateSession request",
589            endpoint = %self.endpoint.endpoint_url,
590            session_id = self.header.session_id,
591        );
592        let request = self.build_request(channel).instrument(span.clone()).await?;
593
594        let response = channel
595            .send(request, timeout)
596            .instrument(span.clone())
597            .await?;
598
599        let _h = span.enter();
600        if let ResponseMessage::ActivateSession(response) = response {
601            tracing::debug!("activate_session success");
602            // trace!("ActivateSessionResponse = {:#?}", response);
603            process_service_result(&response.response_header)?;
604            channel.update_from_activated_session(&response.server_nonce)?;
605            Ok(*response)
606        } else {
607            tracing::error!("activate_session failed");
608            Err(process_unexpected_response(response))
609        }
610    }
611}
612
613#[derive(Debug, Clone)]
614/// Close the session by sending a [`CloseSessionRequest`] to the server.
615///
616/// Note: Avoid using this on an session managed by the [`Session`] type,
617/// instead call [`Session::disconnect`].
618pub struct CloseSession {
619    delete_subscriptions: bool,
620    header: RequestHeaderBuilder,
621}
622
623builder_base!(CloseSession);
624
625impl CloseSession {
626    /// Create a new `CloseSession` request.
627    ///
628    /// Crate private as there is no way to use this safely.
629    pub(crate) fn new(session: &Session) -> Self {
630        Self {
631            delete_subscriptions: true,
632            header: RequestHeaderBuilder::new_from_session(session),
633        }
634    }
635
636    /// Create a new `CloseSession` request.
637    pub fn new_manual(
638        session_id: u32,
639        timeout: Duration,
640        auth_token: NodeId,
641        request_handle: IntegerId,
642    ) -> Self {
643        Self {
644            delete_subscriptions: true,
645            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
646        }
647    }
648
649    /// Set `DeleteSubscriptions`, indicating to the server whether it should
650    /// delete subscriptions immediately or wait for them to expire.
651    pub fn delete_subscriptions(mut self, delete_subscriptions: bool) -> Self {
652        self.delete_subscriptions = delete_subscriptions;
653        self
654    }
655}
656
657impl UARequest for CloseSession {
658    type Out = CloseSessionResponse;
659
660    async fn send<'a>(self, channel: &'a AsyncSecureChannel) -> Result<Self::Out, Error>
661    where
662        Self: 'a,
663    {
664        let request = CloseSessionRequest {
665            delete_subscriptions: self.delete_subscriptions,
666            request_header: self.header.header,
667        };
668        let span = debug_span!(
669            "Sending CloseSession request",
670            session_id = self.header.session_id,
671        );
672        let response = channel
673            .send(request, self.header.timeout)
674            .instrument(span.clone())
675            .await?;
676        let _h = span.enter();
677        if let ResponseMessage::CloseSession(response) = response {
678            builder_debug!(self, "close_session success");
679            process_service_result(&response.response_header)?;
680            Ok(*response)
681        } else {
682            builder_error!(self, "close_session failed {:?}", response);
683            Err(process_unexpected_response(response))
684        }
685    }
686}
687
688#[derive(Debug, Clone)]
689/// Cancels an outstanding service request by sending a [`CancelRequest`] to the server.
690///
691/// See OPC UA Part 4 - Services 5.6.5 for complete description of the service and error responses.
692pub struct Cancel {
693    request_handle: IntegerId,
694    header: RequestHeaderBuilder,
695}
696
697builder_base!(Cancel);
698
699impl Cancel {
700    /// Create a new cancel request, to cancel a running service call.
701    pub fn new(request_to_cancel: IntegerId, session: &Session) -> Self {
702        Self {
703            request_handle: request_to_cancel,
704            header: RequestHeaderBuilder::new_from_session(session),
705        }
706    }
707
708    /// Create a new cancel request, to cancel a running service call.
709    pub fn new_manual(
710        request_to_cancel: IntegerId,
711        session_id: u32,
712        timeout: Duration,
713        auth_token: NodeId,
714        request_handle: IntegerId,
715    ) -> Self {
716        Self {
717            request_handle: request_to_cancel,
718            header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
719        }
720    }
721}
722
723impl UARequest for Cancel {
724    type Out = CancelResponse;
725
726    async fn send<'a>(self, channel: &'a AsyncSecureChannel) -> Result<Self::Out, Error>
727    where
728        Self: 'a,
729    {
730        let request = CancelRequest {
731            request_header: self.header.header,
732            request_handle: self.request_handle,
733        };
734        let span = debug_span!(
735            "Sending Cancel request",
736            request_handle = self.request_handle,
737            session_id = self.header.session_id,
738        );
739
740        let response = channel
741            .send(request, self.header.timeout)
742            .instrument(span.clone())
743            .await?;
744        let _h = span.enter();
745        if let ResponseMessage::Cancel(response) = response {
746            process_service_result(&response.response_header)?;
747            Ok(*response)
748        } else {
749            Err(process_unexpected_response(response))
750        }
751    }
752}
753
754impl Session {
755    /// Sends a [`CreateSessionRequest`] to the server, returning the session id of the created
756    /// session. Internally, the session will store the authentication token which is used for requests
757    /// subsequent to this call.
758    ///
759    /// See OPC UA Part 4 - Services 5.6.2 for complete description of the service and error responses.
760    ///
761    /// # Returns
762    ///
763    /// * `Ok(NodeId)` - Success, session id
764    /// * `Err(Error)` - Request failed, [Status code](StatusCode) is the reason for failure.
765    ///
766    pub(crate) async fn create_session(&self) -> Result<NodeId, Error> {
767        let response = CreateSession::new(self).send(&self.channel).await?;
768
769        let session_id = {
770            self.session_id.store(Arc::new(response.session_id.clone()));
771            response.session_id.clone()
772        };
773
774        Ok(session_id)
775    }
776
777    /// Sends an [`ActivateSessionRequest`] to the server to activate this session
778    ///
779    /// See OPC UA Part 4 - Services 5.6.3 for complete description of the service and error responses.
780    ///
781    /// # Returns
782    ///
783    /// * `Ok(())` - Success
784    /// * `Err(Error)` - Request failed, [Status code](StatusCode) is the reason for failure.
785    ///
786    pub(crate) async fn activate_session(&self) -> Result<(), Error> {
787        ActivateSession::new(self).send(&self.channel).await?;
788        Ok(())
789    }
790
791    /// Close the session by sending a [`CloseSessionRequest`] to the server.
792    ///
793    /// This is not accessible by users, they must instead call `disconnect` to properly close the session.
794    pub(crate) async fn close_session(&self, delete_subscriptions: bool) -> Result<(), Error> {
795        CloseSession::new(self)
796            .delete_subscriptions(delete_subscriptions)
797            .send(&self.channel)
798            .await?;
799        Ok(())
800    }
801
802    /// Cancels an outstanding service request by sending a [`CancelRequest`] to the server.
803    ///
804    /// See OPC UA Part 4 - Services 5.6.5 for complete description of the service and error responses.
805    ///
806    /// # Arguments
807    ///
808    /// * `request_handle` - Handle to the outstanding request to be cancelled.
809    ///
810    /// # Returns
811    ///
812    /// * `Ok(u32)` - Success, number of cancelled requests
813    /// * `Err(Error)` - Request failed, [Status code](StatusCode) is the reason for failure.
814    ///
815    pub async fn cancel(&self, request_handle: IntegerId) -> Result<u32, Error> {
816        Ok(Cancel::new(request_handle, self)
817            .send(&self.channel)
818            .await?
819            .cancel_count)
820    }
821}