项目文件夹

文件
2026-07-13 13:29:29 +08:00

271 行
9.6 KiB
C++

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// Since kDefaultTotalBytesLimit is private, we need some hacks to get the limit.
// Works for pb 2.4, 2.6, 3.0
#include "google/protobuf/stubs/common.h"
#if GOOGLE_PROTOBUF_VERSION < 4022000
#define private public
#include <google/protobuf/io/coded_stream.h>
const int PB_TOTAL_BYETS_LIMITS_RAW =
google::protobuf::io::CodedInputStream::kDefaultTotalBytesLimit;
const uint64_t PB_TOTAL_BYETS_LIMITS =
PB_TOTAL_BYETS_LIMITS_RAW < 0 ? (uint64_t)-1LL : PB_TOTAL_BYETS_LIMITS_RAW;
#undef private
#else
#include <google/protobuf/io/coded_stream.h>
const int PB_TOTAL_BYETS_LIMITS_RAW = INT_MAX;
const uint64_t PB_TOTAL_BYETS_LIMITS =
PB_TOTAL_BYETS_LIMITS_RAW < 0 ? (uint64_t)-1LL : PB_TOTAL_BYETS_LIMITS_RAW;
#endif
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/text_format.h>
#include <gflags/gflags.h>
#include "butil/logging.h"
#include "butil/memory/singleton_on_pthread_once.h"
#include "brpc/protocol.h"
#include "brpc/controller.h"
#include "brpc/compress.h"
#include "brpc/global.h"
#include "brpc/serialized_request.h"
#include "brpc/input_messenger.h"
namespace brpc {
DEFINE_uint64(max_body_size, 64 * 1024 * 1024,
"Maximum size of a single message body in all protocols");
DEFINE_bool(log_error_text, false,
"Print Controller.ErrorText() when server is about to"
" respond a failed RPC");
BRPC_VALIDATE_GFLAG(log_error_text, PassValidate);
// Not using ProtocolType_MAX as the boundary because others may define new
// protocols outside brpc.
const size_t MAX_PROTOCOL_SIZE = 128;
struct ProtocolEntry {
butil::atomic<bool> valid;
Protocol protocol;
ProtocolEntry() : valid(false) {}
};
struct ProtocolMap {
ProtocolEntry entries[MAX_PROTOCOL_SIZE];
};
inline ProtocolEntry* get_protocol_map() {
return butil::get_leaky_singleton<ProtocolMap>()->entries;
}
static pthread_mutex_t s_protocol_map_mutex = PTHREAD_MUTEX_INITIALIZER;
int RegisterProtocol(ProtocolType type, const Protocol& protocol) {
const size_t index = type;
if (index >= MAX_PROTOCOL_SIZE) {
LOG(ERROR) << "ProtocolType=" << type << " is out of range";
return -1;
}
if (!protocol.support_client() && !protocol.support_server()) {
LOG(ERROR) << "ProtocolType=" << type
<< " neither supports client nor server";
return -1;
}
ProtocolEntry* const protocol_map = get_protocol_map();
BAIDU_SCOPED_LOCK(s_protocol_map_mutex);
if (protocol_map[index].valid.load(butil::memory_order_relaxed)) {
LOG(ERROR) << "ProtocolType=" << type << " was registered";
return -1;
}
protocol_map[index].protocol = protocol;
protocol_map[index].valid.store(true, butil::memory_order_release);
return 0;
}
// Called frequently, must be fast.
const Protocol* FindProtocol(ProtocolType type) {
const size_t index = type;
if (index >= MAX_PROTOCOL_SIZE) {
LOG(ERROR) << "ProtocolType=" << type << " is out of range";
return NULL;
}
ProtocolEntry* const protocol_map = get_protocol_map();
if (protocol_map[index].valid.load(butil::memory_order_acquire)) {
return &protocol_map[index].protocol;
}
return NULL;
}
void ListProtocols(std::vector<Protocol>* vec) {
vec->clear();
ProtocolEntry* const protocol_map = get_protocol_map();
for (size_t i = 0; i < MAX_PROTOCOL_SIZE; ++i) {
if (protocol_map[i].valid.load(butil::memory_order_acquire)) {
vec->push_back(protocol_map[i].protocol);
}
}
}
void ListProtocols(std::vector<std::pair<ProtocolType, Protocol> >* vec) {
vec->clear();
ProtocolEntry* const protocol_map = get_protocol_map();
for (size_t i = 0; i < MAX_PROTOCOL_SIZE; ++i) {
if (protocol_map[i].valid.load(butil::memory_order_acquire)) {
vec->emplace_back((ProtocolType)i, protocol_map[i].protocol);
}
}
}
void SerializeRequestDefault(butil::IOBuf* buf, Controller* cntl,
const google::protobuf::Message* request) {
// Check sanity of request.
if (!request) {
return cntl->SetFailed(EREQUEST, "`request' is NULL");
}
if (!request->IsInitialized()) {
return cntl->SetFailed(
EREQUEST, "Missing required fields in request: %s",
request->InitializationErrorString().c_str());
}
if (!SerializeAsCompressedData(*request, buf, cntl->request_compress_type())) {
return cntl->SetFailed(
EREQUEST, "Fail to compress request, compress_type=%d",
(int)cntl->request_compress_type());
}
}
// ======================================================
inline bool CompareStringPieceWithoutCase(
const butil::StringPiece& s1, const char* s2) {
if (strlen(s2) != s1.size()) {
return false;
}
return strncasecmp(s1.data(), s2, s1.size()) == 0;
}
ProtocolType StringToProtocolType(const butil::StringPiece& name,
bool print_log_on_unknown) {
// Force init of s_protocol_name.
GlobalInitializeOrDie();
ProtocolEntry* const protocol_map = get_protocol_map();
for (size_t i = 0; i < MAX_PROTOCOL_SIZE; ++i) {
if (protocol_map[i].valid.load(butil::memory_order_acquire) &&
CompareStringPieceWithoutCase(name, protocol_map[i].protocol.name)) {
return static_cast<ProtocolType>(i);
}
}
// We need to print a log here otherwise the return value cannot reflect
// the original input, which makes later initializations of other classes
// fail with vague logs which is not informational to user, like this:
// "channel doesn't support protocol=unknown"
// Some callsite may not need this log, so we keep a flag.
if (print_log_on_unknown) {
std::ostringstream err;
err << "Unknown protocol `" << name << "', supported protocols:";
for (size_t i = 0; i < MAX_PROTOCOL_SIZE; ++i) {
if (protocol_map[i].valid.load(butil::memory_order_acquire)) {
err << ' ' << protocol_map[i].protocol.name;
}
}
LOG(ERROR) << err.str();
}
return PROTOCOL_UNKNOWN;
}
const char* ProtocolTypeToString(ProtocolType type) {
// Force init of s_protocol_name.
GlobalInitializeOrDie();
const Protocol* p = FindProtocol(type);
if (p != NULL) {
return p->name;
}
return "unknown";
}
BUTIL_FORCE_INLINE bool ParsePbFromZeroCopyStreamInlined(
google::protobuf::Message* msg,
google::protobuf::io::ZeroCopyInputStream* input) {
google::protobuf::io::CodedInputStream decoder(input);
// Remove the limit inside pb so that it never conflicts with -max_body_size
// According to source code of pb, SetTotalBytesLimit is not a simple set,
// avoid calling the function when the limit is definitely unreached.
if (PB_TOTAL_BYETS_LIMITS < FLAGS_max_body_size) {
#if GOOGLE_PROTOBUF_VERSION >= 3006000
decoder.SetTotalBytesLimit(INT_MAX);
#else
decoder.SetTotalBytesLimit(INT_MAX, -1);
#endif
}
return msg->ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
}
BUTIL_FORCE_INLINE bool ParsePbTextFromZeroCopyStreamInlined(
google::protobuf::Message* msg,
google::protobuf::io::ZeroCopyInputStream* input) {
return google::protobuf::TextFormat::Parse(input, msg);
}
bool ParsePbFromZeroCopyStream(
google::protobuf::Message* msg,
google::protobuf::io::ZeroCopyInputStream* input) {
return ParsePbFromZeroCopyStreamInlined(msg, input);
}
bool ParsePbTextFromIOBuf(google::protobuf::Message* msg, const butil::IOBuf& buf) {
butil::IOBufAsZeroCopyInputStream stream(buf);
return ParsePbTextFromZeroCopyStreamInlined(msg, &stream);
}
bool ParsePbFromIOBuf(google::protobuf::Message* msg, const butil::IOBuf& buf) {
butil::IOBufAsZeroCopyInputStream stream(buf);
return ParsePbFromZeroCopyStreamInlined(msg, &stream);
}
bool ParsePbFromArray(google::protobuf::Message* msg,
const void* data, size_t size) {
google::protobuf::io::ArrayInputStream stream(data, size);
return ParsePbFromZeroCopyStreamInlined(msg, &stream);
}
bool ParsePbFromString(google::protobuf::Message* msg, const std::string& str) {
google::protobuf::io::ArrayInputStream stream(str.data(), str.size());
return ParsePbFromZeroCopyStreamInlined(msg, &stream);
}
void LogErrorTextAndDelete::operator()(Controller* c) const {
if (!c) {
return;
}
if (FLAGS_log_error_text && c->ErrorCode()) {
if (c->ErrorCode() == ECLOSE) {
LOG(WARNING) << "Close connection to " << c->remote_side()
<< ": " << c->ErrorText();
} else {
LOG(WARNING) << "Error to " << c->remote_side()
<< ": " << c->ErrorText();
}
}
if (_delete_cntl) {
delete c;
}
}
} // namespace brpc