Repository: bitcoin/bitcoin
File: src/ipc/process.cpp (C++)

Code before:
    bool checkSpawned(int argc, char* argv[], int& fd) override
    {
        // If this process was not started with a single -ipcfd argument, it is
        // not a process spawned by the spawn() call above, so return false and
        // do not try to serve requests.
        if (argc != 3 || strcmp(argv[1], "-ipcfd") != 0) {
            return false;
        }
        // If a single -ipcfd argument was provided, return true and get the
        // file descriptor so Protocol::serve() can be called to handle
        // requests from the parent process. The -ipcfd argument is not valid
        // in combination with other arguments because the parent process
        // should be able to control the child process through the IPC protocol
        // without passing information out of band.
        if (!ParseInt32(argv[2], &fd)) {
            throw std::runtime_error(strprintf("Invalid -ipcfd number '%s'", argv[2]));
        }
        return true;
    }
    int connect(const fs::path& data_dir,
                const std::string& dest_exe_name,
                std::string& address,
                std::string& error) override;
    int bind(const fs::path& data_dir, const std::string& exe_name, std::string& address, std::string& error) override;
};

static bool ParseAddress(std::string& address,
                  const fs::path& data_dir,
                  const std::string& dest_exe_name,
                  struct sockaddr_un& addr,
                  std::string& error)
{
    if (address.compare(0, 4, "unix") == 0 && (address.size() == 4 || address[4] == ':')) {
        fs::path path;
        if (address.size() <= 5) {
            path = data_dir / fs::PathFromString(strprintf("%s.sock", RemovePrefixView(dest_exe_name, "bitcoin-")));
        } else {
            path = data_dir / fs::PathFromString(address.substr(5));
        }
        std::string path_str = fs::PathToString(path);
        if (path_str.size() >= sizeof(addr.sun_path)) {
            error = strprintf("Address '%s' path '%s' exceeded maximum socket path length", address, fs::quoted(fs::PathToString(path)));
            return false;
        }
        memset(&addr, 0, sizeof(addr));
        addr.sun_family = AF_UNIX;
        strncpy(addr.sun_path, path_str.c_str(), sizeof(addr.sun_path)-1);
        address = strprintf("unix:%s", path_str);
        return true;
    }


Review comment (suggestion):
52917ad4be1ca574543e854fdc154e88d65ce57f: this could use a test.

Or maybe we can introduce something akin to `CNetAddr` for socket addresses? Fortunately this input can only be provided by the user, so we don't have to be overzealous about sanitising.

Code after:
    bool checkSpawned(int argc, char* argv[], int& fd) override
    {
        // If this process was not started with a single -ipcfd argument, it is
        // not a process spawned by the spawn() call above, so return false and
        // do not try to serve requests.
        if (argc != 3 || strcmp(argv[1], "-ipcfd") != 0) {
            return false;
        }
        // If a single -ipcfd argument was provided, return true and get the
        // file descriptor so Protocol::serve() can be called to handle
        // requests from the parent process. The -ipcfd argument is not valid
        // in combination with other arguments because the parent process
        // should be able to control the child process through the IPC protocol
        // without passing information out of band.
        if (!ParseInt32(argv[2], &fd)) {
            throw std::runtime_error(strprintf("Invalid -ipcfd number '%s'", argv[2]));
        }
        return true;
    }
    int connect(const fs::path& data_dir,
                const std::string& dest_exe_name,
                std::string& address) override;
    int bind(const fs::path& data_dir, const std::string& exe_name, std::string& address) override;
};

static bool ParseAddress(std::string& address,
                  const fs::path& data_dir,
                  const std::string& dest_exe_name,
                  struct sockaddr_un& addr,
                  std::string& error)
{
    if (address.compare(0, 4, "unix") == 0 && (address.size() == 4 || address[4] == ':')) {
        fs::path path;
        if (address.size() <= 5) {
            path = data_dir / fs::PathFromString(strprintf("%s.sock", RemovePrefixView(dest_exe_name, "bitcoin-")));
        } else {
            path = data_dir / fs::PathFromString(address.substr(5));
        }
        std::string path_str = fs::PathToString(path);
        address = strprintf("unix:%s", path_str);
        if (path_str.size() >= sizeof(addr.sun_path)) {
            error = strprintf("Unix address path %s exceeded maximum socket path length", fs::quoted(fs::PathToString(path)));
            return false;
        }
        memset(&addr, 0, sizeof(addr));
        addr.sun_family = AF_UNIX;
        strncpy(addr.sun_path, path_str.c_str(), sizeof(addr.sun_path)-1);
        return true;
    }

    error = strprintf("Unrecognized address '%s'", address);