Skip to content

Commit

Permalink
Expose loggable information about chat connection, and log more
Browse files Browse the repository at this point in the history
  • Loading branch information
akonradi-signal authored Dec 13, 2024
1 parent cf98c1a commit 8414cbf
Show file tree
Hide file tree
Showing 27 changed files with 489 additions and 117 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions node/Native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export function AuthCredentialWithPniResponse_CheckValidContents(bytes: Buffer):
export function AuthCredentialWithPni_CheckValidContents(bytes: Buffer): void;
export function AuthenticatedChatConnection_connect(asyncRuntime: Wrapper<TokioAsyncContext>, connectionManager: Wrapper<ConnectionManager>, username: string, password: string, receiveStories: boolean): CancellablePromise<AuthenticatedChatConnection>;
export function AuthenticatedChatConnection_disconnect(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<AuthenticatedChatConnection>): CancellablePromise<void>;
export function AuthenticatedChatConnection_info(chat: Wrapper<AuthenticatedChatConnection>): ConnectionInfo;
export function AuthenticatedChatConnection_info(chat: Wrapper<AuthenticatedChatConnection>): ChatConnectionInfo;
export function AuthenticatedChatConnection_init_listener(chat: Wrapper<AuthenticatedChatConnection>, listener: ChatListener): void;
export function AuthenticatedChatConnection_send(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<AuthenticatedChatConnection>, httpRequest: Wrapper<HttpRequest>, timeoutMillis: number): CancellablePromise<ChatResponse>;
export function BackupAuthCredentialPresentation_CheckValidContents(presentationBytes: Buffer): void;
Expand Down Expand Up @@ -205,6 +205,9 @@ export function Cds2ClientState_New(mrenclave: Buffer, attestationMsg: Buffer, c
export function CdsiLookup_complete(asyncRuntime: Wrapper<TokioAsyncContext>, lookup: Wrapper<CdsiLookup>): CancellablePromise<LookupResponse>;
export function CdsiLookup_new(asyncRuntime: Wrapper<TokioAsyncContext>, connectionManager: Wrapper<ConnectionManager>, username: string, password: string, request: Wrapper<LookupRequest>): CancellablePromise<CdsiLookup>;
export function CdsiLookup_token(lookup: Wrapper<CdsiLookup>): Buffer;
export function ChatConnectionInfo_description(connectionInfo: Wrapper<ChatConnectionInfo>): string;
export function ChatConnectionInfo_ip_version(connectionInfo: Wrapper<ChatConnectionInfo>): number;
export function ChatConnectionInfo_local_port(connectionInfo: Wrapper<ChatConnectionInfo>): number;
export function ChatService_SetListenerAuth(runtime: Wrapper<TokioAsyncContext>, chat: Wrapper<AuthChat>, listener: ChatListener | null): void;
export function ChatService_SetListenerUnauth(runtime: Wrapper<TokioAsyncContext>, chat: Wrapper<UnauthChat>, listener: ChatListener | null): void;
export function ChatService_auth_send(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<AuthChat>, httpRequest: Wrapper<HttpRequest>, timeoutMillis: number): CancellablePromise<ChatResponse>;
Expand All @@ -223,8 +226,6 @@ export function CiphertextMessage_Type(msg: Wrapper<CiphertextMessage>): number;
export function ComparableBackup_GetComparableString(backup: Wrapper<ComparableBackup>): string;
export function ComparableBackup_GetUnknownFields(backup: Wrapper<ComparableBackup>): string[];
export function ComparableBackup_ReadUnencrypted(stream: InputStream, len: bigint, purpose: number): Promise<ComparableBackup>;
export function ConnectionInfo_ip_version(connectionInfo: Wrapper<ConnectionInfo>): number;
export function ConnectionInfo_local_port(connectionInfo: Wrapper<ConnectionInfo>): number;
export function ConnectionManager_clear_proxy(connectionManager: Wrapper<ConnectionManager>): void;
export function ConnectionManager_new(environment: number, userAgent: string): ConnectionManager;
export function ConnectionManager_on_network_change(connectionManager: Wrapper<ConnectionManager>): void;
Expand Down Expand Up @@ -569,7 +570,7 @@ export function TokioAsyncContext_cancel(context: Wrapper<TokioAsyncContext>, ra
export function TokioAsyncContext_new(): TokioAsyncContext;
export function UnauthenticatedChatConnection_connect(asyncRuntime: Wrapper<TokioAsyncContext>, connectionManager: Wrapper<ConnectionManager>): CancellablePromise<UnauthenticatedChatConnection>;
export function UnauthenticatedChatConnection_disconnect(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<UnauthenticatedChatConnection>): CancellablePromise<void>;
export function UnauthenticatedChatConnection_info(chat: Wrapper<UnauthenticatedChatConnection>): ConnectionInfo;
export function UnauthenticatedChatConnection_info(chat: Wrapper<UnauthenticatedChatConnection>): ChatConnectionInfo;
export function UnauthenticatedChatConnection_init_listener(chat: Wrapper<UnauthenticatedChatConnection>, listener: ChatListener): void;
export function UnauthenticatedChatConnection_send(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<UnauthenticatedChatConnection>, httpRequest: Wrapper<HttpRequest>, timeoutMillis: number): CancellablePromise<ChatResponse>;
export function UnidentifiedSenderMessageContent_Deserialize(data: Buffer): UnidentifiedSenderMessageContent;
Expand Down Expand Up @@ -598,10 +599,10 @@ interface Aes256GcmSiv { readonly __type: unique symbol; }
interface AuthChat { readonly __type: unique symbol; }
interface AuthenticatedChatConnection { readonly __type: unique symbol; }
interface CdsiLookup { readonly __type: unique symbol; }
interface ChatConnectionInfo { readonly __type: unique symbol; }
interface CiphertextMessage { readonly __type: unique symbol; }
interface ComparableBackup { readonly __type: unique symbol; }
interface ComparableBackup { readonly __type: unique symbol; }
interface ConnectionInfo { readonly __type: unique symbol; }
interface ConnectionManager { readonly __type: unique symbol; }
interface DecryptionErrorMessage { readonly __type: unique symbol; }
interface ExpiringProfileKeyCredential { readonly __type: unique symbol; }
Expand Down
13 changes: 9 additions & 4 deletions node/ts/net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,19 +242,20 @@ export type ChatConnection = {
export interface ConnectionInfo {
localPort: number;
ipVersion: 'IPv4' | 'IPv6';
toString: () => string;
}

class ConnectionInfoImpl
implements Wrapper<Native.ConnectionInfo>, ConnectionInfo
implements Wrapper<Native.ChatConnectionInfo>, ConnectionInfo
{
constructor(public _nativeHandle: Native.ConnectionInfo) {}
constructor(public _nativeHandle: Native.ChatConnectionInfo) {}

public get localPort(): number {
return Native.ConnectionInfo_local_port(this);
return Native.ChatConnectionInfo_local_port(this);
}

public get ipVersion(): 'IPv4' | 'IPv6' {
const value = Native.ConnectionInfo_ip_version(this);
const value = Native.ChatConnectionInfo_ip_version(this);
switch (value) {
case 1:
return 'IPv4';
Expand All @@ -264,6 +265,10 @@ class ConnectionInfoImpl
throw new TypeError(`ip type was unexpectedly ${value}`);
}
}

public toString() : string {
return Native.ChatConnectionInfo_description(this)
}
}

export class UnauthenticatedChatConnection implements ChatConnection {
Expand Down
1 change: 1 addition & 0 deletions rust/bridge/ffi/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ include = [
"libsignal-account-keys",
"libsignal-bridge-types",
"libsignal-core",
"libsignal-net",
"libsignal-protocol",
"mediasan-common",
"signal-crypto",
Expand Down
2 changes: 1 addition & 1 deletion rust/bridge/shared/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use std::num::NonZeroU16;

use base64::prelude::{Engine, BASE64_STANDARD};
use libsignal_bridge_macros::bridge_fn;
use libsignal_bridge_types::net::ConnectionInfo;
pub use libsignal_bridge_types::net::{ConnectionManager, Environment, TokioAsyncContext};
use libsignal_net::auth::Auth;
use libsignal_net::chat::ConnectionInfo;

use crate::support::*;
use crate::*;
Expand Down
19 changes: 12 additions & 7 deletions rust/bridge/shared/src/net/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use http::uri::InvalidUri;
use http::{HeaderName, HeaderValue, StatusCode};
use libsignal_bridge_macros::{bridge_fn, bridge_io};
use libsignal_bridge_types::net::chat::*;
use libsignal_bridge_types::net::{ConnectionInfo, ConnectionManager, TokioAsyncContext};
use libsignal_bridge_types::net::{ConnectionManager, TokioAsyncContext};
use libsignal_bridge_types::support::AsType;
use libsignal_net::auth::Auth;
use libsignal_net::chat::{
Expand Down Expand Up @@ -61,13 +61,18 @@ fn HttpRequest_add_header(
}

#[bridge_fn(jni = false)]
fn ConnectionInfo_local_port(connection_info: &ConnectionInfo) -> u16 {
connection_info.0.local_port
fn ChatConnectionInfo_local_port(connection_info: &ChatConnectionInfo) -> u16 {
connection_info.transport_info.local_port
}

#[bridge_fn(jni = false)]
fn ConnectionInfo_ip_version(connection_info: &ConnectionInfo) -> u8 {
connection_info.0.ip_version as u8
fn ChatConnectionInfo_ip_version(connection_info: &ChatConnectionInfo) -> u8 {
connection_info.transport_info.ip_version as u8
}

#[bridge_fn(jni = false)]
fn ChatConnectionInfo_description(connection_info: &ChatConnectionInfo) -> String {
connection_info.to_string()
}

#[bridge_fn]
Expand Down Expand Up @@ -127,7 +132,7 @@ async fn UnauthenticatedChatConnection_disconnect(chat: &UnauthenticatedChatConn
}

#[bridge_fn(jni = false)]
fn UnauthenticatedChatConnection_info(chat: &UnauthenticatedChatConnection) -> ConnectionInfo {
fn UnauthenticatedChatConnection_info(chat: &UnauthenticatedChatConnection) -> ChatConnectionInfo {
chat.info()
}

Expand Down Expand Up @@ -177,7 +182,7 @@ async fn AuthenticatedChatConnection_disconnect(chat: &AuthenticatedChatConnecti
}

#[bridge_fn(jni = false)]
fn AuthenticatedChatConnection_info(chat: &AuthenticatedChatConnection) -> ConnectionInfo {
fn AuthenticatedChatConnection_info(chat: &AuthenticatedChatConnection) -> ChatConnectionInfo {
chat.info()
}

Expand Down
4 changes: 0 additions & 4 deletions rust/bridge/shared/types/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ impl Environment {
}
}

// Trivial wrapper type that cbindgen will treat as opaque.
pub struct ConnectionInfo(pub libsignal_net::infra::ConnectionInfo);
bridge_as_handle!(ConnectionInfo);

const CONNECT_PARAMS: ConnectionOutcomeParams = {
ConnectionOutcomeParams {
age_cutoff: Duration::from_secs(5 * 60),
Expand Down
33 changes: 22 additions & 11 deletions rust/bridge/shared/types/src/net/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,28 @@ use std::time::Duration;

use atomic_take::AtomicTake;
use futures_util::stream::BoxStream;
use futures_util::StreamExt as _;
use futures_util::{FutureExt as _, StreamExt as _};
use http::status::InvalidStatusCode;
use http::uri::{InvalidUri, PathAndQuery};
use http::{HeaderMap, HeaderName, HeaderValue};
use libsignal_net::auth::Auth;
use libsignal_net::chat::{
self, ChatConnection, ChatServiceError, DebugInfo as ChatServiceDebugInfo, Request,
Response as ChatResponse,
self, ChatConnection, ChatServiceError, ConnectionInfo, DebugInfo as ChatServiceDebugInfo,
Request, Response as ChatResponse,
};
use libsignal_net::infra::route::{ConnectionProxyConfig, DirectOrProxyProvider};
use libsignal_net::infra::tcp_ssl::InvalidProxyConfig;
use libsignal_net::infra::Connection;
use libsignal_protocol::Timestamp;
use tokio::sync::{mpsc, oneshot};

use crate::net::{ConnectionInfo, ConnectionManager, TokioAsyncContext};
use crate::net::{ConnectionManager, TokioAsyncContext};
use crate::support::*;
use crate::*;

pub type ChatConnectionInfo = ConnectionInfo;

bridge_as_handle!(ChatConnectionInfo);

enum ChatListenerState {
Inactive(BoxStream<'static, chat::server_requests::ServerEvent>),
Active {
Expand Down Expand Up @@ -251,7 +254,7 @@ enum MaybeChatConnection {

impl UnauthenticatedChatConnection {
pub async fn connect(connection_manager: &ConnectionManager) -> Result<Self, ChatServiceError> {
let inner = establish_chat_connection(connection_manager, None).await?;
let inner = establish_chat_connection("unauthenticated", connection_manager, None).await?;
log::info!("connected unauthenticated chat");
Ok(Self {
inner: MaybeChatConnection::WaitingForListener(
Expand All @@ -268,19 +271,19 @@ impl AuthenticatedChatConnection {
auth: Auth,
receive_stories: bool,
) -> Result<Self, ChatServiceError> {
let pending = establish_chat_connection(
let inner = establish_chat_connection(
"authenticated",
connection_manager,
Some(chat::AuthenticatedChatHeaders {
auth,
receive_stories: receive_stories.into(),
}),
)
.await?;
log::info!("connected authenticated chat");
Ok(Self {
inner: MaybeChatConnection::WaitingForListener(
tokio::runtime::Handle::current(),
pending,
inner,
)
.into(),
})
Expand Down Expand Up @@ -340,13 +343,15 @@ impl<C: AsRef<tokio::sync::RwLock<MaybeChatConnection>> + Sync> BridgeChatConnec

fn info(&self) -> ConnectionInfo {
let guard = self.as_ref().blocking_read();
ConnectionInfo(match &*guard {
let connection_info = match &*guard {
MaybeChatConnection::Running(chat_connection) => chat_connection.connection_info(),
MaybeChatConnection::WaitingForListener(_, pending_chat_connection) => {
pending_chat_connection.connection_info()
}
MaybeChatConnection::TemporarilyEvicted => unreachable!("unobservable state"),
})
};

connection_info.clone()
}
}

Expand All @@ -371,6 +376,7 @@ fn init_listener(connection: &mut MaybeChatConnection, listener: Box<dyn ChatLis
}

async fn establish_chat_connection(
auth_type: &'static str,
connection_manager: &ConnectionManager,
auth: Option<chat::AuthenticatedChatHeaders>,
) -> Result<chat::PendingChatConnection, ChatServiceError> {
Expand Down Expand Up @@ -404,6 +410,7 @@ async fn establish_chat_connection(
} = ws_config;

let chat_connect = &env.chat_domain_config.connect;
log::info!("connecting {auth_type} chat");

ChatConnection::start_connect_with(
connect,
Expand All @@ -423,6 +430,10 @@ async fn establish_chat_connection(
},
auth,
)
.inspect(|r| match r {
Ok(_) => log::info!("successfully connected {auth_type} chat"),
Err(e) => log::warn!("failed to connect {auth_type} chat: {e}"),
})
.await
}

Expand Down
1 change: 1 addition & 0 deletions rust/net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
snow = { workspace = true }
static_assertions = { workspace = true }
strum = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt", "time", "macros"] }
Expand Down
4 changes: 4 additions & 0 deletions rust/net/infra/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use crate::certs;

pub trait LogSafeDisplay: Display {}

/// Vacuous implementation since you can't actually [`Display::fmt`] a
/// [`std::convert::Infallible`].
impl LogSafeDisplay for std::convert::Infallible {}

/// Errors that can occur during transport-level connection establishment.
#[derive(displaydoc::Display, Debug, thiserror::Error)]
pub enum TransportConnectError {
Expand Down
17 changes: 12 additions & 5 deletions rust/net/infra/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::certs::RootCertificates;
use crate::connection_manager::{
MultiRouteConnectionManager, SingleRouteThrottlingConnectionManager,
};
use crate::errors::TransportConnectError;
use crate::errors::{LogSafeDisplay, TransportConnectError};
use crate::host::Host;
use crate::timeouts::{WS_KEEP_ALIVE_INTERVAL, WS_MAX_IDLE_INTERVAL};
use crate::utils::ObservableEvent;
Expand Down Expand Up @@ -68,6 +68,13 @@ impl From<&IpAddr> for IpType {
}
}

impl LogSafeDisplay for IpType {}
impl std::fmt::Display for IpType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}

/// Whether or not to enable domain fronting.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct EnableDomainFronting(pub bool);
Expand Down Expand Up @@ -179,7 +186,7 @@ pub struct ServiceConnectionInfo {
/// remote host.
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ConnectionInfo {
pub struct TransportInfo {
/// The IP address version over which the connection is established.
pub ip_version: IpType,

Expand All @@ -189,8 +196,8 @@ pub struct ConnectionInfo {

/// An established connection.
pub trait Connection {
/// Returns information about the connection.
fn connection_info(&self) -> ConnectionInfo;
/// Returns transport-level information about the connection.
fn transport_info(&self) -> TransportInfo;
}

/// Source for the result of a hostname lookup.
Expand All @@ -215,7 +222,7 @@ pub enum DnsSource {
}

/// Type of the route used for the connection.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, strum::Display)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, strum::Display, strum::IntoStaticStr)]
#[strum(serialize_all = "lowercase")]
pub enum RouteType {
/// Direct connection to the service.
Expand Down
Loading

0 comments on commit 8414cbf

Please sign in to comment.