Define DebianService for host-guest communication

1. Use TCP/IP socket for now
2. IP address reporter uses that
3. Refactoring: remove timeout for shell page because systemd unit for
   ip addr reporter 'requires' ttyd
4. move source files for guest(debian) to guest dir

Bug: 372666638
Test: check if shell shows
Change-Id: Ida94a05de9998a06b4b5c7efebbae97c78617bf4
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 0d13019..97d9373 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -60,6 +60,7 @@
 		fai-setup-storage
 		fdisk
 		make
+		protobuf-compiler
 		python3
 		python3-libcloud
 		python3-marshmallow
@@ -115,7 +116,7 @@
 	wget "${url}" -O "${dst}/files/usr/local/bin/ttyd/AVF"
 	chmod 777 "${dst}/files/usr/local/bin/ttyd/AVF"
 
-	pushd "$(dirname "$0")/forwarder_guest" > /dev/null
+	pushd "$(dirname "$0")/../../guest/forwarder_guest" > /dev/null
 	RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
 		--target "${arch}-unknown-linux-gnu" \
 		--target-dir "${workdir}/forwarder_guest"
@@ -123,6 +124,15 @@
 	cp "${workdir}/forwarder_guest/${arch}-unknown-linux-gnu/debug/forwarder_guest" "${dst}/files/usr/local/bin/forwarder_guest/AVF"
 	chmod 777 "${dst}/files/usr/local/bin/forwarder_guest/AVF"
 	popd > /dev/null
