| // Copyright 2019 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 "libipp/ipp_base.h" |
| |
| #include "libipp/ipp_frame.h" |
| #include "libipp/ipp_frame_builder.h" |
| #include "libipp/ipp_parser.h" |
| |
| namespace ipp { |
| |
| namespace { |
| |
| // Sets attributes-charset and attributes-natural-language. |
| void SetDefaultPackageAttributes(Package* package) { |
| Group* oper_grp = package->GetGroup(GroupTag::operation_attributes); |
| if (oper_grp != nullptr) { |
| if (oper_grp->GetSize() == 0) |
| oper_grp->Resize(1); |
| Collection* coll_grp = oper_grp->GetCollection(); |
| Attribute* attr_charset = |
| coll_grp->GetAttribute(AttrName::attributes_charset); |
| Attribute* attr_language = |
| coll_grp->GetAttribute(AttrName::attributes_natural_language); |
| if (attr_charset != nullptr && attr_charset->GetState() == AttrState::unset) |
| attr_charset->SetValue(std::string("utf-8")); |
| if (attr_language != nullptr && |
| attr_language->GetState() == AttrState::unset) |
| attr_language->SetValue(std::string("en-us")); |
| } |
| } |
| |
| // Sets status-message basing on status-code. |
| void SetDefaultResponseAttributes(Response* package) { |
| Group* oper_grp = package->GetGroup(GroupTag::operation_attributes); |
| if (oper_grp != nullptr) { |
| if (oper_grp->GetSize() == 0) |
| oper_grp->Resize(1); |
| Collection* coll_grp = oper_grp->GetCollection(); |
| Attribute* attr = coll_grp->GetAttribute(AttrName::status_message); |
| if (attr != nullptr && attr->GetState() == AttrState::unset) |
| attr->SetValue(ipp::ToString(package->StatusCode())); |
| } |
| } |
| |
| // Clear all values in the package. |
| void ClearPackage(Package* package) { |
| const std::vector<Group*> groups = package->GetAllGroups(); |
| for (auto g : groups) |
| g->Resize(0); |
| } |
| |
| Version GetVersion(const Frame* frame) { |
| uint16_t v = frame->major_version_number_; |
| v <<= 8; |
| v += frame->minor_version_number_; |
| return static_cast<Version>(v); |
| } |
| |
| void SetVersion(Version version, Frame* frame) { |
| uint16_t v = static_cast<uint16_t>(version); |
| frame->major_version_number_ = (v >> 8); |
| frame->minor_version_number_ = (v & 0xff); |
| } |
| |
| } // namespace |
| |
| // internal structure with all data |
| struct Protocol { |
| // internal buffer for current frame |
| Frame frame; |
| // log with errors |
| std::vector<Log> log; |
| // parser and frame builder, both work on the frame and the log defined above |
| Parser parser; |
| FrameBuilder frame_builder; |
| // constructor |
| Protocol() : parser(&frame, &log), frame_builder(&frame, &log) {} |
| // resets everything to initial state |
| void ResetContent() { |
| frame.operation_id_or_status_code_ = 0; |
| frame.groups_tags_.clear(); |
| frame.groups_content_.clear(); |
| frame.data_.clear(); |
| log.clear(); |
| parser.ResetContent(); |
| } |
| }; |
| |
| Client::Client(Version version, int32_t request_id) |
| : protocol_(std::make_unique<Protocol>()) { |
| SetVersionNumber(version); |
| protocol_->frame.request_id_ = request_id; |
| } |
| |
| // Destructor must be defined here, because we do not have definition of |
| // Protocol in the header. |
| Client::~Client() = default; |
| |
| Version Client::GetVersionNumber() const { |
| return GetVersion(&protocol_->frame); |
| } |
| |
| void Client::SetVersionNumber(Version version) { |
| SetVersion(version, &protocol_->frame); |
| } |
| |
| void Client::BuildRequestFrom(Request* request) { |
| protocol_->ResetContent(); |
| SetDefaultPackageAttributes(request); |
| ++(protocol_->frame.request_id_); |
| protocol_->frame.operation_id_or_status_code_ = |
| static_cast<uint16_t>(request->GetOperationId()); |
| protocol_->frame_builder.BuildFrameFromPackage(request); |
| } |
| |
| bool Client::WriteRequestFrameTo(std::vector<uint8_t>* data) const { |
| if (data == nullptr) |
| return false; |
| data->resize(GetFrameLength()); |
| return protocol_->frame_builder.WriteFrameToBuffer(data->data()); |
| } |
| |
| std::size_t Client::GetFrameLength() const { |
| return protocol_->frame_builder.GetFrameLength(); |
| } |
| |
| bool Client::ReadResponseFrameFrom(const uint8_t* ptr, |
| const uint8_t* const buf_end) { |
| protocol_->ResetContent(); |
| return protocol_->parser.ReadFrameFromBuffer(ptr, buf_end); |
| } |
| |
| bool Client::ReadResponseFrameFrom(const std::vector<uint8_t>& data) { |
| protocol_->ResetContent(); |
| const uint8_t* ptr = (data.empty()) ? (nullptr) : (&(data[0])); |
| return protocol_->parser.ReadFrameFromBuffer(ptr, ptr + data.size()); |
| } |
| |
| bool Client::ParseResponseAndSaveTo(Response* response, |
| bool log_unknown_values) { |
| ClearPackage(response); |
| response->StatusCode() = |
| static_cast<Status>(protocol_->frame.operation_id_or_status_code_); |
| return protocol_->parser.SaveFrameToPackage(log_unknown_values, response); |
| } |
| |
| const std::vector<Log>& Client::GetErrorLog() const { |
| return protocol_->log; |
| } |
| |
| Server::Server(Version version, int32_t request_id) |
| : protocol_(std::make_unique<Protocol>()) { |
| SetVersionNumber(version); |
| protocol_->frame.request_id_ = request_id; |
| } |
| |
| // Destructor must be defined here, because we do not have definition of |
| // Protocol in the header. |
| Server::~Server() = default; |
| |
| Version Server::GetVersionNumber() const { |
| return GetVersion(&protocol_->frame); |
| } |
| |
| void Server::SetVersionNumber(Version version) { |
| SetVersion(version, &protocol_->frame); |
| } |
| |
| bool Server::ReadRequestFrameFrom(const uint8_t* ptr, |
| const uint8_t* const buf_end) { |
| protocol_->ResetContent(); |
| return protocol_->parser.ReadFrameFromBuffer(ptr, buf_end); |
| } |
| |
| bool Server::ReadRequestFrameFrom(const std::vector<uint8_t>& data) { |
| protocol_->ResetContent(); |
| return protocol_->parser.ReadFrameFromBuffer(data.data(), |
| data.data() + data.size()); |
| } |
| |
| Operation Server::GetOperationId() const { |
| return static_cast<Operation>(protocol_->frame.operation_id_or_status_code_); |
| } |
| |
| bool Server::ParseRequestAndSaveTo(Request* request, bool log_unknown_values) { |
| ClearPackage(request); |
| return protocol_->parser.SaveFrameToPackage(log_unknown_values, request); |
| } |
| |
| void Server::BuildResponseFrom(Response* package) { |
| protocol_->ResetContent(); |
| SetDefaultPackageAttributes(package); |
| SetDefaultResponseAttributes(package); |
| protocol_->frame.operation_id_or_status_code_ = |
| static_cast<uint16_t>(package->StatusCode()); |
| protocol_->frame_builder.BuildFrameFromPackage(package); |
| } |
| |
| std::size_t Server::GetFrameLength() const { |
| return protocol_->frame_builder.GetFrameLength(); |
| } |
| |
| bool Server::WriteResponseFrameTo(std::vector<uint8_t>* data) const { |
| if (data == nullptr) |
| return false; |
| data->resize(GetFrameLength()); |
| return protocol_->frame_builder.WriteFrameToBuffer(data->data()); |
| } |
| |
| const std::vector<Log>& Server::GetErrorLog() const { |
| return protocol_->log; |
| } |
| |
| } // namespace ipp |