blob: e43ce9ca276ade321a2825a75c8963d5883bfc35 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Implements just enough of fuchsia.posix.socket.Provider and fuchsia.posix.socket.StreamSocket
//! to bind a TcpListener and call getsockopt on it. Handles the TCP_KEEPINTVL and TCP_USER_TIMEOUT
//! options.
use {
fidl::endpoints::{create_request_stream, RequestStream as _},
fidl_fuchsia_io::{NodeInfo, StreamSocket},
fidl_fuchsia_posix_socket::{
BaseSocketMarker, ProviderRequest, ProviderRequestStream, StreamSocketRequest,
StreamSocketRequestStream,
},
fuchsia_async as fasync,
fuchsia_component::server::ServiceFs,
fuchsia_zircon as zx,
futures::StreamExt as _,
};
const TCP_KEEPCNT_OPTION_VALUE: i32 = -11;
const TCP_KEEPINTVL_OPTION_VALUE: i32 = -12;
const TCP_USER_TIMEOUT_OPTION_VALUE: i32 = -13;
#[fasync::run_singlethreaded]
async fn main() {
let mut fs = ServiceFs::new();
fs.dir("svc").add_fidl_service(move |stream| fasync::spawn(serve_provider(stream)));
fs.take_and_serve_directory_handle().unwrap();
let () = fs.collect().await;
}
async fn serve_provider(mut stream: ProviderRequestStream) {
while let Some(event) = stream.next().await {
match event.unwrap() {
ProviderRequest::Socket2 { responder, .. } => {
let (client, server) = create_request_stream::<BaseSocketMarker>().unwrap();
fasync::spawn(serve_stream_socket(server.cast_stream()));
responder.send(&mut Ok(client)).unwrap();
}
r => {
panic!("Unhandled ProviderRequest: {:?}", r);
}
}
}
}
async fn serve_stream_socket(mut stream: StreamSocketRequestStream) {
while let Some(event) = stream.next().await {
match event.unwrap() {
StreamSocketRequest::Describe { responder } => {
let (s0, _) = zx::Socket::create(zx::SocketOpts::STREAM).unwrap();
responder.send(&mut NodeInfo::StreamSocket(StreamSocket { socket: s0 })).unwrap();
}
StreamSocketRequest::SetSockOpt { responder, .. } => {
responder.send(&mut Ok(())).unwrap();
}
StreamSocketRequest::Bind { responder, .. } => {
responder.send(&mut Ok(())).unwrap();
}
StreamSocketRequest::Listen { responder, .. } => {
responder.send(&mut Ok(())).unwrap();
}
StreamSocketRequest::GetSockOpt { level, optname, responder, .. } => {
assert_eq!(i32::from(level), libc::IPPROTO_TCP);
let option_value = match i32::from(optname) {
libc::TCP_KEEPCNT => TCP_KEEPCNT_OPTION_VALUE,
libc::TCP_KEEPINTVL => TCP_KEEPINTVL_OPTION_VALUE,
libc::TCP_USER_TIMEOUT => TCP_USER_TIMEOUT_OPTION_VALUE,
o => panic!("Unhandled GetSockOpt option name: {}", o),
};
responder.send(&mut Ok(option_value.to_le_bytes().to_vec())).unwrap();
}
r => {
panic!("Unhandled StreamSocketRequest: {:?}", r);
}
}
}
}