Separate headers into cpp source files

This commit is contained in:
Jackson Coxson
2025-08-14 17:02:58 -06:00
parent 54caafb4da
commit a16405f011
24 changed files with 940 additions and 616 deletions

View File

@@ -0,0 +1,8 @@
// Jackson Coxson
#ifndef IDEVICE_BINDINGS_H
#define IDEVICE_BINDINGS_H
extern "C" {
#include <idevice.h> // this file is generated by bindgen
}
#endif

View File

@@ -0,0 +1,21 @@
// Jackson Coxson
#ifndef IDEVICE_FFI
#define IDEVICE_FFI
#include <idevice++/bindings.hpp>
#include <string>
namespace IdeviceFFI {
class FfiError {
public:
int32_t code = 0;
std::string message;
FfiError(const IdeviceFfiError* err);
FfiError();
explicit operator bool() const { return code != 0; }
};
} // namespace IdeviceFFI
#endif

View File

@@ -0,0 +1,63 @@
// Jackson Coxson
#ifndef IDEVICE_CPP
#define IDEVICE_CPP
#include <idevice++/ffi.hpp>
#include <idevice++/pairing_file.hpp>
#include <optional>
#include <string>
#if defined(_WIN32) && !defined(__MINGW32__)
// MSVC doesn't have BSD u_int* types
using u_int8_t = std::uint8_t;
using u_int16_t = std::uint16_t;
using u_int32_t = std::uint32_t;
using u_int64_t = std::uint64_t;
#endif
namespace IdeviceFFI {
// Generic “bind a free function” deleter
template <class T, void (*FreeFn)(T*)> struct FnDeleter {
void operator()(T* p) const noexcept {
if (p)
FreeFn(p);
}
};
using IdevicePtr = std::unique_ptr<IdeviceHandle, FnDeleter<IdeviceHandle, idevice_free>>;
class Idevice {
public:
static std::optional<Idevice>
create(IdeviceSocketHandle* socket, const std::string& label, FfiError& err);
static std::optional<Idevice>
create_tcp(const sockaddr* addr, socklen_t addr_len, const std::string& label, FfiError& err);
// Methods
std::optional<std::string> get_type(FfiError& err) const;
bool rsd_checkin(FfiError& err);
bool start_session(const PairingFile& pairing_file, FfiError& err);
// Ownership/RAII
~Idevice() noexcept = default;
Idevice(Idevice&&) noexcept = default;
Idevice& operator=(Idevice&&) noexcept = default;
Idevice(const Idevice&) = delete;
Idevice& operator=(const Idevice&) = delete;
static Idevice adopt(IdeviceHandle* h) noexcept { return Idevice(h); }
// Accessor
IdeviceHandle* raw() const noexcept { return handle_.get(); }
IdeviceHandle* release() noexcept { return handle_.release(); }
private:
explicit Idevice(IdeviceHandle* h) noexcept : handle_(h) {}
IdevicePtr handle_{};
};
} // namespace IdeviceFFI
#endif

View File

@@ -0,0 +1,45 @@
#pragma once
#include <cstdint>
#include <idevice++/bindings.hpp>
#include <idevice++/ffi.hpp>
#include <idevice++/provider.hpp>
#include <memory>
#include <optional>
#include <string>
namespace IdeviceFFI {
using LockdownPtr =
std::unique_ptr<LockdowndClientHandle, FnDeleter<LockdowndClientHandle, lockdownd_client_free>>;
class Lockdown {
public:
// Factory: connect via Provider
static std::optional<Lockdown> connect(Provider& provider, FfiError& err);
// Factory: wrap an existing Idevice socket (consumes it on success)
static std::optional<Lockdown> from_socket(Idevice&& socket, FfiError& err);
// Ops
bool start_session(const PairingFile& pf, FfiError& err);
std::optional<std::pair<uint16_t, bool>> start_service(const std::string& identifier,
FfiError& err);
std::optional<plist_t> get_value(const char* key, const char* domain, FfiError& err);
// RAII / moves
~Lockdown() noexcept = default;
Lockdown(Lockdown&&) noexcept = default;
Lockdown& operator=(Lockdown&&) noexcept = default;
Lockdown(const Lockdown&) = delete;
Lockdown& operator=(const Lockdown&) = delete;
LockdowndClientHandle* raw() const noexcept { return handle_.get(); }
static Lockdown adopt(LockdowndClientHandle* h) noexcept { return Lockdown(h); }
private:
explicit Lockdown(LockdowndClientHandle* h) noexcept : handle_(h) {}
LockdownPtr handle_{};
};
} // namespace IdeviceFFI

