1

I am having issues receiving data from the child process.

To send a string to the child process you write to FD3 and it will output the result to FD4.

The child process runs fine, and if it couldn't write to FD4, the process would not start correctly, so FD4 has to be available but I just don't know why no output is given.

My initial thoughts is when sending the string (to FD3) it wasn't null byte terminating therefore not receiving the string correctly (and then not sending anything back on FD4) but I am sure I am doing it correctly.

I have tested writing to FD4 within the child process manually and the parent receives the output.

use nix::fcntl::FcntlArg::{F_SETFD};
use nix::fcntl::{fcntl, open, FdFlag, OFlag};
use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
use nix::sys::stat::Mode;
use nix::unistd::{close, dup2, execvp, fork, pipe, read, write, ForkResult};
use std::ffi::CString;
use std::os::unix::io::RawFd;
use std::process::abort;

fn main() {
    let input_socket: (RawFd, RawFd) = create_socket();
    let output_socket: (RawFd, RawFd) = create_socket();

    match fork() {
        Ok(ForkResult::Parent { child, .. }) => {
            println!("Child PID: {}", child);

            close(input_socket.1).unwrap();
            close(output_socket.1).unwrap();

            let test = r#"{"id":0,"method":"Target.getTargets"}\0"#;
            write(input_socket.0, test.as_bytes()).expect("unable to write");

            let mut buf = [0; 64];
            read(output_socket.0, &mut buf).unwrap();
            println!("BUFFER: {:#?}", std::str::from_utf8(&buf).unwrap());
        }
        Ok(ForkResult::Child) => {
            setup_child(input_socket.1, output_socket.1);
            abort()
        }
        Err(err) => { println!("{}", err); abort()},
    }
}

#[cfg(any(
    target_os = "android",
    target_os = "dragonfly",
    target_os = "emscripten",
    target_os = "freebsd",
    target_os = "linux",
    target_os = "netbsd",
    target_os = "openbsd"
))]
fn create_socket() -> (RawFd, RawFd) {
    socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::SOCK_CLOEXEC,
    )
    .unwrap()
}

#[cfg(any(target_os = "ios", target_os = "macos"))]
fn create_socket() -> (RawFd, RawFd) {
    let socket = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();
    fcntl(socket.0, F_SETFD(FdFlag::FD_CLOEXEC)).unwrap();
    fcntl(socket.1, F_SETFD(FdFlag::FD_CLOEXEC)).unwrap();
    socket
}

fn setup_child(input: RawFd, output: RawFd) {
    let _input: RawFd = dup2(input, 3).unwrap();
    let _output: RawFd = dup2(output, 4).unwrap();

    let file = CString::new("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome").unwrap();

    let arg1 = CString::new("--remote-debugging-pipe").unwrap();
    let arg2 = CString::new("--enable-logging=stderr").unwrap();
    let args = vec![arg1.as_c_str(),arg2.as_c_str()];

    let _res = execvp(&file, &args).unwrap();
}

This is the open FDs for the child process: lsof -p 14620

COMMAND PID  USER   FD     TYPE DEVICE                  SIZE/OFF                  NODE NAME
Chrome 14620 tom    0      PIPE 0xcafab653bf79be56      16384                     ->0xfc41206e43b6bb9d
Chrome 14620 tom    1      PIPE 0x71c3c6a8bffbf5ad      16384                     ->0x587f975b5bfd4499
Chrome 14620 tom    2      PIPE 0x71c3c6a8bffbf5ad      16384                     ->0x587f975b5bfd4499
Chrome 14620 tom    3u     unix 0x36cd3ac44c49d68d        0t0                     ->0x36cd3ac44c49f2ad
Chrome 14620 tom    4u     unix 0x36cd3ac44c49dc05        0t0                     ->0x36cd3ac44c49f9b5

UPDATE

I found the issue, for some reason the first argument when running the chrome process was being ignored?? So when I place any other argument as the first in the list chrome actually starts up the remote debugging. Weird issue!

When I run the chrome process in terminal with --remote-debugging-pipe as the first argument it works fine too, so why does it happen when i use: execvp(&file, &args)

James
  • 693
  • 1
  • 13
  • 27

1 Answers1

0

The problem is how I am running the process.

execvp(&file, &args) requires the first arg to be the file location. Thanks to: source

Changing this code makes everything run as expected:

let args = vec![file.as_c_str(), arg1.as_c_str(),arg2.as_c_str()];
James
  • 693
  • 1
  • 13
  • 27