summary refs log tree commit diff
path: root/src/ext/wl_main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/wl_main.rs')
-rw-r--r--src/ext/wl_main.rs187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/ext/wl_main.rs b/src/ext/wl_main.rs
new file mode 100644
index 0000000..0b8d6a3
--- /dev/null
+++ b/src/ext/wl_main.rs
@@ -0,0 +1,187 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env::args_os;
+use std::fs::remove_file;
+use std::io::{stdout, IoSlice, Write};
+use std::os::unix::prelude::*;
+use std::process;
+
+use devices::virtio::{remote, virtualized};
+use sys_util::net::{UnixSeqpacket, UnixSeqpacketListener};
+use sys_util::{PollContext, PollToken, ScmSocket};
+
+fn main() {
+    // Create and display the incoming socket.
+    let mut path = std::env::var_os("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing");
+    path.push("/crosvm_wl-");
+    path.push(process::id().to_string());
+    path.push(".sock");
+    let _ = remove_file(&path);
+    let server = UnixSeqpacketListener::bind(&path).expect("failed to create socket");
+    match stdout().write_all(path.as_bytes()) {
+        Ok(()) => println!(),
+        Err(e) => eprintln!("{}", e),
+    }
+
+    // Receive connection from crosvm.
+    let conn = server.accept().expect("accept failed");
+    let client_virtio_device_msg_socket: msg_socket2::Socket<remote::Response, remote::Request> =
+        msg_socket2::Socket::new(conn);
+
+    let (memory_params, client_vm_control_socket) = match client_virtio_device_msg_socket.recv() {
+        Ok(remote::Request::Create {
+            memory_params,
+            vm_control_socket,
+        }) => (memory_params, vm_control_socket.owned()),
+
+        Ok(msg) => panic!("unexpected message: {:?}", msg),
+        Err(e) => panic!("recv error: {}", e),
+    };
+
+    let server_virtio_device_socket_path = args_os().nth(1).expect("missing server socket path");
+    let server_virtio_device_socket =
+        UnixSeqpacket::connect(server_virtio_device_socket_path).expect("connect failed");
+    let server_virtio_device_msg_socket: msg_socket2::Socket<
+        virtualized::Request,
+        virtualized::Response,
+    > = msg_socket2::Socket::new(server_virtio_device_socket);
+
+    let (server_vm_control_socket, ext_vm_control_socket) =
+        UnixSeqpacket::pair().expect("pair failed");
+
+    server_virtio_device_msg_socket
+        .send(virtualized::Request::Create {
+            memory_params,
+            ext_socket: ext_vm_control_socket, // TODO: proxy rather than passing through
+        })
+        .expect("send failed");
+
+    #[derive(Debug, PollToken)]
+    enum Token {
+        ClientVirtioDevice,
+        ClientVmControl,
+        ServerVirtioDevice,
+        ServerVmControl,
+    }
+
+    let poll_ctx = match PollContext::build_with(&[
+        (&client_virtio_device_msg_socket, Token::ClientVirtioDevice),
+        (&client_vm_control_socket, Token::ClientVmControl),
+        (&server_virtio_device_msg_socket, Token::ServerVirtioDevice),
+        (&server_vm_control_socket, Token::ServerVmControl),
+    ]) {
+        Ok(pc) => pc,
+        Err(e) => panic!("failed creating PollContext: {}", e),
+    };
+
+    loop {
+        let events = match poll_ctx.wait() {
+            Ok(v) => v,
+            Err(e) => panic!("failed polling for events: {}", e),
+        };
+
+        for event in &events {
+            match event.token() {
+                Token::ClientVirtioDevice => {
+                    let msg = match dbg!(client_virtio_device_msg_socket.recv()) {
+                        Ok(remote::Request::DebugLabel) => virtualized::Request::DebugLabel,
+                        Ok(remote::Request::DeviceType) => virtualized::Request::DeviceType,
+                        Ok(remote::Request::QueueMaxSizes) => virtualized::Request::QueueMaxSizes,
+                        Ok(remote::Request::Features) => virtualized::Request::Features,
+                        Ok(remote::Request::AckFeatures(value)) => {
+                            virtualized::Request::AckFeatures(value)
+                        }
+                        Ok(remote::Request::ReadConfig { offset, len }) => {
+                            virtualized::Request::ReadConfig { offset, len }
+                        }
+                        Ok(remote::Request::WriteConfig { offset, data }) => {
+                            virtualized::Request::WriteConfig { offset, data }
+                        }
+                        Ok(remote::Request::Activate {
+                            shm,
+                            interrupt,
+                            interrupt_resample_evt,
+                            queues,
+                            queue_evts,
+                        }) => virtualized::Request::Activate {
+                            shm,
+                            interrupt,
+                            interrupt_resample_evt,
+                            queues,
+                            queue_evts,
+                        },
+                        Ok(remote::Request::Reset) => virtualized::Request::Reset,
+                        Ok(remote::Request::GetDeviceBars(address)) => {
+                            virtualized::Request::GetDeviceBars(address)
+                        }
+                        Ok(remote::Request::GetDeviceCaps) => virtualized::Request::GetDeviceCaps,
+                        Ok(remote::Request::Kill) => virtualized::Request::Kill,
+
+                        Ok(req @ remote::Request::Create { .. }) => {
+                            panic!("unexpected message: {:?}", req)
+                        }
+
+                        Err(e) => panic!("recv failed: {}", e),
+                    };
+
+                    if let Err(e) = server_virtio_device_msg_socket.send(msg) {
+                        panic!("send failed: {}", e);
+                    }
+                }
+
+                Token::ClientVmControl => {
+                    let (buf, fds) = client_vm_control_socket
+                        .recv_as_vec_with_fds()
+                        .expect("recv failed");
+                    server_vm_control_socket
+                        .send_with_fds(&[IoSlice::new(&buf)], &fds[..])
+                        .expect("send failed");
+                }
+
+                Token::ServerVirtioDevice => {
+                    let msg = match server_virtio_device_msg_socket.recv() {
+                        Ok(virtualized::Response::DebugLabel(label)) => {
+                            remote::Response::DebugLabel(label)
+                        }
+                        Ok(virtualized::Response::DeviceType(typ)) => {
+                            remote::Response::DeviceType(typ)
+                        }
+                        Ok(virtualized::Response::Features(value)) => {
+                            remote::Response::Features(value)
+                        }
+                        Ok(virtualized::Response::GetDeviceBars(bars)) => {
+                            remote::Response::GetDeviceBars(bars)
+                        }
+                        Ok(virtualized::Response::GetDeviceCaps(caps)) => {
+                            remote::Response::GetDeviceCaps(caps)
+                        }
+                        Ok(virtualized::Response::Kill) => remote::Response::Kill,
+                        Ok(virtualized::Response::QueueMaxSizes(sizes)) => {
+                            remote::Response::QueueMaxSizes(sizes)
+                        }
+                        Ok(virtualized::Response::ReadConfig(config)) => {
+                            remote::Response::ReadConfig(config)
+                        }
+                        Ok(virtualized::Response::Reset(result)) => remote::Response::Reset(result),
+                        Err(e) => panic!("recv failed: {}", e),
+                    };
+
+                    if let Err(e) = client_virtio_device_msg_socket.send(dbg!(msg)) {
+                        panic!("send failed: {}", e);
+                    }
+                }
+
+                Token::ServerVmControl => {
+                    let (buf, fds) = server_vm_control_socket
+                        .recv_as_vec_with_fds()
+                        .expect("recv failed");
+                    client_vm_control_socket
+                        .send_with_fds(&[IoSlice::new(&buf)], &fds[..])
+                        .expect("send failed");
+                }
+            }
+        }
+    }
+}