View File

@@ -0,0 +1,44 @@
// Jackson Coxson
#ifndef IDEVICE_PAIRING_FILE
#define IDEVICE_PAIRING_FILE
#pragma once
#include <idevice++/ffi.hpp>
#include <optional>
#include <string>
#include <vector>
namespace IdeviceFFI {
struct PairingFileDeleter {
void operator()(IdevicePairingFile* p) const noexcept;
};
using PairingFilePtr = std::unique_ptr<IdevicePairingFile, PairingFileDeleter>;
class PairingFile {
public:
static std::optional<PairingFile> read(const std::string& path, FfiError& err);
static std::optional<PairingFile> from_bytes(const uint8_t* data, size_t size, FfiError& err);
~PairingFile() noexcept = default; // unique_ptr handles destruction
PairingFile(const PairingFile&) = delete;
PairingFile& operator=(const PairingFile&) = delete;
PairingFile(PairingFile&&) noexcept = default; // move is correct by default
PairingFile& operator=(PairingFile&&) noexcept = default;
std::optional<std::vector<uint8_t>> serialize(FfiError& err) const;
explicit PairingFile(IdevicePairingFile* ptr) noexcept : ptr_(ptr) {}
IdevicePairingFile* raw() const noexcept { return ptr_.get(); }
IdevicePairingFile* release() noexcept { return ptr_.release(); }
private:
PairingFilePtr ptr_{}; // owns the handle
};
} // namespace IdeviceFFI
#endif

View File

@@ -0,0 +1,49 @@
// Jackson Coxson
#pragma once
#include <cstdint>
#include <idevice++/bindings.hpp>
#include <idevice++/ffi.hpp>
#include <idevice++/usbmuxd.hpp>
#include <optional>
#include <string>
namespace IdeviceFFI {
class FfiError;
class PairingFile; // has: IdevicePairingFile* raw() const; void release_on_success();
class UsbmuxdAddr; // has: UsbmuxdAddrHandle* raw() const; void release_on_success();
using ProviderPtr =
std::unique_ptr<IdeviceProviderHandle, FnDeleter<IdeviceProviderHandle, idevice_provider_free>>;
class Provider {
public:
static std::optional<Provider> tcp_new(const idevice_sockaddr* ip,
PairingFile&& pairing,
const std::string& label,
FfiError& err);
static std::optional<Provider> usbmuxd_new(UsbmuxdAddr&& addr,
uint32_t tag,
const std::string& udid,
uint32_t device_id,
const std::string& label,
FfiError& err);
~Provider() noexcept = default;
Provider(Provider&&) noexcept = default;
Provider& operator=(Provider&&) noexcept = default;
Provider(const Provider&) = delete;
Provider& operator=(const Provider&) = delete;
IdeviceProviderHandle* raw() const noexcept { return handle_.get(); }
static Provider adopt(IdeviceProviderHandle* h) noexcept { return Provider(h); }
IdeviceProviderHandle* release() noexcept { return handle_.release(); }
private:
explicit Provider(IdeviceProviderHandle* h) noexcept : handle_(h) {}
ProviderPtr handle_{};
};
} // namespace IdeviceFFI

View File

