-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(transport): Implement support for CoAP over tcp (#12)
* Implement support for CoAP over tcp Implement the missing structures. Add tests. * Tests for CoAP over TCP. * Fix the license comment to point to the tcp module. * Update comments Fix copy/paste comments. Everything should reffer to the TCP functionality.
- Loading branch information
1 parent
600470b
commit 0e17941
Showing
6 changed files
with
189 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,86 @@ | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
/* | ||
* transport/dtls.rs - transport-specific code for TCP. | ||
* transport/tcp.rs - transport-specific code for TCP. | ||
* This file is part of the libcoap-rs crate, see the README and LICENSE files for | ||
* more information and terms of use. | ||
* Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved. | ||
* See the README as well as the LICENSE file for more information. | ||
*/ | ||
|
||
/// TODO | ||
#[allow(dead_code)] | ||
use libcoap_sys::{coap_endpoint_t, coap_free_endpoint, coap_new_endpoint, coap_proto_t::COAP_PROTO_TCP}; | ||
|
||
use crate::{context::CoapContext, error::EndpointCreationError, transport::EndpointCommon, types::CoapAddress}; | ||
|
||
use std::net::SocketAddr; | ||
|
||
#[cfg(feature = "tcp")] | ||
pub struct CoapTcpEndpoint {} | ||
#[derive(Debug)] | ||
pub struct CoapTcpEndpoint { | ||
raw_endpoint: *mut coap_endpoint_t, | ||
} | ||
|
||
impl CoapTcpEndpoint { | ||
/// Creates a new CoapTcpEndpoint and binds it to the supplied SocketAddr. | ||
/// | ||
/// This is an unsafe function (see #Safety for an explanation of why) used internally by | ||
/// libcoap-rs to instantiate new endpoints. You should most likely not use this function, and | ||
/// use one of the following alternatives instead: | ||
/// - If you just want to add an endpoint to the coap context, use [CoapContext::add_endpoint_tcp()]. | ||
/// - If you need to modify the underlying [coap_endpoint_t] directly (in an unsafe manner), use | ||
/// [CoapContext::add_endpoint_tcp()] to instantiate the endpoint and then [as_mut_raw_endpoint()] | ||
/// to access the underlying struct. | ||
/// | ||
/// # Safety | ||
/// All endpoint types defined in this crate contain a [coap_endpoint_t] instance, | ||
/// which is the representation of endpoints used by the underlying libcoap C library. | ||
/// | ||
/// On instantiation, these [coap_endpoint_t] instances are bound to a context, which includes | ||
/// adding them to a list maintained by the [CoapContext] (or – to be more specific – the | ||
/// underlying [libcoap_sys::coap_context_t]. | ||
/// | ||
/// When the context that this endpoint is bound to is dropped, the context calls [libcoap_sys::coap_free_context()], | ||
/// which will not only free the context, but also all [coap_endpoint_t] instances associated | ||
/// with it, including the one this struct points to. | ||
/// | ||
/// Therefore, if you decide to use this function anyway, you have to ensure that the | ||
/// CoapContext lives at least as long as this struct does. | ||
/// Also note that unlike [CoapContext::add_endpoint_tcp()], this function does not add the | ||
/// endpoint to the [CoapContext::endpoints] vector, while the underlying [coap_endpoint_t] is | ||
/// added to the underlying [libcoap_sys::coap_context_t] | ||
pub(crate) unsafe fn new(context: &mut CoapContext, addr: SocketAddr) -> Result<Self, EndpointCreationError> { | ||
let endpoint = coap_new_endpoint( | ||
context.as_mut_raw_context(), | ||
CoapAddress::from(addr).as_raw_address(), | ||
COAP_PROTO_TCP, | ||
); | ||
if endpoint.is_null() { | ||
return Err(EndpointCreationError::Unknown); | ||
} | ||
Ok(Self { raw_endpoint: endpoint }) | ||
} | ||
} | ||
|
||
impl EndpointCommon for CoapTcpEndpoint { | ||
unsafe fn as_raw_endpoint(&self) -> &coap_endpoint_t { | ||
// SAFETY: raw_endpoint is checked to be a valid pointer on struct instantiation, cannot be | ||
// freed by anything outside of here (assuming the contract of this function is kept), and | ||
// the default (elided) lifetimes are correct (the pointer is valid as long as the endpoint | ||
// is). | ||
&*self.raw_endpoint | ||
} | ||
|
||
unsafe fn as_mut_raw_endpoint(&mut self) -> &mut coap_endpoint_t { | ||
// SAFETY: raw_endpoint is checked to be a valid pointer on struct instantiation, is not | ||
// freed by anything outside of here (assuming the contract of this function is kept), and | ||
// the default (elided) lifetimes are correct (the pointer is valid as long as the endpoint | ||
// is). | ||
&mut *self.raw_endpoint | ||
} | ||
} | ||
|
||
impl Drop for CoapTcpEndpoint { | ||
fn drop(&mut self) { | ||
// SAFETY: Raw endpoint is guaranteed to exist for as long as the container exists. | ||
unsafe { coap_free_endpoint(self.raw_endpoint) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
/* | ||
* tcp_client_server_test.rs - Tests for TCP clients+servers. | ||
* This file is part of the libcoap-rs crate, see the README and LICENSE files for | ||
* more information and terms of use. | ||
* Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved. | ||
* See the README as well as the LICENSE file for more information. | ||
*/ | ||
|
||
use libcoap_rs::session::CoapClientSession; | ||
use libcoap_rs::{ | ||
message::CoapMessageCommon, | ||
protocol::{CoapMessageCode, CoapResponseCode}, | ||
session::CoapSessionCommon, | ||
CoapContext, | ||
}; | ||
use std::time::Duration; | ||
|
||
mod common; | ||
|
||
#[test] | ||
pub fn basic_client_server_request() { | ||
let server_address = common::get_unused_server_addr(); | ||
|
||
let server_handle = common::spawn_test_server(move |context| context.add_endpoint_tcp(server_address).unwrap()); | ||
|
||
let mut context = CoapContext::new().unwrap(); | ||
let session = CoapClientSession::connect_tcp(&mut context, server_address).unwrap(); | ||
|
||
let request = common::gen_test_request(server_address); | ||
let req_handle = session.send_request(request).unwrap(); | ||
loop { | ||
assert!(context.do_io(Some(Duration::from_secs(10))).expect("error during IO") <= Duration::from_secs(10)); | ||
for response in session.poll_handle(&req_handle) { | ||
assert_eq!(response.code(), CoapMessageCode::Response(CoapResponseCode::Content)); | ||
assert_eq!(response.data().unwrap().as_ref(), "Hello World!".as_bytes()); | ||
server_handle.join().unwrap(); | ||
return; | ||
} | ||
} | ||
} |