blob: 8409a926d7c94a6dda85ee5cd0d3c85a24728e88 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "trunks/csme/mei_client_socket.h"
#include <error.h>
#include <fcntl.h>
#include <linux/mei.h>
#include <linux/uuid.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <cstring>
#include <string>
#include <base/check.h>
#include <base/check_op.h>
#include <base/logging.h>
namespace trunks {
namespace csme {
MeiClientSocket::MeiClientSocket(const std::string& mei_path,
const uuid_le& guid)
: mei_path_(mei_path) {
DCHECK(!mei_path_.empty());
memcpy(&guid_, &guid, sizeof(guid));
}
MeiClientSocket::~MeiClientSocket() {
Uninitialize();
}
bool MeiClientSocket::Initialize() {
if (initialized_) {
return true;
}
DCHECK_EQ(fd_, -1);
if (!InitializeInternal()) {
Uninitialize();
return false;
}
initialized_ = true;
return true;
}
void MeiClientSocket::Uninitialize() {
if (fd_ != -1) {
close(fd_);
fd_ = -1;
}
}
bool MeiClientSocket::Send(const std::string& data,
bool /*wait_for_response_ready*/) {
if (!initialized_ && !Initialize()) {
LOG(ERROR) << __func__ << ": Not initialized.";
return false;
}
const uint32_t message_size = data.size();
ssize_t wsize = write(fd_, &message_size, sizeof(message_size));
if (wsize != sizeof(message_size)) {
LOG(ERROR) << __func__ << ": Bad written size of message header: " << wsize;
return false;
}
wsize = write(fd_, data.data(), data.size());
if (wsize != data.size()) {
LOG(ERROR) << __func__ << ": Bad written size of payload: " << wsize;
return false;
}
return true;
}
bool MeiClientSocket::Receive(std::string* data) {
if (!initialized_ && !Initialize()) {
LOG(ERROR) << __func__ << ": Not initialized.";
return false;
}
uint32_t message_size = 0;
ssize_t rsize = read(fd_, &message_size, sizeof(message_size));
if (rsize != sizeof(message_size)) {
LOG(ERROR) << "Unexpected message header size: " << rsize;
return false;
}
data->resize(message_size);
char* buffer = const_cast<char*>(data->data());
for (ssize_t remaining_size = message_size; remaining_size > 0;) {
const ssize_t rsize = read(fd_, buffer, remaining_size);
if (rsize < 0) {
LOG(ERROR) << ": Error calling `read()`: " << errno;
data->clear();
return false;
}
buffer += rsize;
remaining_size -= rsize;
}
return true;
}
bool MeiClientSocket::InitializeInternal() {
DCHECK_EQ(fd_, -1);
fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd_ == -1) {
LOG(ERROR) << __func__ << ": Error calling `socket()`." << errno;
return false;
}
struct sockaddr_un addr = {};
addr.sun_family = AF_UNIX;
CHECK_LT(mei_path_.size(), sizeof(addr.sun_path));
strncpy(addr.sun_path, mei_path_.c_str(), sizeof(addr.sun_path));
if (connect(fd_, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
LOG(ERROR) << __func__ << ": Error when connecting socket: " << errno;
return false;
}
return true;
}
} // namespace csme
} // namespace trunks