@@ -0,0 +1,127 @@
// Jackson Coxson
#ifndef IDEVICE_USBMUXD_HPP
#define IDEVICE_USBMUXD_HPP
#include <cstdint>
#include <idevice++/idevice.hpp>
#include <idevice++/pairing_file.hpp>
#include <optional>
#include <string>
#include <vector>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#endif
namespace IdeviceFFI {
using AddrPtr =
std::unique_ptr<UsbmuxdAddrHandle, FnDeleter<UsbmuxdAddrHandle, idevice_usbmuxd_addr_free>>;
using DevicePtr = std::unique_ptr<UsbmuxdDeviceHandle,
FnDeleter<UsbmuxdDeviceHandle, idevice_usbmuxd_device_free>>;
using ConnectionPtr =
std::unique_ptr<UsbmuxdConnectionHandle,
FnDeleter<UsbmuxdConnectionHandle, idevice_usbmuxd_connection_free>>;
class UsbmuxdAddr {
public:
static std::optional<UsbmuxdAddr>
tcp_new(const sockaddr* addr, socklen_t addr_len, FfiError& err);
#if defined(__unix__) || defined(__APPLE__)
static std::optional<UsbmuxdAddr> unix_new(const std::string& path, FfiError& err);
#endif
static UsbmuxdAddr default_new();
~UsbmuxdAddr() noexcept = default;
UsbmuxdAddr(UsbmuxdAddr&&) noexcept = default;
UsbmuxdAddr& operator=(UsbmuxdAddr&&) noexcept = default;
UsbmuxdAddr(const UsbmuxdAddr&) = delete;
UsbmuxdAddr& operator=(const UsbmuxdAddr&) = delete;
UsbmuxdAddrHandle* raw() const noexcept { return handle_.get(); }
UsbmuxdAddrHandle* release() noexcept { return handle_.release(); }
static UsbmuxdAddr adopt(UsbmuxdAddrHandle* h) noexcept { return UsbmuxdAddr(h); }
private:
explicit UsbmuxdAddr(UsbmuxdAddrHandle* h) noexcept : handle_(h) {}
AddrPtr handle_{};
};
class UsbmuxdConnectionType {
public:
enum class Value : uint8_t { Usb = 1, Network = 2, Unknown = 3 };
explicit UsbmuxdConnectionType(uint8_t v) : _value(static_cast<Value>(v)) {}
std::string to_string() const; // body in .cpp
Value value() const noexcept { return _value; }
bool operator==(Value other) const noexcept { return _value == other; }
private:
Value _value{Value::Unknown};
};
class UsbmuxdDevice {
public:
~UsbmuxdDevice() noexcept = default;
UsbmuxdDevice(UsbmuxdDevice&&) noexcept = default;
UsbmuxdDevice& operator=(UsbmuxdDevice&&) noexcept = default;
UsbmuxdDevice(const UsbmuxdDevice&) = delete;
UsbmuxdDevice& operator=(const UsbmuxdDevice&) = delete;
static UsbmuxdDevice adopt(UsbmuxdDeviceHandle* h) noexcept { return UsbmuxdDevice(h); }
UsbmuxdDeviceHandle* raw() const noexcept { return handle_.get(); }
std::optional<std::string> get_udid() const;
std::optional<uint32_t> get_id() const;
std::optional<UsbmuxdConnectionType> get_connection_type() const;
private:
explicit UsbmuxdDevice(UsbmuxdDeviceHandle* h) noexcept : handle_(h) {}
DevicePtr handle_{};
friend class UsbmuxdConnection;
};
class PairingFile;
class UsbmuxdConnection {
public:
static std::optional<UsbmuxdConnection>
tcp_new(const idevice_sockaddr* addr, idevice_socklen_t addr_len, uint32_t tag, FfiError& err);
#if defined(__unix__) || defined(__APPLE__)
static std::optional<UsbmuxdConnection>
unix_new(const std::string& path, uint32_t tag, FfiError& err);
#endif
static std::optional<UsbmuxdConnection> default_new(uint32_t tag, FfiError& err);
~UsbmuxdConnection() noexcept = default;
UsbmuxdConnection(UsbmuxdConnection&&) noexcept = default;
UsbmuxdConnection& operator=(UsbmuxdConnection&&) noexcept = default;
UsbmuxdConnection(const UsbmuxdConnection&) = delete;
UsbmuxdConnection& operator=(const UsbmuxdConnection&) = delete;
std::optional<std::vector<UsbmuxdDevice>> get_devices(FfiError& err) const;
std::optional<std::string> get_buid(FfiError& err) const;
std::optional<PairingFile> get_pair_record(const std::string& udid, FfiError& err);
std::optional<Idevice>
connect_to_device(uint32_t device_id, uint16_t port, const std::string& path, FfiError& err) &&;
std::optional<Idevice>
connect_to_device(uint32_t, uint16_t, const std::string&, FfiError&) & = delete;
std::optional<Idevice>
connect_to_device(uint32_t, uint16_t, const std::string&, FfiError&) const& = delete;
UsbmuxdConnectionHandle* raw() const noexcept { return handle_.get(); }
private:
explicit UsbmuxdConnection(UsbmuxdConnectionHandle* h) noexcept : handle_(h) {}
ConnectionPtr handle_{};
};
} // namespace IdeviceFFI
#endif