#include "docker_engine_client.hpp" #include #include #include #include #include #include #include DockerEngineClient::DockerEngineClient(std::string socket_path) : socket_path_(std::move(socket_path)) {} EngineResponse DockerEngineClient::request(const std::string& method, const std::string& path, const std::string& body) const { EngineResponse response; const int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { response.error = std::strerror(errno); return response; } sockaddr_un address{}; address.sun_family = AF_UNIX; if (socket_path_.size() >= sizeof(address.sun_path)) { response.error = "Docker socket path is too long."; close(fd); return response; } std::strncpy(address.sun_path, socket_path_.c_str(), sizeof(address.sun_path) - 1); if (connect(fd, reinterpret_cast(&address), sizeof(address)) != 0) { response.error = std::strerror(errno); close(fd); return response; } timeval timeout{}; timeout.tv_sec = 10; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); std::ostringstream request; request << method << " " << path << " HTTP/1.1\r\n" << "Host: docker\r\n" << "Connection: close\r\n" << "Content-Type: application/json\r\n" << "Content-Length: " << body.size() << "\r\n\r\n" << body; const std::string wire = request.str(); std::size_t sent = 0; while (sent < wire.size()) { const ssize_t count = write(fd, wire.data() + sent, wire.size() - sent); if (count <= 0) { response.error = std::strerror(errno); close(fd); return response; } sent += static_cast(count); } std::string raw; char buffer[8192]; ssize_t count = 0; while ((count = read(fd, buffer, sizeof(buffer))) > 0) { raw.append(buffer, static_cast(count)); } close(fd); if (count < 0) { response.error = std::strerror(errno); return response; } const std::size_t header_end = raw.find("\r\n\r\n"); if (header_end == std::string::npos) { response.error = "Invalid response from Docker Engine."; return response; } const std::size_t status_end = raw.find("\r\n"); std::istringstream status_line(raw.substr(0, status_end)); std::string http_version; status_line >> http_version >> response.status_code; if (response.status_code == 0) { response.error = "Invalid HTTP status from Docker Engine."; return response; } response.body = raw.substr(header_end + 4); if (!response.ok()) { response.error = response.body.empty() ? "Docker Engine request failed." : response.body; } return response; }