+
+	pushd $(dirname $0)/../../guest/ip_addr_reporter > /dev/null
+	RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc" cargo build \
+		--target aarch64-unknown-linux-gnu \
+		--target-dir ${workdir}/ip_addr_reporter
+	mkdir -p ${dst}/files/usr/local/bin/ip_addr_reporter
+	cp ${workdir}/ip_addr_reporter/aarch64-unknown-linux-gnu/debug/ip_addr_reporter ${dst}/files/usr/local/bin/ip_addr_reporter/AVF
+	chmod 777 ${dst}/files/usr/local/bin/ip_addr_reporter/AVF
+	popd > /dev/null
 }
 
 run_fai() {
diff --git a/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF b/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF
new file mode 100644
index 0000000..7d163fb
--- /dev/null
+++ b/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF
@@ -0,0 +1,13 @@
+[Unit]
+Description=ip report service
+After=syslog.target
+After=network.target
+Requires=ttyd.service
+[Service]
+ExecStart=/usr/local/bin/ip_addr_reporter
+Type=simple
+Restart=on-failure
+User=root
+Group=root
+[Install]
+WantedBy=multi-user.target
diff --git a/build/debian/fai_config/files/etc/systemd/system/vsockip.service/AVF b/build/debian/fai_config/files/etc/systemd/system/vsockip.service/AVF
deleted file mode 100644
index a29020b..0000000
--- a/build/debian/fai_config/files/etc/systemd/system/vsockip.service/AVF
+++ /dev/null
@@ -1,12 +0,0 @@
-[Unit]
-Description=vsock ip service
-After=syslog.target
-After=network.target
-[Service]
-ExecStart=/usr/bin/python3 /usr/local/bin/vsock.py
-Type=simple
-Restart=always
-User=root
-Group=root
-[Install]
-WantedBy=multi-user.target
diff --git a/build/debian/fai_config/files/usr/local/bin/vsock.py/AVF b/build/debian/fai_config/files/usr/local/bin/vsock.py/AVF
deleted file mode 100755
index 292d953..0000000
--- a/build/debian/fai_config/files/usr/local/bin/vsock.py/AVF
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python3
-
-import socket
-
-# Constants for vsock (from linux/vm_sockets.h)
-AF_VSOCK = 40
-SOCK_STREAM = 1
-VMADDR_CID_ANY = -1
-
-def get_local_ip():
-    """Retrieves the first IPv4 address found on the system.
-
-    Returns:
-        str: The local IPv4 address, or '127.0.0.1' if no IPv4 address is found.
-    """
-
-    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-    try:
-        s.connect(('8.8.8.8', 80))
-        ip = s.getsockname()[0]
-    except Exception:
-        ip = '127.0.0.1'
-    finally:
-        s.close()
-    return ip
-
-def main():
-    PORT = 1024
-
-    # Create a vsock socket
-    server_socket = socket.socket(AF_VSOCK, SOCK_STREAM)
-
-    # Bind the socket to the server address
-    server_address = (VMADDR_CID_ANY, PORT)
-    server_socket.bind(server_address)
-
-    # Listen for incoming connections
-    server_socket.listen(1)
-    print(f"VSOCK server listening on port {PORT}...")
-
-    while True:
-        # Accept a connection
-        connection, client_address = server_socket.accept()
-        print(f"Connection from: {client_address}")
-
-        try:
-            # Get the local IP address
-            local_ip = get_local_ip()
-
-            # Send the IP address to the client
-            connection.sendall(local_ip.encode())
-        finally:
-            # Close the connection
-            connection.close()
-
-if __name__ == "__main__":
-    main()
diff --git a/build/debian/fai_config/scripts/AVF/10-systemd b/build/debian/fai_config/scripts/AVF/10-systemd
index d33b92a..09d1bd1 100755
--- a/build/debian/fai_config/scripts/AVF/10-systemd
+++ b/build/debian/fai_config/scripts/AVF/10-systemd
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 chmod +x $target/usr/local/bin/forwarder_guest
+chmod +x $target/usr/local/bin/ip_addr_reporter
 chmod +x $target/usr/local/bin/ttyd
-chmod +x $target/usr/local/bin/vsock.py
 ln -s /etc/systemd/system/ttyd.service $target/etc/systemd/system/multi-user.target.wants/ttyd.service
-ln -s /etc/systemd/system/vsockip.service $target/etc/systemd/system/multi-user.target.wants/vsockip.service
\ No newline at end of file
+ln -s /etc/systemd/system/ip_addr_reporter.service $target/etc/systemd/system/multi-user.target.wants/ip_addr_reporter.service
\ No newline at end of file
diff --git a/build/debian/forwarder_guest/Cargo.toml b/build/debian/forwarder_guest/Cargo.toml
deleted file mode 100644
index e70dcd4..0000000
--- a/build/debian/forwarder_guest/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "forwarder_guest"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-clap = { version = "4.5.19", features = ["derive"] }
-forwarder = { path = "../../../libs/libforwarder" }
-poll_token_derive = "0.1.0"
-remain = "0.2.14"
-vmm-sys-util = "0.12.1"
diff --git a/build/debian/forwarder_guest/src/main.rs b/build/debian/forwarder_guest/src/main.rs
deleted file mode 100644
index 6ebd4ef..0000000
--- a/build/debian/forwarder_guest/src/main.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2024 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Copied from ChromiumOS with relicensing:
-// src/platform2/vm_tools/chunnel/src/bin/chunnel.rs
-
-//! Guest-side stream socket forwarder
-
-use std::fmt;
-use std::result;
-
-use clap::Parser;
-use forwarder::forwarder::{ForwarderError, ForwarderSession};
-use forwarder::stream::{StreamSocket, StreamSocketError};
-use poll_token_derive::PollToken;
-use vmm_sys_util::poll::{PollContext, PollToken};
-
-#[remain::sorted]
-#[derive(Debug)]
-enum Error {
-    ConnectSocket(StreamSocketError),
-    Forward(ForwarderError),
-    PollContextAdd(vmm_sys_util::errno::Error),
-    PollContextDelete(vmm_sys_util::errno::Error),
-    PollContextNew(vmm_sys_util::errno::Error),
-    PollWait(vmm_sys_util::errno::Error),
-}
-
-type Result<T> = result::Result<T, Error>;
-
-impl fmt::Display for Error {
-    #[remain::check]
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Error::*;
-
-        #[remain::sorted]
-        match self {
-            ConnectSocket(e) => write!(f, "failed to connect socket: {}", e),
-            Forward(e) => write!(f, "failed to forward traffic: {}", e),
-            PollContextAdd(e) => write!(f, "failed to add fd to poll context: {}", e),
-            PollContextDelete(e) => write!(f, "failed to delete fd from poll context: {}", e),
-            PollContextNew(e) => write!(f, "failed to create poll context: {}", e),
-            PollWait(e) => write!(f, "failed to wait for poll: {}", e),
-        }
-    }
-}
-
-fn run_forwarder(local_stream: StreamSocket, remote_stream: StreamSocket) -> Result<()> {
-    #[derive(PollToken)]
-    enum Token {
-        LocalStreamReadable,
-        RemoteStreamReadable,
-    }
-    let poll_ctx: PollContext<Token> = PollContext::new().map_err(Error::PollContextNew)?;
-    poll_ctx.add(&local_stream, Token::LocalStreamReadable).map_err(Error::PollContextAdd)?;
-    poll_ctx.add(&remote_stream, Token::RemoteStreamReadable).map_err(Error::PollContextAdd)?;
-
-    let mut forwarder = ForwarderSession::new(local_stream, remote_stream);
-
-    loop {
-        let events = poll_ctx.wait().map_err(Error::PollWait)?;
-
-        for event in events.iter_readable() {
-            match event.token() {
-                Token::LocalStreamReadable => {
-                    let shutdown = forwarder.forward_from_local().map_err(Error::Forward)?;
-                    if shutdown {
-                        poll_ctx
-                            .delete(forwarder.local_stream())
-                            .map_err(Error::PollContextDelete)?;
-                    }
-                }
-                Token::RemoteStreamReadable => {
-                    let shutdown = forwarder.forward_from_remote().map_err(Error::Forward)?;
-                    if shutdown {
-                        poll_ctx
-                            .delete(forwarder.remote_stream())
-                            .map_err(Error::PollContextDelete)?;
-                    }
-                }
-            }
-        }
-        if forwarder.is_shut_down() {
-            return Ok(());
-        }
-    }
-}
-
-#[derive(Parser)]
-/// Flags for running command
-pub struct Args {
-    /// Local socket address
-    #[arg(long)]
-    #[arg(alias = "local")]
-    local_sockaddr: String,
-
-    /// Remote socket address
-    #[arg(long)]
-    #[arg(alias = "remote")]
-    remote_sockaddr: String,
-}
-
-// TODO(b/370897694): Support forwarding for datagram socket
-fn main() -> Result<()> {
-    let args = Args::parse();
-
-    let local_stream = StreamSocket::connect(&args.local_sockaddr).map_err(Error::ConnectSocket)?;
-    let remote_stream =
-        StreamSocket::connect(&args.remote_sockaddr).map_err(Error::ConnectSocket)?;
-
-    run_forwarder(local_stream, remote_stream)
-}
diff --git a/build/debian/port_listener/build.sh b/build/debian/port_listener/build.sh
deleted file mode 100755
index a1d0205..0000000
--- a/build/debian/port_listener/build.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-
-set -e
-
-check_sudo() {
-	if [ "$EUID" -ne 0 ]; then
-		echo "Please run as root."
-		exit
-	fi
-}
-
-install_prerequisites() {
-    apt update
-    apt install --no-install-recommends --assume-yes \
-        bpftool \
-        clang \
-        libbpf-dev \
-        libgoogle-glog-dev \
-        libstdc++-14-dev
-}
-
-build_port_listener() {
-    cp $(dirname $0)/src/* ${workdir}
-    out_dir=${PWD}
-    pushd ${workdir}
-        bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
-        clang \
-            -O2 \
-            -Wall \
-            -target bpf \
-            -g \
-            -c listen_tracker.ebpf.c \
-            -o listen_tracker.ebpf.o
-        bpftool gen skeleton listen_tracker.ebpf.o > listen_tracker.skel.h
-        clang++ \
-            -O2 \
-            -Wall \
-            -lbpf \
-            -lglog \
-            -o port_listener \
-            main.cc
-        cp port_listener ${out_dir}
-    popd
-}
-
-clean_up() {
-	rm -rf ${workdir}
-}
-trap clean_up EXIT
-workdir=$(mktemp -d)
-
-check_sudo
-install_prerequisites
-build_port_listener
diff --git a/build/debian/port_listener/src/common.h b/build/debian/port_listener/src/common.h
deleted file mode 100644
index d6e507c..0000000
--- a/build/debian/port_listener/src/common.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2024 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Copied from ChromiumOS with relicensing:
-// src/platform2/vm_tools/port_listener/common.h
-
-#ifndef VM_TOOLS_PORT_LISTENER_COMMON_H_
-#define VM_TOOLS_PORT_LISTENER_COMMON_H_
-
-enum State {
-    kPortListenerUp,
-    kPortListenerDown,
-};
-
-struct event {
-    enum State state;
-    uint16_t port;
-};
-
-#endif // VM_TOOLS_PORT_LISTENER_COMMON_H_
diff --git a/build/debian/port_listener/src/listen_tracker.ebpf.c b/build/debian/port_listener/src/listen_tracker.ebpf.c
deleted file mode 100644
index 030ded0..0000000
--- a/build/debian/port_listener/src/listen_tracker.ebpf.c
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2024 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Copied from ChromiumOS with relicensing:
-// src/platform2/vm_tools/port_listener/listen_tracker.ebpf.c
-
-// bpf_helpers.h uses types defined here
-#include "vmlinux.h"
-
-#include <bpf/bpf_helpers.h>
-
-#include "common.h"
-
-// For some reason 6.1 doesn't include these symbols in the debug build
-// so they don't get included in vmlinux.h. These features have existed since
-// well before 6.1.
-#define BPF_F_NO_PREALLOC (1U << 0)
-#define BPF_ANY 0
-
-struct {
-    __uint(type, BPF_MAP_TYPE_RINGBUF);
-    __uint(max_entries, 1 << 24);
-} events SEC(".maps");
-
-struct {
-    __uint(type, BPF_MAP_TYPE_HASH);
-    __type(key, struct sock*);
-    __type(value, __u8);
-    __uint(max_entries, 65535);
-    __uint(map_flags, BPF_F_NO_PREALLOC);
-} sockmap SEC(".maps");
-
-const __u8 set_value = 0;
-
-SEC("tp/sock/inet_sock_set_state")
-int tracepoint_inet_sock_set_state(struct trace_event_raw_inet_sock_set_state* ctx) {
-    // We don't support anything other than TCP.
-    if (ctx->protocol != IPPROTO_TCP) {
-        return 0;
-    }
-    struct sock* sk = (struct sock*)ctx->skaddr;
-    // If we're transitioning away from LISTEN but we don't know about this
-    // socket yet then don't report anything.
-    if (ctx->oldstate == BPF_TCP_LISTEN && bpf_map_lookup_elem(&sockmap, &sk) == NULL) {
-        return 0;
-    }
-    // If we aren't transitioning to or from TCP_LISTEN then we don't care.
-    if (ctx->newstate != BPF_TCP_LISTEN && ctx->oldstate != BPF_TCP_LISTEN) {
-        return 0;
-    }
-
-    struct event* ev;
-    ev = bpf_ringbuf_reserve(&events, sizeof(*ev), 0);
-    if (!ev) {
-        return 0;
-    }
-    ev->port = ctx->sport;
-
-    if (ctx->newstate == BPF_TCP_LISTEN) {
-        bpf_map_update_elem(&sockmap, &sk, &set_value, BPF_ANY);
-        ev->state = kPortListenerUp;
-    }
-    if (ctx->oldstate == BPF_TCP_LISTEN) {
-        bpf_map_delete_elem(&sockmap, &sk);
-        ev->state = kPortListenerDown;
-    }
-    bpf_ringbuf_submit(ev, 0);
-
-    return 0;
-}
diff --git a/build/debian/port_listener/src/main.cc b/build/debian/port_listener/src/main.cc
deleted file mode 100644
index b0b0979..0000000
--- a/build/debian/port_listener/src/main.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2024 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Copied from ChromiumOS with relicensing:
-// src/platform2/vm_tools/port_listener/main.cc
-
-#include <bpf/libbpf.h>
-#include <bpf/libbpf_legacy.h>
-#include <glog/logging.h>
-#include <sys/socket.h>
-
-#include <linux/vm_sockets.h> // Needs to come after sys/socket.h
-
-#include <memory>
-#include <unordered_map>
-
-#include "common.h"
-#include "listen_tracker.skel.h"
-
-typedef std::unordered_map<int, int> port_usage_map;
-
-namespace port_listener {
-namespace {
-
-int HandleEvent(void* ctx, void* const data, size_t size) {
-    port_usage_map* map = reinterpret_cast<port_usage_map*>(ctx);
-    const struct event* ev = (struct event*)data;
-
-    switch (ev->state) {
-        case kPortListenerUp:
-            (*map)[ev->port]++;
-            break;
-
-        case kPortListenerDown:
-            if ((*map)[ev->port] > 0) {
-                (*map)[ev->port]--;
-            } else {
-                LOG(INFO) << "Received down event while port count was 0; ignoring";
-            }
-
-            break;
-
-        default:
-            LOG(ERROR) << "Unknown event state " << ev->state;
-    }
-
-    LOG(INFO) << "Listen event: port=" << ev->port << " state=" << ev->state;
-
-    return 0;
-}
-
-typedef std::unique_ptr<struct ring_buffer, decltype(&ring_buffer__free)> ring_buffer_ptr;
-typedef std::unique_ptr<listen_tracker_ebpf, decltype(&listen_tracker_ebpf__destroy)>
-        listen_tracker_ptr;
-
-// BPFProgram tracks the state and resources of the listen_tracker BPF program.
-class BPFProgram {
-public:
-    // Default movable but not copyable.
-    BPFProgram(BPFProgram&& other) = default;
-    BPFProgram(const BPFProgram& other) = delete;
-    BPFProgram& operator=(BPFProgram&& other) = default;
-    BPFProgram& operator=(const BPFProgram& other) = delete;
-
-    // Load loads the listen_tracker BPF program and prepares it for polling. On
-    // error nullptr is returned.
-    static std::unique_ptr<BPFProgram> Load() {
-        auto* skel = listen_tracker_ebpf__open();
-        if (!skel) {
-            PLOG(ERROR) << "Failed to open listen_tracker BPF skeleton";
-            return nullptr;
-        }
-        listen_tracker_ptr skeleton(skel, listen_tracker_ebpf__destroy);
-
-        int err = listen_tracker_ebpf__load(skeleton.get());
-        if (err) {
-            PLOG(ERROR) << "Failed to load listen_tracker BPF program";
-            return nullptr;
-        }
-
-        auto map = std::make_unique<port_usage_map>();
-        auto* rb = ring_buffer__new(bpf_map__fd(skel->maps.events), HandleEvent, map.get(), NULL);
-        if (!rb) {
-            PLOG(ERROR) << "Failed to open ring buffer for listen_tracker";
-            return nullptr;
-        }
-        ring_buffer_ptr ringbuf(rb, ring_buffer__free);
-
-        err = listen_tracker_ebpf__attach(skeleton.get());
-        if (err) {
-            PLOG(ERROR) << "Failed to attach listen_tracker";
-            return nullptr;
-        }
-
-        return std::unique_ptr<BPFProgram>(
-                new BPFProgram(std::move(skeleton), std::move(ringbuf), std::move(map)));
-    }
-
-    // Poll waits for the listen_tracker BPF program to post a new event to the
-    // ring buffer. BPFProgram handles integrating this new event into the
-    // port_usage map and callers should consult port_usage() after Poll returns
-    // for the latest data.
-    const bool Poll() {
-        int err = ring_buffer__poll(rb_.get(), -1);
-        if (err < 0) {
-            LOG(ERROR) << "Error polling ring buffer ret=" << err;
-            return false;
-        }
-
-        return true;
-    }
-
-    const port_usage_map& port_usage() { return *port_usage_; }
-
-private:
-    BPFProgram(listen_tracker_ptr&& skeleton, ring_buffer_ptr&& rb,
-               std::unique_ptr<port_usage_map>&& port_usage)
-          : skeleton_(std::move(skeleton)),
-            rb_(std::move(rb)),
-            port_usage_(std::move(port_usage)) {}
-
-    listen_tracker_ptr skeleton_;
-    ring_buffer_ptr rb_;
-    std::unique_ptr<port_usage_map> port_usage_;
-};
-
-} // namespace
-} // namespace port_listener
-
-int main(int argc, char** argv) {
-    google::InitGoogleLogging(argv[0]);
-    libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
-
-    // Load our BPF program.
-    auto program = port_listener::BPFProgram::Load();
-    if (program == nullptr) {
-        LOG(ERROR) << "Failed to load BPF program";
-        return EXIT_FAILURE;
-    }
-
-    // main loop: poll for listen updates
-    for (;;) {
-        if (!program->Poll()) {
-            LOG(ERROR) << "Failure while polling BPF program";
-            return EXIT_FAILURE;
-        }
-        // port_usage will be updated with the latest usage data
-
-        for (auto it : program->port_usage()) {
-            if (it.second <= 0) {
-                continue;
-            }
-            // TODO(b/340126051): Add listening TCP4 ports.
-        }
-        // TODO(b/340126051): Notify port information to the guest agent.
-    }
-}