commit 824ea2a25f3de11cdc5a53151ac60ab7d059002c Author: dongl <2725096176@qq.com> Date: Wed May 3 19:09:14 2023 +0800 tbb libevent protobuf diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b6df6d4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.24) +project(IM2) + +set(CMAKE_CXX_STANDARD 17) + +add_subdirectory(MS) +add_subdirectory(MP) +add_subdirectory(MC) +add_subdirectory(MDB/imm_mysqldb) diff --git a/MC/CMakeLists.txt b/MC/CMakeLists.txt new file mode 100644 index 0000000..1096651 --- /dev/null +++ b/MC/CMakeLists.txt @@ -0,0 +1,14 @@ +project(MC) + +include_directories(${CMAKE_SOURCE_DIR}/include/libevent) +include_directories(${CMAKE_SOURCE_DIR}/include/mp) + +link_directories(${CMAKE_SOURCE_DIR}/lib/libevent) + + +add_executable(MC main.cpp) + +target_link_libraries(MC + event + MP + ) \ No newline at end of file diff --git a/MC/main.cpp b/MC/main.cpp new file mode 100644 index 0000000..0e0f830 --- /dev/null +++ b/MC/main.cpp @@ -0,0 +1,89 @@ +// +// Created by dongl on 23-4-15. +// + +#include +#include +#include "Request.h" +#include "Response.h" +#include "event2/event.h" +#include "event2/bufferevent.h" + +void client_read_cb(struct bufferevent *bev, void *ctx); +void client_write_cb(struct bufferevent *bev, void *ctx); + +int main() { + event_base *base = event_base_new(); + bufferevent* bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); + sockaddr_in c_sin = {0}; + memset(&c_sin, 0, sizeof(c_sin)); + c_sin = { + AF_INET, + htons(9999), + + }; + evutil_inet_pton(AF_INET, "127.0.0.1", &c_sin.sin_addr.s_addr); + + + bufferevent_setcb(bev, client_read_cb, client_write_cb, nullptr, nullptr); + bufferevent_enable(bev, EV_READ | EV_WRITE); + int ret = bufferevent_socket_connect(bev, (sockaddr *) &c_sin, sizeof(c_sin)); + if (ret == 0) { + printf("connected\n"); + fflush(stdout); + } + + auto request = new Request(mp::MP_REQUEST_LOGIN, 783556037, "Aa316216"); + auto packet = request->operator()(); + bufferevent_write(bev, packet.c_str(), packet.size()); + + uint8_t l; + memcpy(&l, packet.c_str(), 1); + memcpy((void *) packet.c_str(), packet.c_str() + 1, packet.size() - 1); + + std::string h; + memcpy((void *) h.c_str(), packet.c_str(), l); + + auto mph = new mp::mph(); + mph->ParseFromString(h); + printf("packet size: %u\n", mph->mpb_size()); + printf("packet size: %zu\n", packet.size()); + + + fflush(stdout); + event_base_dispatch(base); + event_base_free(base); +} + +void client_read_cb(struct bufferevent *bev, void *ctx) { + printf("[read]: "); + // read L 读包长度 + uint8_t packetLen; + bufferevent_read(bev, &packetLen, 1); + // read V 读包头 + char data_h[256] = {0}; + bufferevent_read(bev, data_h, packetLen); + + auto mph = std::make_shared(mp::mph()); + mph->ParseFromString(data_h); + printf("mph->mpb_size: %d\n", mph->mpb_size()); + + + // read V 读包体 包头内含有包体长度 + char data_b[256] = {0}; + bufferevent_read(bev, data_b, mph->mpb_size()); + printf("data_b: %s\n", data_b); + + mp::response* resp = new mp::response(); + resp->ParseFromString(data_b); + printf("%s\n", resp->sri().sri_msg().c_str()); + + fflush(stdout); +} + +void client_write_cb(struct bufferevent *bev, void *ctx) { +// Bytef data[1024] = {0}; +// uint32_t len = login(2725096176, "Aa316216", data, sizeof(data)); +// bufferevent_write(bev, data, len); +// sleep(3); +} \ No newline at end of file diff --git a/MDB/imm_mysqldb/CMakeLists.txt b/MDB/imm_mysqldb/CMakeLists.txt new file mode 100644 index 0000000..ec0049b --- /dev/null +++ b/MDB/imm_mysqldb/CMakeLists.txt @@ -0,0 +1,20 @@ +project(imm_mysqldb) + +include_directories(${CMAKE_SOURCE_DIR}/include/mp) +include_directories(${CMAKE_SOURCE_DIR}/include/libevent) +include_directories(${CMAKE_SOURCE_DIR}/include/mysql++) +include_directories(${CMAKE_SOURCE_DIR}/include/mysql++/mysql) + +link_directories(${CMAKE_SOURCE_DIR}/lib/mysql++) + +aux_source_directory(user DIR_USER) + +add_library(imm_mysqldb + ConnectionPool.cpp + ${DIR_USER} +) + +target_link_libraries(imm_mysqldb + mysqlpp mysqlclient + MP +) \ No newline at end of file diff --git a/MDB/imm_mysqldb/ConnectionPool.cpp b/MDB/imm_mysqldb/ConnectionPool.cpp new file mode 100644 index 0000000..a30bad3 --- /dev/null +++ b/MDB/imm_mysqldb/ConnectionPool.cpp @@ -0,0 +1,31 @@ +// +// Created by dongl on 23-4-8. +// +#include "ConnectionPool.h" + +#include + +mysqlpp::Connection *ConnectionPool::create() { + return new mysqlpp::Connection( + db_.empty() ? nullptr : db_.c_str(), + server_.empty() ? nullptr : server_.c_str(), + user_.empty() ? nullptr : user_.c_str(), + password_.empty() ? "" : password_.c_str()); +} + +void ConnectionPool::destroy(mysqlpp::Connection *connection) { + delete connection; +} + +unsigned int ConnectionPool::max_idle_time() { + return 30; +} + + +ConnectionPool::ConnectionPool(std::string server, std::string db, std::string user, + std::string password) : server_(std::move(server)), db_(std::move(db)), user_(std::move(user)), + password_(std::move(password)) {} + +ConnectionPool::~ConnectionPool() { + clear(); +} diff --git a/MDB/imm_mysqldb/ConnectionPool.h b/MDB/imm_mysqldb/ConnectionPool.h new file mode 100644 index 0000000..2183306 --- /dev/null +++ b/MDB/imm_mysqldb/ConnectionPool.h @@ -0,0 +1,28 @@ +// +// Created by dongl on 23-4-8. +// + +#ifndef IM_CONNECTIONPOOL_H +#define IM_CONNECTIONPOOL_H + +#include + +class ConnectionPool : public mysqlpp::ConnectionPool { +public: + ConnectionPool(std::string server, std::string db, std::string user, + std::string password); + + ~ConnectionPool() override; + +protected: + mysqlpp::Connection *create() override; + + void destroy(mysqlpp::Connection *connection) override; + + unsigned int max_idle_time() override; + +private: + std::string server_, db_, user_, password_; +}; + +#endif //IM_CONNECTIONPOOL_H diff --git a/MDB/imm_mysqldb/template_table/im_user.h b/MDB/imm_mysqldb/template_table/im_user.h new file mode 100644 index 0000000..aa1fbe5 --- /dev/null +++ b/MDB/imm_mysqldb/template_table/im_user.h @@ -0,0 +1,21 @@ +// +// Created by dongl on 23-4-16. +// + +#ifndef IM_IM_USER_H +#define IM_IM_USER_H + +#include +#include + +sql_create_5(im_user, +1, 5, // 1 当主键 第三个参数是 SETCOUNT。如果这为非零值,则添加一个初始化构造函数和一个成员函数,该函数采用给定数量的参数,用于设置结构的前 N 个字段。 +mysqlpp::sql_bigint , account, +mysqlpp::sql_varchar,username, +mysqlpp::sql_varchar,password, +mysqlpp::sql_varchar,password_salt, +mysqlpp::sql_tinyblob, client_info +); + + +#endif //IM_IM_USER_H diff --git a/MDB/imm_mysqldb/user/DBUser.cpp b/MDB/imm_mysqldb/user/DBUser.cpp new file mode 100644 index 0000000..cc71d8b --- /dev/null +++ b/MDB/imm_mysqldb/user/DBUser.cpp @@ -0,0 +1,52 @@ +// +// Created by dongl on 23-4-16. +// + + +#include "../template_table/im_user.h" +#include "DBUser.h" + +mp::sri* DBUser::login(uint64_t account, const std::string& password) { + printf("account:%lu, password: %s\n", account, password.c_str()); + mysqlpp::ScopedConnection conn(*pool, true); + + auto query = conn->query("select * from im_user where account="+ std::to_string(account)+";"); + + std::vector v; + query.storein(v); + printf("info: %s\n", query.info().c_str()); + + // 无账户 + if (v.empty()) { + printf("无此用户\n"); + sri->set_sri_msg("account null!"); + sri->set_sri_code(mp::MP_LOGIN_ACCOUNT_NOT); + return sri; + } + + // 判断密码 + im_user user = v[0]; + if (user.password == password) { + printf("登陆成功\n"); + sri->set_sri_msg("login success!"); + sri->set_sri_code(mp::MP_LOGIN_SUCCESS); + sri->set_sri_token("token"); + } else { + printf("登陆失败\n"); + sri->set_sri_msg("login fail!"); + sri->set_sri_code(mp::MP_LOGIN_FAIL); + } + + return sri; +} + + +DBUser::DBUser() { + sri = new mp::sri(); +} + +DBUser::~DBUser() { + delete sri; +} + + diff --git a/MDB/imm_mysqldb/user/DBUser.h b/MDB/imm_mysqldb/user/DBUser.h new file mode 100644 index 0000000..79afd41 --- /dev/null +++ b/MDB/imm_mysqldb/user/DBUser.h @@ -0,0 +1,24 @@ +// +// Created by dongl on 23-4-16. +// + +#ifndef IM_DBUSER_H +#define IM_DBUSER_H + + +#include "../ConnectionPool.h" +#include "proto/mp.sri.pb.h" + + +class DBUser { + ConnectionPool* pool = new ConnectionPool("124.221.152.192", "ims", "IMS", "WimTFC8N58kznx2k"); +public: + DBUser(); + virtual ~DBUser(); + mp::sri* login(uint64_t account, const std::string& password); +private: + mp::sri* sri; +}; + + +#endif //IM_DBUSER_H diff --git a/MP/CMakeLists.txt b/MP/CMakeLists.txt new file mode 100644 index 0000000..1a0a20d --- /dev/null +++ b/MP/CMakeLists.txt @@ -0,0 +1,16 @@ +project(MP) + +include_directories(${CMAKE_SOURCE_DIR}/include/mp) +include_directories(${CMAKE_SOURCE_DIR}/include/mp/proto) + +aux_source_directory(${CMAKE_SOURCE_DIR}/MP MP_DIR) +aux_source_directory(${CMAKE_SOURCE_DIR}/MP/proto PROTO_DIR) + +add_library(MP + ${MP_DIR} + ${PROTO_DIR} + ) + +target_link_libraries(MP + protobuf +) diff --git a/MP/Request.cpp b/MP/Request.cpp new file mode 100644 index 0000000..a9d905c --- /dev/null +++ b/MP/Request.cpp @@ -0,0 +1,42 @@ +// +// Created by dongl on 23-4-21. +// + +#include "Request.h" + +Request::Request(mp::MP_TYPE type, uint64_t account, const std::string& password) : +Mph(type), Body(account, password), Cqi() { + +} + +Request::Request(mp::MP_TYPE type, uint64_t target, uint64_t source, const std::string& data) : +Mph(type), Body(target, source, data), Cqi() { + +} + + +void Request::init() { + memset(temp, 0 , 256); + request = new mp::request(); + request->set_allocated_body(body); + request->set_allocated_cqi(cqi); + mph->set_mpb_size(body->ByteSizeLong() + cqi->ByteSizeLong()); +} + +std::string Request::operator()() { + init(); + std::string temp_mph; + std::string temp_request; + mph->SerializeToString(&temp_mph); + request->SerializeToString(&temp_request); + + auto L = (uint8_t )temp_mph.size(); + sprintf(temp, "%c", L); + sprintf(temp, "%s%s%s", temp, temp_mph.c_str(), temp_request.c_str()); + return temp; +} + +Request::~Request() { + delete request; +} + diff --git a/MP/Response.cpp b/MP/Response.cpp new file mode 100644 index 0000000..e0f513e --- /dev/null +++ b/MP/Response.cpp @@ -0,0 +1,64 @@ +// +// Created by dongl on 23-4-21. +// + +#include "Response.h" + +Response::Response(mp::MP_TYPE type, mp::MP_SRI code, const std::string &username, const std::string &msg, const std::string &token) : + Mph(type), + Sri(code, username, msg, token) { +} + +Response::~Response() { + delete response; +} + +void Response::init() { + memset(temp, 0 , 256); + response = new mp::response(); + response->set_allocated_sri(sri); + mph->set_mpb_size( response->ByteSizeLong()); +} + +std::string Response::operator()() { + init(); + std::string temp_mph; + std::string temp_request; + + mph->SerializeToString(&temp_mph); + response->SerializeToString(&temp_request); + + uint8_t size = mph->ByteSizeLong(); + sprintf(temp, "%c", size); + sprintf(temp, "%s%s%s", temp, temp_mph.c_str(), temp_request.c_str()); + // time: 0426 19:54 debug return 这里反复执行 然后temp 字符串就乱了 变了 + return temp; +} + +std::string Response::packet () { + init(); + std::string temp_mph; + std::string temp_request; + + mph->SerializeToString(&temp_mph); + response->SerializeToString(&temp_request); + + uint8_t size = mph->ByteSizeLong(); + sprintf(temp, "%c", size); + sprintf(temp, "%s%s%s", temp, temp_mph.c_str(), temp_request.c_str()); + + printf("size: %zu\n", mph->ByteSizeLong() + response->ByteSizeLong() + 1); + printf("size: %zu\n", temp_mph.size() + temp_request.size() + 1); + printf("size: %zu\n", strlen(temp)); + + printf("response size: %zu\n", response->ByteSizeLong()); + + + printf("temp_mph: %s\n", temp_mph.c_str()); + printf("temp_request: %s\n", temp_request.c_str()); + printf("temp: %s\n", temp); + + // time: 0426 19:54 debug return 这里反复执行 然后temp 字符串就乱了 变了 + return temp; +} + diff --git a/MP/proto/mp.body.pb.cc b/MP/proto/mp.body.pb.cc new file mode 100644 index 0000000..8d5e161 --- /dev/null +++ b/MP/proto/mp.body.pb.cc @@ -0,0 +1,423 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.body.proto + +#include "proto/mp.body.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include +namespace mp { +class bodyDefaultTypeInternal { + public: + ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed _instance; +} _body_default_instance_; +} // namespace mp +static void InitDefaultsscc_info_body_mp_2ebody_2eproto() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::mp::_body_default_instance_; + new (ptr) ::mp::body(); + ::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr); + } + ::mp::body::InitAsDefaultInstance(); +} + +::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_body_mp_2ebody_2eproto = + {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_body_mp_2ebody_2eproto}, {}}; + +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_mp_2ebody_2eproto[1]; +static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_mp_2ebody_2eproto = nullptr; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_mp_2ebody_2eproto = nullptr; + +const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_mp_2ebody_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::mp::body, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + PROTOBUF_FIELD_OFFSET(::mp::body, account_), + PROTOBUF_FIELD_OFFSET(::mp::body, password_), + PROTOBUF_FIELD_OFFSET(::mp::body, target_), + PROTOBUF_FIELD_OFFSET(::mp::body, source_), + PROTOBUF_FIELD_OFFSET(::mp::body, data_), +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::mp::body)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::mp::_body_default_instance_), +}; + +const char descriptor_table_protodef_mp_2ebody_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n\rmp.body.proto\022\002mp\"W\n\004body\022\017\n\007account\030\001" + " \001(\004\022\020\n\010password\030\002 \001(\t\022\016\n\006target\030\003 \001(\004\022\016" + "\n\006source\030\004 \001(\004\022\014\n\004data\030\005 \001(\tb\006proto3" + ; +static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_mp_2ebody_2eproto_deps[1] = { +}; +static ::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase*const descriptor_table_mp_2ebody_2eproto_sccs[1] = { + &scc_info_body_mp_2ebody_2eproto.base, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_mp_2ebody_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2ebody_2eproto = { + false, false, descriptor_table_protodef_mp_2ebody_2eproto, "mp.body.proto", 116, + &descriptor_table_mp_2ebody_2eproto_once, descriptor_table_mp_2ebody_2eproto_sccs, descriptor_table_mp_2ebody_2eproto_deps, 1, 0, + schemas, file_default_instances, TableStruct_mp_2ebody_2eproto::offsets, + file_level_metadata_mp_2ebody_2eproto, 1, file_level_enum_descriptors_mp_2ebody_2eproto, file_level_service_descriptors_mp_2ebody_2eproto, +}; + +// Force running AddDescriptors() at dynamic initialization time. +static bool dynamic_init_dummy_mp_2ebody_2eproto = (static_cast(::PROTOBUF_NAMESPACE_ID::internal::AddDescriptors(&descriptor_table_mp_2ebody_2eproto)), true); +namespace mp { + +// =================================================================== + +void body::InitAsDefaultInstance() { +} +class body::_Internal { + public: +}; + +body::body(::PROTOBUF_NAMESPACE_ID::Arena* arena) + : ::PROTOBUF_NAMESPACE_ID::Message(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:mp.body) +} +body::body(const body& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + password_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (!from._internal_password().empty()) { + password_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_password(), + GetArena()); + } + data_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (!from._internal_data().empty()) { + data_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_data(), + GetArena()); + } + ::memcpy(&account_, &from.account_, + static_cast(reinterpret_cast(&source_) - + reinterpret_cast(&account_)) + sizeof(source_)); + // @@protoc_insertion_point(copy_constructor:mp.body) +} + +void body::SharedCtor() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&scc_info_body_mp_2ebody_2eproto.base); + password_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + data_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + ::memset(&account_, 0, static_cast( + reinterpret_cast(&source_) - + reinterpret_cast(&account_)) + sizeof(source_)); +} + +body::~body() { + // @@protoc_insertion_point(destructor:mp.body) + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +void body::SharedDtor() { + GOOGLE_DCHECK(GetArena() == nullptr); + password_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + data_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void body::ArenaDtor(void* object) { + body* _this = reinterpret_cast< body* >(object); + (void)_this; +} +void body::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void body::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const body& body::default_instance() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&::scc_info_body_mp_2ebody_2eproto.base); + return *internal_default_instance(); +} + + +void body::Clear() { +// @@protoc_insertion_point(message_clear_start:mp.body) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + password_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + data_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + ::memset(&account_, 0, static_cast( + reinterpret_cast(&source_) - + reinterpret_cast(&account_)) + sizeof(source_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* body::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena; + while (!ctx->Done(&ptr)) { + ::PROTOBUF_NAMESPACE_ID::uint32 tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + CHK_(ptr); + switch (tag >> 3) { + // uint64 account = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) { + account_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + // string password = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) { + auto str = _internal_mutable_password(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "mp.body.password")); + CHK_(ptr); + } else goto handle_unusual; + continue; + // uint64 target = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 24)) { + target_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + // uint64 source = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 32)) { + source_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + // string data = 5; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 42)) { + auto str = _internal_mutable_data(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "mp.body.data")); + CHK_(ptr); + } else goto handle_unusual; + continue; + default: { + handle_unusual: + if ((tag & 7) == 4 || tag == 0) { + ctx->SetLastTag(tag); + goto success; + } + ptr = UnknownFieldParse(tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + continue; + } + } // switch + } // while +success: + return ptr; +failure: + ptr = nullptr; + goto success; +#undef CHK_ +} + +::PROTOBUF_NAMESPACE_ID::uint8* body::_InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:mp.body) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // uint64 account = 1; + if (this->account() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(1, this->_internal_account(), target); + } + + // string password = 2; + if (this->password().size() > 0) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_password().data(), static_cast(this->_internal_password().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "mp.body.password"); + target = stream->WriteStringMaybeAliased( + 2, this->_internal_password(), target); + } + + // uint64 target = 3; + if (this->target() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(3, this->_internal_target(), target); + } + + // uint64 source = 4; + if (this->source() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(4, this->_internal_source(), target); + } + + // string data = 5; + if (this->data().size() > 0) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_data().data(), static_cast(this->_internal_data().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "mp.body.data"); + target = stream->WriteStringMaybeAliased( + 5, this->_internal_data(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:mp.body) + return target; +} + +size_t body::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:mp.body) + size_t total_size = 0; + + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string password = 2; + if (this->password().size() > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_password()); + } + + // string data = 5; + if (this->data().size() > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_data()); + } + + // uint64 account = 1; + if (this->account() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64Size( + this->_internal_account()); + } + + // uint64 target = 3; + if (this->target() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64Size( + this->_internal_target()); + } + + // uint64 source = 4; + if (this->source() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64Size( + this->_internal_source()); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( + _internal_metadata_, total_size, &_cached_size_); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void body::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:mp.body) + GOOGLE_DCHECK_NE(&from, this); + const body* source = + ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( + &from); + if (source == nullptr) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:mp.body) + ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:mp.body) + MergeFrom(*source); + } +} + +void body::MergeFrom(const body& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:mp.body) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.password().size() > 0) { + _internal_set_password(from._internal_password()); + } + if (from.data().size() > 0) { + _internal_set_data(from._internal_data()); + } + if (from.account() != 0) { + _internal_set_account(from._internal_account()); + } + if (from.target() != 0) { + _internal_set_target(from._internal_target()); + } + if (from.source() != 0) { + _internal_set_source(from._internal_source()); + } +} + +void body::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:mp.body) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void body::CopyFrom(const body& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:mp.body) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool body::IsInitialized() const { + return true; +} + +void body::InternalSwap(body* other) { + using std::swap; + _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); + password_.Swap(&other->password_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + data_.Swap(&other->data_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(body, source_) + + sizeof(body::source_) + - PROTOBUF_FIELD_OFFSET(body, account_)>( + reinterpret_cast(&account_), + reinterpret_cast(&other->account_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata body::GetMetadata() const { + return GetMetadataStatic(); +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::mp::body* Arena::CreateMaybeMessage< ::mp::body >(Arena* arena) { + return Arena::CreateMessageInternal< ::mp::body >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/MP/proto/mp.cqi.pb.cc b/MP/proto/mp.cqi.pb.cc new file mode 100644 index 0000000..63adcda --- /dev/null +++ b/MP/proto/mp.cqi.pb.cc @@ -0,0 +1,334 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.cqi.proto + +#include "proto/mp.cqi.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include +namespace mp { +class cqiDefaultTypeInternal { + public: + ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed _instance; +} _cqi_default_instance_; +} // namespace mp +static void InitDefaultsscc_info_cqi_mp_2ecqi_2eproto() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::mp::_cqi_default_instance_; + new (ptr) ::mp::cqi(); + ::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr); + } + ::mp::cqi::InitAsDefaultInstance(); +} + +::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_cqi_mp_2ecqi_2eproto = + {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_cqi_mp_2ecqi_2eproto}, {}}; + +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_mp_2ecqi_2eproto[1]; +static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_mp_2ecqi_2eproto[1]; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_mp_2ecqi_2eproto = nullptr; + +const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_mp_2ecqi_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::mp::cqi, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + PROTOBUF_FIELD_OFFSET(::mp::cqi, cqi_type_), + PROTOBUF_FIELD_OFFSET(::mp::cqi, cqi_version_), +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::mp::cqi)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::mp::_cqi_default_instance_), +}; + +const char descriptor_table_protodef_mp_2ecqi_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n\014mp.cqi.proto\022\002mp\";\n\003cqi\022\037\n\010cqi_type\030\001 " + "\001(\0162\r.mp.MP_C_TYPE\022\023\n\013cqi_version\030\002 \001(\002*" + "3\n\tMP_C_TYPE\022\021\n\rMC_TYPE_LINUX\020\000\022\023\n\017MC_TY" + "PE_WINDOWS\020\001b\006proto3" + ; +static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_mp_2ecqi_2eproto_deps[1] = { +}; +static ::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase*const descriptor_table_mp_2ecqi_2eproto_sccs[1] = { + &scc_info_cqi_mp_2ecqi_2eproto.base, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_mp_2ecqi_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2ecqi_2eproto = { + false, false, descriptor_table_protodef_mp_2ecqi_2eproto, "mp.cqi.proto", 140, + &descriptor_table_mp_2ecqi_2eproto_once, descriptor_table_mp_2ecqi_2eproto_sccs, descriptor_table_mp_2ecqi_2eproto_deps, 1, 0, + schemas, file_default_instances, TableStruct_mp_2ecqi_2eproto::offsets, + file_level_metadata_mp_2ecqi_2eproto, 1, file_level_enum_descriptors_mp_2ecqi_2eproto, file_level_service_descriptors_mp_2ecqi_2eproto, +}; + +// Force running AddDescriptors() at dynamic initialization time. +static bool dynamic_init_dummy_mp_2ecqi_2eproto = (static_cast(::PROTOBUF_NAMESPACE_ID::internal::AddDescriptors(&descriptor_table_mp_2ecqi_2eproto)), true); +namespace mp { +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MP_C_TYPE_descriptor() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_mp_2ecqi_2eproto); + return file_level_enum_descriptors_mp_2ecqi_2eproto[0]; +} +bool MP_C_TYPE_IsValid(int value) { + switch (value) { + case 0: + case 1: + return true; + default: + return false; + } +} + + +// =================================================================== + +void cqi::InitAsDefaultInstance() { +} +class cqi::_Internal { + public: +}; + +cqi::cqi(::PROTOBUF_NAMESPACE_ID::Arena* arena) + : ::PROTOBUF_NAMESPACE_ID::Message(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:mp.cqi) +} +cqi::cqi(const cqi& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::memcpy(&cqi_type_, &from.cqi_type_, + static_cast(reinterpret_cast(&cqi_version_) - + reinterpret_cast(&cqi_type_)) + sizeof(cqi_version_)); + // @@protoc_insertion_point(copy_constructor:mp.cqi) +} + +void cqi::SharedCtor() { + ::memset(&cqi_type_, 0, static_cast( + reinterpret_cast(&cqi_version_) - + reinterpret_cast(&cqi_type_)) + sizeof(cqi_version_)); +} + +cqi::~cqi() { + // @@protoc_insertion_point(destructor:mp.cqi) + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +void cqi::SharedDtor() { + GOOGLE_DCHECK(GetArena() == nullptr); +} + +void cqi::ArenaDtor(void* object) { + cqi* _this = reinterpret_cast< cqi* >(object); + (void)_this; +} +void cqi::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void cqi::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const cqi& cqi::default_instance() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&::scc_info_cqi_mp_2ecqi_2eproto.base); + return *internal_default_instance(); +} + + +void cqi::Clear() { +// @@protoc_insertion_point(message_clear_start:mp.cqi) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + ::memset(&cqi_type_, 0, static_cast( + reinterpret_cast(&cqi_version_) - + reinterpret_cast(&cqi_type_)) + sizeof(cqi_version_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* cqi::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena; + while (!ctx->Done(&ptr)) { + ::PROTOBUF_NAMESPACE_ID::uint32 tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + CHK_(ptr); + switch (tag >> 3) { + // .mp.MP_C_TYPE cqi_type = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) { + ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + _internal_set_cqi_type(static_cast<::mp::MP_C_TYPE>(val)); + } else goto handle_unusual; + continue; + // float cqi_version = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 21)) { + cqi_version_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr); + ptr += sizeof(float); + } else goto handle_unusual; + continue; + default: { + handle_unusual: + if ((tag & 7) == 4 || tag == 0) { + ctx->SetLastTag(tag); + goto success; + } + ptr = UnknownFieldParse(tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + continue; + } + } // switch + } // while +success: + return ptr; +failure: + ptr = nullptr; + goto success; +#undef CHK_ +} + +::PROTOBUF_NAMESPACE_ID::uint8* cqi::_InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:mp.cqi) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // .mp.MP_C_TYPE cqi_type = 1; + if (this->cqi_type() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( + 1, this->_internal_cqi_type(), target); + } + + // float cqi_version = 2; + if (!(this->cqi_version() <= 0 && this->cqi_version() >= 0)) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(2, this->_internal_cqi_version(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:mp.cqi) + return target; +} + +size_t cqi::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:mp.cqi) + size_t total_size = 0; + + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .mp.MP_C_TYPE cqi_type = 1; + if (this->cqi_type() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_cqi_type()); + } + + // float cqi_version = 2; + if (!(this->cqi_version() <= 0 && this->cqi_version() >= 0)) { + total_size += 1 + 4; + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( + _internal_metadata_, total_size, &_cached_size_); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void cqi::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:mp.cqi) + GOOGLE_DCHECK_NE(&from, this); + const cqi* source = + ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( + &from); + if (source == nullptr) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:mp.cqi) + ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:mp.cqi) + MergeFrom(*source); + } +} + +void cqi::MergeFrom(const cqi& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:mp.cqi) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.cqi_type() != 0) { + _internal_set_cqi_type(from._internal_cqi_type()); + } + if (!(from.cqi_version() <= 0 && from.cqi_version() >= 0)) { + _internal_set_cqi_version(from._internal_cqi_version()); + } +} + +void cqi::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:mp.cqi) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void cqi::CopyFrom(const cqi& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:mp.cqi) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool cqi::IsInitialized() const { + return true; +} + +void cqi::InternalSwap(cqi* other) { + using std::swap; + _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(cqi, cqi_version_) + + sizeof(cqi::cqi_version_) + - PROTOBUF_FIELD_OFFSET(cqi, cqi_type_)>( + reinterpret_cast(&cqi_type_), + reinterpret_cast(&other->cqi_type_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata cqi::GetMetadata() const { + return GetMetadataStatic(); +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::mp::cqi* Arena::CreateMaybeMessage< ::mp::cqi >(Arena* arena) { + return Arena::CreateMessageInternal< ::mp::cqi >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/MP/proto/mp.mph.pb.cc b/MP/proto/mp.mph.pb.cc new file mode 100644 index 0000000..f23453a --- /dev/null +++ b/MP/proto/mp.mph.pb.cc @@ -0,0 +1,432 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.mph.proto + +#include "proto/mp.mph.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include +namespace mp { +class mphDefaultTypeInternal { + public: + ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed _instance; +} _mph_default_instance_; +} // namespace mp +static void InitDefaultsscc_info_mph_mp_2emph_2eproto() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::mp::_mph_default_instance_; + new (ptr) ::mp::mph(); + ::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr); + } + ::mp::mph::InitAsDefaultInstance(); +} + +::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_mph_mp_2emph_2eproto = + {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_mph_mp_2emph_2eproto}, {}}; + +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_mp_2emph_2eproto[1]; +static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_mp_2emph_2eproto[1]; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_mp_2emph_2eproto = nullptr; + +const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_mp_2emph_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::mp::mph, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + PROTOBUF_FIELD_OFFSET(::mp::mph, mpb_size_), + PROTOBUF_FIELD_OFFSET(::mp::mph, mp_id_), + PROTOBUF_FIELD_OFFSET(::mp::mph, mp_sum_), + PROTOBUF_FIELD_OFFSET(::mp::mph, mp_type_), + PROTOBUF_FIELD_OFFSET(::mp::mph, path_), +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::mp::mph)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::mp::_mph_default_instance_), +}; + +const char descriptor_table_protodef_mp_2emph_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n\014mp.mph.proto\022\002mp\"b\n\003mph\022\020\n\010mpb_size\030\001 " + "\001(\r\022\r\n\005mp_id\030\002 \001(\004\022\016\n\006mp_sum\030\003 \001(\r\022\034\n\007mp" + "_type\030\004 \001(\0162\013.mp.MP_TYPE\022\014\n\004path\030\005 \001(\t*\230" + "\001\n\007MP_TYPE\022\024\n\020MP_REQUEST_LOGIN\020\000\022\025\n\021MP_R" + "EQUEST_LOGOUT\020\001\022\027\n\023MP_REQUEST_REGISTER\020\002" + "\022\025\n\021MP_RESPONSE_LOGIN\020\024\022\026\n\022MP_RESPONSE_L" + "OGOUT\020\025\022\030\n\024MP_RESPONSE_REGISTER\020\026b\006proto" + "3" + ; +static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_mp_2emph_2eproto_deps[1] = { +}; +static ::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase*const descriptor_table_mp_2emph_2eproto_sccs[1] = { + &scc_info_mph_mp_2emph_2eproto.base, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_mp_2emph_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2emph_2eproto = { + false, false, descriptor_table_protodef_mp_2emph_2eproto, "mp.mph.proto", 281, + &descriptor_table_mp_2emph_2eproto_once, descriptor_table_mp_2emph_2eproto_sccs, descriptor_table_mp_2emph_2eproto_deps, 1, 0, + schemas, file_default_instances, TableStruct_mp_2emph_2eproto::offsets, + file_level_metadata_mp_2emph_2eproto, 1, file_level_enum_descriptors_mp_2emph_2eproto, file_level_service_descriptors_mp_2emph_2eproto, +}; + +// Force running AddDescriptors() at dynamic initialization time. +static bool dynamic_init_dummy_mp_2emph_2eproto = (static_cast(::PROTOBUF_NAMESPACE_ID::internal::AddDescriptors(&descriptor_table_mp_2emph_2eproto)), true); +namespace mp { +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MP_TYPE_descriptor() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_mp_2emph_2eproto); + return file_level_enum_descriptors_mp_2emph_2eproto[0]; +} +bool MP_TYPE_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 20: + case 21: + case 22: + return true; + default: + return false; + } +} + + +// =================================================================== + +void mph::InitAsDefaultInstance() { +} +class mph::_Internal { + public: +}; + +mph::mph(::PROTOBUF_NAMESPACE_ID::Arena* arena) + : ::PROTOBUF_NAMESPACE_ID::Message(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:mp.mph) +} +mph::mph(const mph& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + path_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (!from._internal_path().empty()) { + path_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_path(), + GetArena()); + } + ::memcpy(&mp_id_, &from.mp_id_, + static_cast(reinterpret_cast(&mp_type_) - + reinterpret_cast(&mp_id_)) + sizeof(mp_type_)); + // @@protoc_insertion_point(copy_constructor:mp.mph) +} + +void mph::SharedCtor() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&scc_info_mph_mp_2emph_2eproto.base); + path_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + ::memset(&mp_id_, 0, static_cast( + reinterpret_cast(&mp_type_) - + reinterpret_cast(&mp_id_)) + sizeof(mp_type_)); +} + +mph::~mph() { + // @@protoc_insertion_point(destructor:mp.mph) + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +void mph::SharedDtor() { + GOOGLE_DCHECK(GetArena() == nullptr); + path_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void mph::ArenaDtor(void* object) { + mph* _this = reinterpret_cast< mph* >(object); + (void)_this; +} +void mph::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void mph::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const mph& mph::default_instance() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&::scc_info_mph_mp_2emph_2eproto.base); + return *internal_default_instance(); +} + + +void mph::Clear() { +// @@protoc_insertion_point(message_clear_start:mp.mph) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + path_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + ::memset(&mp_id_, 0, static_cast( + reinterpret_cast(&mp_type_) - + reinterpret_cast(&mp_id_)) + sizeof(mp_type_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* mph::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena; + while (!ctx->Done(&ptr)) { + ::PROTOBUF_NAMESPACE_ID::uint32 tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + CHK_(ptr); + switch (tag >> 3) { + // uint32 mpb_size = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) { + mpb_size_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + // uint64 mp_id = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 16)) { + mp_id_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + // uint32 mp_sum = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 24)) { + mp_sum_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + // .mp.MP_TYPE mp_type = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 32)) { + ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + _internal_set_mp_type(static_cast<::mp::MP_TYPE>(val)); + } else goto handle_unusual; + continue; + // string path = 5; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 42)) { + auto str = _internal_mutable_path(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "mp.mph.path")); + CHK_(ptr); + } else goto handle_unusual; + continue; + default: { + handle_unusual: + if ((tag & 7) == 4 || tag == 0) { + ctx->SetLastTag(tag); + goto success; + } + ptr = UnknownFieldParse(tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + continue; + } + } // switch + } // while +success: + return ptr; +failure: + ptr = nullptr; + goto success; +#undef CHK_ +} + +::PROTOBUF_NAMESPACE_ID::uint8* mph::_InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:mp.mph) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // uint32 mpb_size = 1; + if (this->mpb_size() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(1, this->_internal_mpb_size(), target); + } + + // uint64 mp_id = 2; + if (this->mp_id() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(2, this->_internal_mp_id(), target); + } + + // uint32 mp_sum = 3; + if (this->mp_sum() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(3, this->_internal_mp_sum(), target); + } + + // .mp.MP_TYPE mp_type = 4; + if (this->mp_type() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( + 4, this->_internal_mp_type(), target); + } + + // string path = 5; + if (this->path().size() > 0) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_path().data(), static_cast(this->_internal_path().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "mp.mph.path"); + target = stream->WriteStringMaybeAliased( + 5, this->_internal_path(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:mp.mph) + return target; +} + +size_t mph::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:mp.mph) + size_t total_size = 0; + + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string path = 5; + if (this->path().size() > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_path()); + } + + // uint64 mp_id = 2; + if (this->mp_id() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64Size( + this->_internal_mp_id()); + } + + // uint32 mpb_size = 1; + if (this->mpb_size() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32Size( + this->_internal_mpb_size()); + } + + // uint32 mp_sum = 3; + if (this->mp_sum() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32Size( + this->_internal_mp_sum()); + } + + // .mp.MP_TYPE mp_type = 4; + if (this->mp_type() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_mp_type()); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( + _internal_metadata_, total_size, &_cached_size_); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void mph::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:mp.mph) + GOOGLE_DCHECK_NE(&from, this); + const mph* source = + ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( + &from); + if (source == nullptr) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:mp.mph) + ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:mp.mph) + MergeFrom(*source); + } +} + +void mph::MergeFrom(const mph& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:mp.mph) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.path().size() > 0) { + _internal_set_path(from._internal_path()); + } + if (from.mp_id() != 0) { + _internal_set_mp_id(from._internal_mp_id()); + } + if (from.mpb_size() != 0) { + _internal_set_mpb_size(from._internal_mpb_size()); + } + if (from.mp_sum() != 0) { + _internal_set_mp_sum(from._internal_mp_sum()); + } + if (from.mp_type() != 0) { + _internal_set_mp_type(from._internal_mp_type()); + } +} + +void mph::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:mp.mph) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void mph::CopyFrom(const mph& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:mp.mph) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool mph::IsInitialized() const { + return true; +} + +void mph::InternalSwap(mph* other) { + using std::swap; + _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); + path_.Swap(&other->path_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(mph, mp_type_) + + sizeof(mph::mp_type_) + - PROTOBUF_FIELD_OFFSET(mph, mp_id_)>( + reinterpret_cast(&mp_id_), + reinterpret_cast(&other->mp_id_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata mph::GetMetadata() const { + return GetMetadataStatic(); +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::mp::mph* Arena::CreateMaybeMessage< ::mp::mph >(Arena* arena) { + return Arena::CreateMessageInternal< ::mp::mph >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/MP/proto/mp.request.pb.cc b/MP/proto/mp.request.pb.cc new file mode 100644 index 0000000..3d60605 --- /dev/null +++ b/MP/proto/mp.request.pb.cc @@ -0,0 +1,371 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.request.proto + +#include "mp.request.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include +extern PROTOBUF_INTERNAL_EXPORT_mp_2ebody_2eproto ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_body_mp_2ebody_2eproto; +extern PROTOBUF_INTERNAL_EXPORT_mp_2ecqi_2eproto ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_cqi_mp_2ecqi_2eproto; +namespace mp { +class requestDefaultTypeInternal { + public: + ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed _instance; +} _request_default_instance_; +} // namespace mp +static void InitDefaultsscc_info_request_mp_2erequest_2eproto() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::mp::_request_default_instance_; + new (ptr) ::mp::request(); + ::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr); + } + ::mp::request::InitAsDefaultInstance(); +} + +::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<2> scc_info_request_mp_2erequest_2eproto = + {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 2, 0, InitDefaultsscc_info_request_mp_2erequest_2eproto}, { + &scc_info_body_mp_2ebody_2eproto.base, + &scc_info_cqi_mp_2ecqi_2eproto.base,}}; + +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_mp_2erequest_2eproto[1]; +static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_mp_2erequest_2eproto = nullptr; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_mp_2erequest_2eproto = nullptr; + +const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_mp_2erequest_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::mp::request, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + PROTOBUF_FIELD_OFFSET(::mp::request, body_), + PROTOBUF_FIELD_OFFSET(::mp::request, cqi_), +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::mp::request)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::mp::_request_default_instance_), +}; + +const char descriptor_table_protodef_mp_2erequest_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n\020mp.request.proto\022\002mp\032\rmp.body.proto\032\014m" + "p.cqi.proto\"7\n\007request\022\026\n\004body\030\002 \001(\0132\010.m" + "p.body\022\024\n\003cqi\030\003 \001(\0132\007.mp.cqib\006proto3" + ; +static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_mp_2erequest_2eproto_deps[2] = { + &::descriptor_table_mp_2ebody_2eproto, + &::descriptor_table_mp_2ecqi_2eproto, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase*const descriptor_table_mp_2erequest_2eproto_sccs[1] = { + &scc_info_request_mp_2erequest_2eproto.base, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_mp_2erequest_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2erequest_2eproto = { + false, false, descriptor_table_protodef_mp_2erequest_2eproto, "mp.request.proto", 116, + &descriptor_table_mp_2erequest_2eproto_once, descriptor_table_mp_2erequest_2eproto_sccs, descriptor_table_mp_2erequest_2eproto_deps, 1, 2, + schemas, file_default_instances, TableStruct_mp_2erequest_2eproto::offsets, + file_level_metadata_mp_2erequest_2eproto, 1, file_level_enum_descriptors_mp_2erequest_2eproto, file_level_service_descriptors_mp_2erequest_2eproto, +}; + +// Force running AddDescriptors() at dynamic initialization time. +static bool dynamic_init_dummy_mp_2erequest_2eproto = (static_cast(::PROTOBUF_NAMESPACE_ID::internal::AddDescriptors(&descriptor_table_mp_2erequest_2eproto)), true); +namespace mp { + +// =================================================================== + +void request::InitAsDefaultInstance() { + ::mp::_request_default_instance_._instance.get_mutable()->body_ = const_cast< ::mp::body*>( + ::mp::body::internal_default_instance()); + ::mp::_request_default_instance_._instance.get_mutable()->cqi_ = const_cast< ::mp::cqi*>( + ::mp::cqi::internal_default_instance()); +} +class request::_Internal { + public: + static const ::mp::body& body(const request* msg); + static const ::mp::cqi& cqi(const request* msg); +}; + +const ::mp::body& +request::_Internal::body(const request* msg) { + return *msg->body_; +} +const ::mp::cqi& +request::_Internal::cqi(const request* msg) { + return *msg->cqi_; +} +void request::clear_body() { + if (GetArena() == nullptr && body_ != nullptr) { + delete body_; + } + body_ = nullptr; +} +void request::clear_cqi() { + if (GetArena() == nullptr && cqi_ != nullptr) { + delete cqi_; + } + cqi_ = nullptr; +} +request::request(::PROTOBUF_NAMESPACE_ID::Arena* arena) + : ::PROTOBUF_NAMESPACE_ID::Message(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:mp.request) +} +request::request(const request& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_body()) { + body_ = new ::mp::body(*from.body_); + } else { + body_ = nullptr; + } + if (from._internal_has_cqi()) { + cqi_ = new ::mp::cqi(*from.cqi_); + } else { + cqi_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:mp.request) +} + +void request::SharedCtor() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&scc_info_request_mp_2erequest_2eproto.base); + ::memset(&body_, 0, static_cast( + reinterpret_cast(&cqi_) - + reinterpret_cast(&body_)) + sizeof(cqi_)); +} + +request::~request() { + // @@protoc_insertion_point(destructor:mp.request) + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +void request::SharedDtor() { + GOOGLE_DCHECK(GetArena() == nullptr); + if (this != internal_default_instance()) delete body_; + if (this != internal_default_instance()) delete cqi_; +} + +void request::ArenaDtor(void* object) { + request* _this = reinterpret_cast< request* >(object); + (void)_this; +} +void request::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void request::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const request& request::default_instance() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&::scc_info_request_mp_2erequest_2eproto.base); + return *internal_default_instance(); +} + + +void request::Clear() { +// @@protoc_insertion_point(message_clear_start:mp.request) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArena() == nullptr && body_ != nullptr) { + delete body_; + } + body_ = nullptr; + if (GetArena() == nullptr && cqi_ != nullptr) { + delete cqi_; + } + cqi_ = nullptr; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* request::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena; + while (!ctx->Done(&ptr)) { + ::PROTOBUF_NAMESPACE_ID::uint32 tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + CHK_(ptr); + switch (tag >> 3) { + // .mp.body body = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) { + ptr = ctx->ParseMessage(_internal_mutable_body(), ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + // .mp.cqi cqi = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) { + ptr = ctx->ParseMessage(_internal_mutable_cqi(), ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + default: { + handle_unusual: + if ((tag & 7) == 4 || tag == 0) { + ctx->SetLastTag(tag); + goto success; + } + ptr = UnknownFieldParse(tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + continue; + } + } // switch + } // while +success: + return ptr; +failure: + ptr = nullptr; + goto success; +#undef CHK_ +} + +::PROTOBUF_NAMESPACE_ID::uint8* request::_InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:mp.request) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // .mp.body body = 2; + if (this->has_body()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 2, _Internal::body(this), target, stream); + } + + // .mp.cqi cqi = 3; + if (this->has_cqi()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 3, _Internal::cqi(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:mp.request) + return target; +} + +size_t request::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:mp.request) + size_t total_size = 0; + + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .mp.body body = 2; + if (this->has_body()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *body_); + } + + // .mp.cqi cqi = 3; + if (this->has_cqi()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *cqi_); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( + _internal_metadata_, total_size, &_cached_size_); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void request::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:mp.request) + GOOGLE_DCHECK_NE(&from, this); + const request* source = + ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( + &from); + if (source == nullptr) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:mp.request) + ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:mp.request) + MergeFrom(*source); + } +} + +void request::MergeFrom(const request& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:mp.request) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.has_body()) { + _internal_mutable_body()->::mp::body::MergeFrom(from._internal_body()); + } + if (from.has_cqi()) { + _internal_mutable_cqi()->::mp::cqi::MergeFrom(from._internal_cqi()); + } +} + +void request::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:mp.request) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void request::CopyFrom(const request& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:mp.request) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool request::IsInitialized() const { + return true; +} + +void request::InternalSwap(request* other) { + using std::swap; + _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(request, cqi_) + + sizeof(request::cqi_) + - PROTOBUF_FIELD_OFFSET(request, body_)>( + reinterpret_cast(&body_), + reinterpret_cast(&other->body_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata request::GetMetadata() const { + return GetMetadataStatic(); +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::mp::request* Arena::CreateMaybeMessage< ::mp::request >(Arena* arena) { + return Arena::CreateMessageInternal< ::mp::request >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/MP/proto/mp.response.pb.cc b/MP/proto/mp.response.pb.cc new file mode 100644 index 0000000..381ae42 --- /dev/null +++ b/MP/proto/mp.response.pb.cc @@ -0,0 +1,311 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.response.proto + +#include "proto/mp.response.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include +extern PROTOBUF_INTERNAL_EXPORT_mp_2esri_2eproto ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_sri_mp_2esri_2eproto; +namespace mp { +class responseDefaultTypeInternal { + public: + ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed _instance; +} _response_default_instance_; +} // namespace mp +static void InitDefaultsscc_info_response_mp_2eresponse_2eproto() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::mp::_response_default_instance_; + new (ptr) ::mp::response(); + ::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr); + } + ::mp::response::InitAsDefaultInstance(); +} + +::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<1> scc_info_response_mp_2eresponse_2eproto = + {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 1, 0, InitDefaultsscc_info_response_mp_2eresponse_2eproto}, { + &scc_info_sri_mp_2esri_2eproto.base,}}; + +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_mp_2eresponse_2eproto[1]; +static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_mp_2eresponse_2eproto = nullptr; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_mp_2eresponse_2eproto = nullptr; + +const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_mp_2eresponse_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::mp::response, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + PROTOBUF_FIELD_OFFSET(::mp::response, sri_), +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::mp::response)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::mp::_response_default_instance_), +}; + +const char descriptor_table_protodef_mp_2eresponse_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n\021mp.response.proto\022\002mp\032\014mp.sri.proto\" \n" + "\010response\022\024\n\003sri\030\003 \001(\0132\007.mp.srib\006proto3" + ; +static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_mp_2eresponse_2eproto_deps[1] = { + &::descriptor_table_mp_2esri_2eproto, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase*const descriptor_table_mp_2eresponse_2eproto_sccs[1] = { + &scc_info_response_mp_2eresponse_2eproto.base, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_mp_2eresponse_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2eresponse_2eproto = { + false, false, descriptor_table_protodef_mp_2eresponse_2eproto, "mp.response.proto", 79, + &descriptor_table_mp_2eresponse_2eproto_once, descriptor_table_mp_2eresponse_2eproto_sccs, descriptor_table_mp_2eresponse_2eproto_deps, 1, 1, + schemas, file_default_instances, TableStruct_mp_2eresponse_2eproto::offsets, + file_level_metadata_mp_2eresponse_2eproto, 1, file_level_enum_descriptors_mp_2eresponse_2eproto, file_level_service_descriptors_mp_2eresponse_2eproto, +}; + +// Force running AddDescriptors() at dynamic initialization time. +static bool dynamic_init_dummy_mp_2eresponse_2eproto = (static_cast(::PROTOBUF_NAMESPACE_ID::internal::AddDescriptors(&descriptor_table_mp_2eresponse_2eproto)), true); +namespace mp { + +// =================================================================== + +void response::InitAsDefaultInstance() { + ::mp::_response_default_instance_._instance.get_mutable()->sri_ = const_cast< ::mp::sri*>( + ::mp::sri::internal_default_instance()); +} +class response::_Internal { + public: + static const ::mp::sri& sri(const response* msg); +}; + +const ::mp::sri& +response::_Internal::sri(const response* msg) { + return *msg->sri_; +} +void response::clear_sri() { + if (GetArena() == nullptr && sri_ != nullptr) { + delete sri_; + } + sri_ = nullptr; +} +response::response(::PROTOBUF_NAMESPACE_ID::Arena* arena) + : ::PROTOBUF_NAMESPACE_ID::Message(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:mp.response) +} +response::response(const response& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_sri()) { + sri_ = new ::mp::sri(*from.sri_); + } else { + sri_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:mp.response) +} + +void response::SharedCtor() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&scc_info_response_mp_2eresponse_2eproto.base); + sri_ = nullptr; +} + +response::~response() { + // @@protoc_insertion_point(destructor:mp.response) + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +void response::SharedDtor() { + GOOGLE_DCHECK(GetArena() == nullptr); + if (this != internal_default_instance()) delete sri_; +} + +void response::ArenaDtor(void* object) { + response* _this = reinterpret_cast< response* >(object); + (void)_this; +} +void response::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void response::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const response& response::default_instance() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&::scc_info_response_mp_2eresponse_2eproto.base); + return *internal_default_instance(); +} + + +void response::Clear() { +// @@protoc_insertion_point(message_clear_start:mp.response) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArena() == nullptr && sri_ != nullptr) { + delete sri_; + } + sri_ = nullptr; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* response::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena; + while (!ctx->Done(&ptr)) { + ::PROTOBUF_NAMESPACE_ID::uint32 tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + CHK_(ptr); + switch (tag >> 3) { + // .mp.sri sri = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) { + ptr = ctx->ParseMessage(_internal_mutable_sri(), ptr); + CHK_(ptr); + } else goto handle_unusual; + continue; + default: { + handle_unusual: + if ((tag & 7) == 4 || tag == 0) { + ctx->SetLastTag(tag); + goto success; + } + ptr = UnknownFieldParse(tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + continue; + } + } // switch + } // while +success: + return ptr; +failure: + ptr = nullptr; + goto success; +#undef CHK_ +} + +::PROTOBUF_NAMESPACE_ID::uint8* response::_InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:mp.response) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // .mp.sri sri = 3; + if (this->has_sri()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 3, _Internal::sri(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:mp.response) + return target; +} + +size_t response::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:mp.response) + size_t total_size = 0; + + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .mp.sri sri = 3; + if (this->has_sri()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *sri_); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( + _internal_metadata_, total_size, &_cached_size_); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void response::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:mp.response) + GOOGLE_DCHECK_NE(&from, this); + const response* source = + ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( + &from); + if (source == nullptr) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:mp.response) + ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:mp.response) + MergeFrom(*source); + } +} + +void response::MergeFrom(const response& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:mp.response) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.has_sri()) { + _internal_mutable_sri()->::mp::sri::MergeFrom(from._internal_sri()); + } +} + +void response::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:mp.response) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void response::CopyFrom(const response& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:mp.response) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool response::IsInitialized() const { + return true; +} + +void response::InternalSwap(response* other) { + using std::swap; + _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); + swap(sri_, other->sri_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata response::GetMetadata() const { + return GetMetadataStatic(); +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::mp::response* Arena::CreateMaybeMessage< ::mp::response >(Arena* arena) { + return Arena::CreateMessageInternal< ::mp::response >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/MP/proto/mp.sri.pb.cc b/MP/proto/mp.sri.pb.cc new file mode 100644 index 0000000..7ac8436 --- /dev/null +++ b/MP/proto/mp.sri.pb.cc @@ -0,0 +1,428 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.sri.proto + +#include "proto/mp.sri.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include +namespace mp { +class sriDefaultTypeInternal { + public: + ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed _instance; +} _sri_default_instance_; +} // namespace mp +static void InitDefaultsscc_info_sri_mp_2esri_2eproto() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::mp::_sri_default_instance_; + new (ptr) ::mp::sri(); + ::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr); + } + ::mp::sri::InitAsDefaultInstance(); +} + +::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_sri_mp_2esri_2eproto = + {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_sri_mp_2esri_2eproto}, {}}; + +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_mp_2esri_2eproto[1]; +static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_mp_2esri_2eproto[1]; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_mp_2esri_2eproto = nullptr; + +const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_mp_2esri_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::mp::sri, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + PROTOBUF_FIELD_OFFSET(::mp::sri, sri_code_), + PROTOBUF_FIELD_OFFSET(::mp::sri, sri_username_), + PROTOBUF_FIELD_OFFSET(::mp::sri, sri_msg_), + PROTOBUF_FIELD_OFFSET(::mp::sri, sri_token_), +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::mp::sri)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::mp::_sri_default_instance_), +}; + +const char descriptor_table_protodef_mp_2esri_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n\014mp.sri.proto\022\002mp\"]\n\003sri\022\034\n\010sri_code\030\001 " + "\001(\0162\n.mp.MP_SRI\022\024\n\014sri_username\030\002 \001(\t\022\017\n" + "\007sri_msg\030\003 \001(\t\022\021\n\tsri_token\030\004 \001(\t*\246\001\n\006MP" + "_SRI\022\030\n\024MP_LOGIN_ACCOUNT_NOT\020\000\022\024\n\020MP_LOG" + "IN_SUCCESS\020\001\022\021\n\rMP_LOGIN_FAIL\020\002\022\027\n\023MP_RE" + "GISTER_SUCCESS\020\n\022\025\n\021MP_REGISTER_EXIST\020\013\022" + "\025\n\021MP_LOGOUT_SUCCESS\020\024\022\022\n\016MP_LOGOUT_FAIL" + "\020\025b\006proto3" + ; +static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_mp_2esri_2eproto_deps[1] = { +}; +static ::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase*const descriptor_table_mp_2esri_2eproto_sccs[1] = { + &scc_info_sri_mp_2esri_2eproto.base, +}; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_mp_2esri_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2esri_2eproto = { + false, false, descriptor_table_protodef_mp_2esri_2eproto, "mp.sri.proto", 290, + &descriptor_table_mp_2esri_2eproto_once, descriptor_table_mp_2esri_2eproto_sccs, descriptor_table_mp_2esri_2eproto_deps, 1, 0, + schemas, file_default_instances, TableStruct_mp_2esri_2eproto::offsets, + file_level_metadata_mp_2esri_2eproto, 1, file_level_enum_descriptors_mp_2esri_2eproto, file_level_service_descriptors_mp_2esri_2eproto, +}; + +// Force running AddDescriptors() at dynamic initialization time. +static bool dynamic_init_dummy_mp_2esri_2eproto = (static_cast(::PROTOBUF_NAMESPACE_ID::internal::AddDescriptors(&descriptor_table_mp_2esri_2eproto)), true); +namespace mp { +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MP_SRI_descriptor() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_mp_2esri_2eproto); + return file_level_enum_descriptors_mp_2esri_2eproto[0]; +} +bool MP_SRI_IsValid(int value) { + switch (value) { + case 0: + case 1: + case 2: + case 10: + case 11: + case 20: + case 21: + return true; + default: + return false; + } +} + + +// =================================================================== + +void sri::InitAsDefaultInstance() { +} +class sri::_Internal { + public: +}; + +sri::sri(::PROTOBUF_NAMESPACE_ID::Arena* arena) + : ::PROTOBUF_NAMESPACE_ID::Message(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:mp.sri) +} +sri::sri(const sri& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + sri_username_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (!from._internal_sri_username().empty()) { + sri_username_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_sri_username(), + GetArena()); + } + sri_msg_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (!from._internal_sri_msg().empty()) { + sri_msg_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_sri_msg(), + GetArena()); + } + sri_token_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + if (!from._internal_sri_token().empty()) { + sri_token_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_sri_token(), + GetArena()); + } + sri_code_ = from.sri_code_; + // @@protoc_insertion_point(copy_constructor:mp.sri) +} + +void sri::SharedCtor() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&scc_info_sri_mp_2esri_2eproto.base); + sri_username_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + sri_msg_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + sri_token_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + sri_code_ = 0; +} + +sri::~sri() { + // @@protoc_insertion_point(destructor:mp.sri) + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +void sri::SharedDtor() { + GOOGLE_DCHECK(GetArena() == nullptr); + sri_username_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + sri_msg_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + sri_token_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void sri::ArenaDtor(void* object) { + sri* _this = reinterpret_cast< sri* >(object); + (void)_this; +} +void sri::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void sri::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const sri& sri::default_instance() { + ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&::scc_info_sri_mp_2esri_2eproto.base); + return *internal_default_instance(); +} + + +void sri::Clear() { +// @@protoc_insertion_point(message_clear_start:mp.sri) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + sri_username_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + sri_msg_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + sri_token_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + sri_code_ = 0; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* sri::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena; + while (!ctx->Done(&ptr)) { + ::PROTOBUF_NAMESPACE_ID::uint32 tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + CHK_(ptr); + switch (tag >> 3) { + // .mp.MP_SRI sri_code = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) { + ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + _internal_set_sri_code(static_cast<::mp::MP_SRI>(val)); + } else goto handle_unusual; + continue; + // string sri_username = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) { + auto str = _internal_mutable_sri_username(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "mp.sri.sri_username")); + CHK_(ptr); + } else goto handle_unusual; + continue; + // string sri_msg = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) { + auto str = _internal_mutable_sri_msg(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "mp.sri.sri_msg")); + CHK_(ptr); + } else goto handle_unusual; + continue; + // string sri_token = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 34)) { + auto str = _internal_mutable_sri_token(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "mp.sri.sri_token")); + CHK_(ptr); + } else goto handle_unusual; + continue; + default: { + handle_unusual: + if ((tag & 7) == 4 || tag == 0) { + ctx->SetLastTag(tag); + goto success; + } + ptr = UnknownFieldParse(tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + continue; + } + } // switch + } // while +success: + return ptr; +failure: + ptr = nullptr; + goto success; +#undef CHK_ +} + +::PROTOBUF_NAMESPACE_ID::uint8* sri::_InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:mp.sri) + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // .mp.MP_SRI sri_code = 1; + if (this->sri_code() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray( + 1, this->_internal_sri_code(), target); + } + + // string sri_username = 2; + if (this->sri_username().size() > 0) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_sri_username().data(), static_cast(this->_internal_sri_username().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "mp.sri.sri_username"); + target = stream->WriteStringMaybeAliased( + 2, this->_internal_sri_username(), target); + } + + // string sri_msg = 3; + if (this->sri_msg().size() > 0) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_sri_msg().data(), static_cast(this->_internal_sri_msg().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "mp.sri.sri_msg"); + target = stream->WriteStringMaybeAliased( + 3, this->_internal_sri_msg(), target); + } + + // string sri_token = 4; + if (this->sri_token().size() > 0) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_sri_token().data(), static_cast(this->_internal_sri_token().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "mp.sri.sri_token"); + target = stream->WriteStringMaybeAliased( + 4, this->_internal_sri_token(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:mp.sri) + return target; +} + +size_t sri::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:mp.sri) + size_t total_size = 0; + + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string sri_username = 2; + if (this->sri_username().size() > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_sri_username()); + } + + // string sri_msg = 3; + if (this->sri_msg().size() > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_sri_msg()); + } + + // string sri_token = 4; + if (this->sri_token().size() > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_sri_token()); + } + + // .mp.MP_SRI sri_code = 1; + if (this->sri_code() != 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_sri_code()); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( + _internal_metadata_, total_size, &_cached_size_); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void sri::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:mp.sri) + GOOGLE_DCHECK_NE(&from, this); + const sri* source = + ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( + &from); + if (source == nullptr) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:mp.sri) + ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:mp.sri) + MergeFrom(*source); + } +} + +void sri::MergeFrom(const sri& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:mp.sri) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.sri_username().size() > 0) { + _internal_set_sri_username(from._internal_sri_username()); + } + if (from.sri_msg().size() > 0) { + _internal_set_sri_msg(from._internal_sri_msg()); + } + if (from.sri_token().size() > 0) { + _internal_set_sri_token(from._internal_sri_token()); + } + if (from.sri_code() != 0) { + _internal_set_sri_code(from._internal_sri_code()); + } +} + +void sri::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:mp.sri) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void sri::CopyFrom(const sri& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:mp.sri) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool sri::IsInitialized() const { + return true; +} + +void sri::InternalSwap(sri* other) { + using std::swap; + _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); + sri_username_.Swap(&other->sri_username_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + sri_msg_.Swap(&other->sri_msg_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + sri_token_.Swap(&other->sri_token_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); + swap(sri_code_, other->sri_code_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata sri::GetMetadata() const { + return GetMetadataStatic(); +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::mp::sri* Arena::CreateMaybeMessage< ::mp::sri >(Arena* arena) { + return Arena::CreateMessageInternal< ::mp::sri >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/MS/CMakeLists.txt b/MS/CMakeLists.txt new file mode 100644 index 0000000..134af1f --- /dev/null +++ b/MS/CMakeLists.txt @@ -0,0 +1,40 @@ +project(MS) + +aux_source_directory(pool/thread DIR_THREAD_POOL) +aux_source_directory(pool/mem DIR_MEM_POOL) +aux_source_directory(pool/object DIR_OBJECT_POOL) +aux_source_directory(mmm DIR_MMM) +aux_source_directory(tools DIR_TOOLS) + +include_directories(${CMAKE_SOURCE_DIR}/include/libevent) +include_directories(${CMAKE_SOURCE_DIR}/include/mp) +include_directories(${CMAKE_SOURCE_DIR}/include/ini) +include_directories(${CMAKE_SOURCE_DIR}/include/mysql++) +include_directories(${CMAKE_SOURCE_DIR}/include/mysql++/mysql) +include_directories(${CMAKE_SOURCE_DIR}/MDB/imm_mysqldb) +include_directories(${CMAKE_SOURCE_DIR}/MS/works) +message("CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/include/libevent") + +link_directories(${CMAKE_SOURCE_DIR}/lib/libevent) +link_directories(${CMAKE_SOURCE_DIR}/lib/tbb) + +add_subdirectory(works) + +add_executable(MS + main.cpp + MS.cpp + MS.cpp + ${DIR_THREAD_POOL} + ${DIR_MMM} + ${DIR_MEM_POOL} + ${DIR_OBJECT_POOL} + ${DIR_TOOLS} +) + +target_link_libraries(MS + works + event + tbb + imm_mysqldb + MP + ) \ No newline at end of file diff --git a/MS/MS.cpp b/MS/MS.cpp new file mode 100644 index 0000000..eabbb30 --- /dev/null +++ b/MS/MS.cpp @@ -0,0 +1,83 @@ +// +// Created by dongl on 23-4-8. +// + +#include "MS.h" +#include +#include +#include "event2/listener.h" + + +ev_pool* MS::pool = nullptr; +class management* MS::mage = nullptr; +MS::MS() { + + pool = new ev_pool(4); + pool->add_event_base(listener); + pool->add_event_bases(4); + pool->run(); + mage = new class management(); +} +MS::~MS() { + delete pool; + delete mage; +} + +void MS::listener() { + event_base *base = event_base_new(); + sockaddr_in sin = {0}; + memset(&sin, 0, sizeof(sin)); + sin = { + AF_INET, + htons(9999) + }; + evconnlistener *listener = + evconnlistener_new_bind(base, + MS::link, + base, + LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_EXEC | + LEV_OPT_DEFERRED_ACCEPT, + 10, + (sockaddr *) &sin, + sizeof(sin) + ); + event_base_dispatch(base); + evconnlistener_free(listener); + event_base_free(base); +} + + +void MS::link(struct evconnlistener *e, int fd, struct sockaddr *addr, int socklen, void *arg) { + if (!pool) { + perror("en: Prohibit manual static invocation MS::link()\n"); + return; + } + printf("listen_cb\n"); + pool->add_buffer_event(fd, read_cb, write_cb, event_cb, BEV_OPT_CLOSE_ON_FREE); + fflush(stdout); +} + +void MS::read_cb(struct bufferevent *bev, void *ctx) { + printf("[read]: %p, %p\n", ctx, bev); + mage->read_packet(bev); + fflush(stdout); +} + +void MS::write_cb(struct bufferevent *bev, void *ctx) { + printf("[write]: %p\n", ctx); + fflush(stdout); +} + +void MS::event_cb(struct bufferevent *bev, short what, void *ctx) { + printf("[event]: %p\n", ctx); + if (what == BEV_EVENT_EOF || BEV_EVENT_ERROR || BEV_EVENT_TIMEOUT) { + printf("客户端退出\n"); + handler::remove_user(bev); + bufferevent_free(bev); + } + + fflush(stdout); +} + + + diff --git a/MS/MS.h b/MS/MS.h new file mode 100644 index 0000000..06f8e9d --- /dev/null +++ b/MS/MS.h @@ -0,0 +1,28 @@ +// +// Created by dongl on 23-4-8. +// + +#ifndef IM_SERVER_H +#define IM_SERVER_H + +#include "tbb/tbb.h" +#include "event2/util.h" +#include "pool/thread/ev_pool.h" +#include "mmm/management.h" + +class MS { +public: + MS(); + virtual ~MS(); + static void link(struct evconnlistener *e, evutil_socket_t s, struct sockaddr *addr, int socklen, void *arg); + static void listener(); + static void read_cb(struct bufferevent *bev, void *ctx); + static void write_cb(struct bufferevent *bev, void *ctx); + static void event_cb(struct bufferevent *bev, short what, void *ctx); +private: + static ev_pool* pool; + static class management* mage; +}; + + +#endif //IM_SERVER_H diff --git a/MS/config/config.ini b/MS/config/config.ini new file mode 100644 index 0000000..4e4db08 --- /dev/null +++ b/MS/config/config.ini @@ -0,0 +1,10 @@ +[server-mapping] +0 = "controller/UserController" + + + + +[mysql] + +[redis] + diff --git a/MS/main.cpp b/MS/main.cpp new file mode 100644 index 0000000..ffe7fe6 --- /dev/null +++ b/MS/main.cpp @@ -0,0 +1,10 @@ +// +// Created by dongl on 23-4-17. +// + +#include "MS.h" + + +int main () { + MS(); +} \ No newline at end of file diff --git a/MS/mmm/agreement.cpp b/MS/mmm/agreement.cpp new file mode 100644 index 0000000..d7702e2 --- /dev/null +++ b/MS/mmm/agreement.cpp @@ -0,0 +1,41 @@ +// +// Created by dongl on 23-4-20. +// + +#include "agreement.h" +#include "Response.h" + + +agreement_request::agreement_request() : agreement() {} +agreement_request::~agreement_request() {} + +void agreement_request::set (std::shared_ptr &mph, std::shared_ptr& request, bufferevent* bev) { + m_mph = mph; + m_body = request->body(); + m_cqi = request->cqi(); + m_bev = bev; +} + +agreement_response::agreement_response() : agreement() {} +agreement_response::~agreement_response() {} + + +void agreement_response::set(mp::MP_TYPE type, mp::sri* sri, bufferevent* bev) { + auto resp = std::make_shared(mp::response()); + + m_sri = resp->sri(); + m_sri.set_sri_username(sri->sri_username()); + m_sri.set_sri_msg(sri->sri_msg()); + m_sri.set_sri_code(sri->sri_code()); + m_sri.set_sri_token(sri->sri_token()); + + m_bev = bev; +} + + + + + + + + diff --git a/MS/mmm/agreement.h b/MS/mmm/agreement.h new file mode 100644 index 0000000..032d59a --- /dev/null +++ b/MS/mmm/agreement.h @@ -0,0 +1,54 @@ +// +// Created by dongl on 23-4-20. +// + +#ifndef IM2_AGREEMENT_H +#define IM2_AGREEMENT_H + + +#include +#include "Body.h" +#include "proto/mp.mph.pb.h" +#include "proto/mp.cqi.pb.h" +#include "proto/mp.sri.pb.h" +#include "proto/mp.response.pb.h" +#include "proto/mp.request.pb.h" +#include "event2/bufferevent.h" + +class agreement { +public: + agreement(){} + virtual ~agreement() {} +}; + + +class agreement_request : public agreement{ +public: + agreement_request(); + ~agreement_request(); + +public: + void set (std::shared_ptr &mph, std::shared_ptr& request, bufferevent* bev); + +public: + std::shared_ptr m_mph; + mp::body m_body; + mp::cqi m_cqi; + bufferevent* m_bev; +}; + + +class agreement_response : public agreement { +public: + agreement_response(); + ~agreement_response() override; + +public: + void set (mp::MP_TYPE type, mp::sri* sri, bufferevent* bev); +public: + std::shared_ptr m_mph; + mp::sri m_sri; + bufferevent* m_bev; +}; + +#endif //IM2_AGREEMENT_H diff --git a/MS/mmm/analysis.h b/MS/mmm/analysis.h new file mode 100644 index 0000000..7b9c36a --- /dev/null +++ b/MS/mmm/analysis.h @@ -0,0 +1,40 @@ +// +// Created by dongl on 23-4-21. +// + +#ifndef IM2_ANALYSIS_H +#define IM2_ANALYSIS_H + +#include +#include +#include "proto/mp.request.pb.h" +#include "agreement.h" + + +class analysis { +public: + analysis(std::shared_ptr& mph, char* data, bufferevent* bev) : m_mph(mph), m_data(data), m_bev(bev) { + + } + + std::shared_ptr operator () () { + // agreement_request + auto type = m_mph->mp_type(); + auto agreementRequest = std::make_shared(agreement_request()); + + // request + auto request = std::make_shared(mp::request()); + request->ParseFromString(m_data); + agreementRequest->set(m_mph, request, m_bev); + + return agreementRequest; + } +private: + std::shared_ptr m_mph; + char* m_data = nullptr; + bufferevent* m_bev = nullptr; +}; + + + +#endif //IM2_ANALYSIS_H diff --git a/MS/mmm/handler.cpp b/MS/mmm/handler.cpp new file mode 100644 index 0000000..dfdda5e --- /dev/null +++ b/MS/mmm/handler.cpp @@ -0,0 +1,54 @@ +// +// Created by dongl on 23-4-28. +// + +#include "handler.h" +#include "Response.h" + +std::map handler::user_fd; + + +void handler::resp(const std::shared_ptr& request, + const std::shared_ptr& response) { + // 用户操作逻辑包 + auto resp = new Response((mp::MP_TYPE) (request->m_mph->mp_type() + 20), + response->m_sri.sri_code(), response->m_sri.sri_username(), + response->m_sri.sri_msg(), response->m_sri.sri_token()); + auto ret = resp->packet(); + + bufferevent_write(request->m_bev, ret.c_str(), ret.size()); + delete resp; +} + +void +handler::send(const std::shared_ptr &request, const std::shared_ptr &response) { + // 聊天消息包 + userinfo *user = user_fd.find(request->m_body.target())->second; + +} + + +void handler::add_user(const std::shared_ptr& request) { + auto ele = new userinfo(); + ele->bev = request->m_bev; + ele->ip = 0; + user_fd.insert({request->m_body.account(), ele}); +} + +void handler::remove_user(bufferevent *bev) { + uint64_t target_ele; + for (const auto &item: user_fd) { + if (bev == item.second->bev) { + target_ele = item.first; + break; + } + } + + user_fd.erase(target_ele); +} + +void handler::remove_user(const std::shared_ptr& request) { + user_fd.erase(request->m_body.account()); +} + + diff --git a/MS/mmm/handler.h b/MS/mmm/handler.h new file mode 100644 index 0000000..b63e83d --- /dev/null +++ b/MS/mmm/handler.h @@ -0,0 +1,35 @@ +// +// Created by dongl on 23-4-20. +// + +#ifndef IM2_HANDLER_H +#define IM2_HANDLER_H + +#include "agreement.h" + +struct userinfo { + bufferevent* bev; + uint64_t ip; +}; + + +class handler { +public: + virtual void run(std::shared_ptr request, std::shared_ptr response) = 0; + +public: + // 用户不在线时应 删除 user fd 映射 + static void add_user(const std::shared_ptr& request); + static void remove_user(const std::shared_ptr& request); + static void remove_user(bufferevent* bev); + static void find_fd(uint64_t account); + static void resp(const std::shared_ptr& request, const std::shared_ptr& response); + static void send(const std::shared_ptr& request, const std::shared_ptr& response); + +protected: + static std::map user_fd; +}; + + + +#endif //IM2_HANDLER_H diff --git a/MS/mmm/management.cpp b/MS/mmm/management.cpp new file mode 100644 index 0000000..a85194b --- /dev/null +++ b/MS/mmm/management.cpp @@ -0,0 +1,48 @@ +// +// Created by dongl on 23-4-21. +// + +#include "management.h" +#include "Response.h" + + + +management::management() { + +} + +management::~management() { + +} + + +void management::send_packet(bufferevent *bev) { + +} + +void management::read_packet(bufferevent *bev) { + // read L 读包长度 + uint8_t packetLen; + bufferevent_read(bev, &packetLen, 1); + // read V 读包头 + char data_h[256] = {0}; + bufferevent_read(bev, data_h, packetLen); + + auto mph = std::make_shared(mp::mph()); + mph->ParseFromString(data_h); + + // read V 读包体 包头内含有包体长度 + char data_b[256] = {0}; + bufferevent_read(bev, data_b, mph->mpb_size()); + + // 请求 + auto request = analysis(mph, data_b, bev)(); + // 响应 + auto response= std::make_shared(agreement_response()); + // 执行逻辑 自定义 + mapping::run(mph->mp_type(), request, response); +} + + + + diff --git a/MS/mmm/management.h b/MS/mmm/management.h new file mode 100644 index 0000000..fff2090 --- /dev/null +++ b/MS/mmm/management.h @@ -0,0 +1,25 @@ +// +// Created by dongl on 23-4-21. +// + +#ifndef IM2_MANAGEMENT_H +#define IM2_MANAGEMENT_H + + +#include "event2/bufferevent.h" +#include "mapping.h" +#include "analysis.h" +#include "Response.h" + + +class management { +public: + management(); + virtual ~management(); +public: + void read_packet(bufferevent* bev); + void send_packet(bufferevent* bev); +}; + + +#endif //IM2_MANAGEMENT_H diff --git a/MS/mmm/mapping.cpp b/MS/mmm/mapping.cpp new file mode 100644 index 0000000..739bd81 --- /dev/null +++ b/MS/mmm/mapping.cpp @@ -0,0 +1,38 @@ +// +// Created by dongl on 23-4-23. +// +#include "mapping.h" +#include "SimpleIni.h" +#include "EnumMapping.h" +#include + +std::map mapping::map; + +mapping::mapping() { + if (map.empty()) { +// CSimpleIniA ini; +// ini.SetUnicode(); +// ini.LoadFile("/home/dongl/code/网络编程/IMS/config/db.ini"); +// auto key_value = ini.GetSection("server-mapping"); + + auto userController = new UserController(); + map.insert( std::pair(mp::MP_REQUEST_LOGIN, userController)); + map.insert( std::pair(mp::MP_REQUEST_REGISTER, userController)); + map.insert( std::pair(mp::MP_REQUEST_LOGOUT, userController)); + } +} + +void mapping::run(const mp::MP_TYPE mpTYpe, std::shared_ptr& request, std::shared_ptr& response) { + mapping(); + printf("%s\n", myenumToString(mpTYpe)); + // 取出需要的执行对象 + auto fun = map.find(mpTYpe)->second; + // 开始执行 请求 + fun->run(request, response); + // 发送 响应 + handler::resp(request, response); +} + + + + diff --git a/MS/mmm/mapping.h b/MS/mmm/mapping.h new file mode 100644 index 0000000..5895c1f --- /dev/null +++ b/MS/mmm/mapping.h @@ -0,0 +1,24 @@ +// +// Created by dongl on 23-4-23. +// + +#ifndef IM2_MAPPING_H1 +#define IM2_MAPPING_H1 + +#include "agreement.h" +#include "controller/works.h" + + +class mapping { +private: +public: + mapping(); +public: + static void run(mp::MP_TYPE mpTYpe, std::shared_ptr& request, std::shared_ptr& response); +private: + static std::map map; +}; + + + +#endif //IM2_MAPPING_H1 diff --git a/MS/pool/mem/mem_pool.cpp b/MS/pool/mem/mem_pool.cpp new file mode 100644 index 0000000..c0ec612 --- /dev/null +++ b/MS/pool/mem/mem_pool.cpp @@ -0,0 +1,5 @@ +// +// Created by dongl on 23-4-18. +// + +#include "mem_pool.h" diff --git a/MS/pool/mem/mem_pool.h b/MS/pool/mem/mem_pool.h new file mode 100644 index 0000000..9b8f55e --- /dev/null +++ b/MS/pool/mem/mem_pool.h @@ -0,0 +1,33 @@ +// +// Created by dongl on 23-4-18. +// + +#ifndef IM2_MEM_POOL_H +#define IM2_MEM_POOL_H + + +#include +#include + +// mem 块 +struct mem_black { + void* black_data; + uint16_t black_id; + uint16_t black_data_size; + +}; + +// mem 桶 +struct mem_barrel { + +}; + +// mem pool mgr +class mem_pool { + +private: + ; +}; + + +#endif //IM2_MEM_POOL_H diff --git a/MS/pool/object/object_pool.cpp b/MS/pool/object/object_pool.cpp new file mode 100644 index 0000000..57c6c8d --- /dev/null +++ b/MS/pool/object/object_pool.cpp @@ -0,0 +1,5 @@ +// +// Created by dongl on 23-4-18. +// + +#include "object_pool.h" diff --git a/MS/pool/object/object_pool.h b/MS/pool/object/object_pool.h new file mode 100644 index 0000000..e0af20d --- /dev/null +++ b/MS/pool/object/object_pool.h @@ -0,0 +1,15 @@ +// +// Created by dongl on 23-4-18. +// + +#ifndef IM2_OBJECT_POOL_H +#define IM2_OBJECT_POOL_H + + +class object_pool { + + +}; + + +#endif //IM2_OBJECT_POOL_H diff --git a/MS/pool/thread/ev_base.h b/MS/pool/thread/ev_base.h new file mode 100644 index 0000000..8d55800 --- /dev/null +++ b/MS/pool/thread/ev_base.h @@ -0,0 +1,29 @@ +// +// Created by dongl on 23-4-14. +// + +#ifndef IM_EV_BASE_H +#define IM_EV_BASE_H + +#include "event2/event.h" +#include "event2/bufferevent.h" + +class ev_base { +public: + explicit ev_base(event_base *base) : base(base) {} + + void operator() (){ + event_base_dispatch(base); + event_base_free(base); + } +private: + event_base* base; + int ev_base_id; +}; + + + + + + +#endif //IM_EV_BASE_H diff --git a/MS/pool/thread/ev_pool.cpp b/MS/pool/thread/ev_pool.cpp new file mode 100644 index 0000000..b9be2fc --- /dev/null +++ b/MS/pool/thread/ev_pool.cpp @@ -0,0 +1,125 @@ +// +// Created by dongl on 23-4-14. +// + +#include "ev_pool.h" + +std::function ev_base(event_base* base) { + return [=](){ + printf("ev_base ptr: %p, pthread: %ld\n",base, pthread_self()); + event_base_loop(base, EVLOOP_NO_EXIT_ON_EMPTY); + }; +} + +ev_pool::ev_pool(int size) : m_pool_max_size(size), m_pool_curr_size(0), m_poll(false) { + +} + +void ev_pool::add_event_base() { + if (m_pool_curr_size >= m_pool_max_size && m_poll) { + perror("add_event_base failed"); + return; + } + event_base* base = event_base_new(); + m_ev_bases.push_back(base); + m_pool.run(ev_base(base)); + m_pool_curr_size += 1; +} + +void ev_pool::add_event_base(const std::function& function) { + m_pool.run(function); +} + +void ev_pool::add_event_bases(int num) { + if (num > m_pool_max_size && m_poll) { + perror("add_event_bases failed"); + fflush(stdout); + return; + } + for (int i = 0; i < num; ++i) { + add_event_base(); + } +} + +bool ev_pool::polling(bool poll) { + m_poll = poll; + return m_poll; +} + +void read(evutil_socket_t, short, void *) { + printf("read\n"); + fflush(stdout); +} + +void ev_pool::add_buffer_event(evutil_socket_t fd, bufferevent_data_cb readcb, bufferevent_data_cb writecb, + bufferevent_event_cb eventcb, short events) { + + event_base* base = dispatching(); + bufferevent* bev = bufferevent_socket_new(base, fd, events); + bufferevent_setcb(bev, readcb, writecb, eventcb, base); + bufferevent_enable(bev, EV_READ | EV_WRITE); + m_bevs.insert(std::pair(base, bev)); + printf("event_base: %p, fd: %d\n", base, fd); +} + +void ev_pool::add_event(evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg) { + + event* ev = event_new(dispatching(), fd, events, callback, callback_arg); + event_add(ev, nullptr); +} + +event_base *ev_pool::dispatching() { + static auto base = m_ev_bases.begin(); + + if (base != m_ev_bases.end()) + base; + else + base = m_ev_bases.begin(); + return *base++; +} + +void ev_pool::ev_loop_exit(event_base* base) { + free(); +} + +void ev_pool::ev_base_exit(event_base* base) { + auto b = std::remove(m_ev_bases.begin(), m_ev_bases.end(), base); + bufferevent_free(m_bevs.find(*b)->second); + event_base_loopexit(base, nullptr); + event_base_free(base); + + m_bevs.erase(m_bevs.find(*b)); + m_ev_bases.erase(b); +} + +void ev_pool::free() { + for (const auto &item: m_bevs) { + bufferevent_free(item.second); + } + for (const auto &item: m_ev_bases) { + event_base_free(item); + } + m_bevs.clear(); + m_ev_bases.clear(); +} + +void ev_pool::run() { + m_pool.wait(); +} + + + + + + + + + + + + + + + + + diff --git a/MS/pool/thread/ev_pool.h b/MS/pool/thread/ev_pool.h new file mode 100644 index 0000000..192e416 --- /dev/null +++ b/MS/pool/thread/ev_pool.h @@ -0,0 +1,38 @@ +// +// Created by dongl on 23-4-14. +// + +#ifndef IM_EV_POOL_H +#define IM_EV_POOL_H + +#include +#include +#include "event2/event.h" +#include "event2/bufferevent.h" + +class ev_pool { +public: + explicit ev_pool(int size = 4); + void add_event_base(); + void add_event_base(const std::function& function); + void add_event_bases(int num); + bool polling(bool poll = false); + void add_buffer_event(evutil_socket_t fd, bufferevent_data_cb readcb, bufferevent_data_cb writecb, + bufferevent_event_cb eventcb, short events); + void add_event(evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg); + event_base* dispatching(); + void ev_loop_exit(event_base* base); + void ev_base_exit(event_base* base); + void run(); + void free(); +private: + tbb::task_group m_pool; + std::vector m_ev_bases; + std::map m_bevs; + int m_pool_max_size; + int m_pool_curr_size; + bool m_poll; +}; + + +#endif //IM_EV_POOL_H diff --git a/MS/tools/hash.cpp b/MS/tools/hash.cpp new file mode 100644 index 0000000..0aeaf18 --- /dev/null +++ b/MS/tools/hash.cpp @@ -0,0 +1,5 @@ +// +// Created by dongl on 23-4-26. +// + +#include "hash.h" diff --git a/MS/tools/hash.h b/MS/tools/hash.h new file mode 100644 index 0000000..254ca86 --- /dev/null +++ b/MS/tools/hash.h @@ -0,0 +1,14 @@ +// +// Created by dongl on 23-4-26. +// + +#ifndef IM2_HASH_H +#define IM2_HASH_H + + +class hash { + +}; + + +#endif //IM2_HASH_H diff --git a/MS/works/CMakeLists.txt b/MS/works/CMakeLists.txt new file mode 100644 index 0000000..1be540a --- /dev/null +++ b/MS/works/CMakeLists.txt @@ -0,0 +1,14 @@ +project(works) + +aux_source_directory(controller DIR_WORKS_CONTROLLER) +aux_source_directory(service DIR_WORKS_SERVICE) +aux_source_directory(db DIR_WORKS_DB) + +include_directories(${CMAKE_SOURCE_DIR}/MS/mmm) +include_directories(${CMAKE_SOURCE_DIR}/MDB/imm_mysqldb) + +add_library(works + ${DIR_WORKS_CONTROLLER} + ${DIR_WORKS_SERVICE} + ${DIR_WORKS_DB} +) \ No newline at end of file diff --git a/MS/works/controller/UserController.cpp b/MS/works/controller/UserController.cpp new file mode 100644 index 0000000..91b0bb9 --- /dev/null +++ b/MS/works/controller/UserController.cpp @@ -0,0 +1,24 @@ +// +// Created by dongl on 23-4-20. +// + +#include "UserController.h" + +void UserController::run(std::shared_ptr agreement_request, std::shared_ptr agreement_response) { + if (agreement_request->m_mph->mp_type() == mp::MP_REQUEST_LOGIN) { + auto sri = service.login(agreement_request->m_body.account(), agreement_request->m_body.password()); + agreement_response->set(mp::MP_RESPONSE_LOGIN, sri, agreement_request->m_bev); + handler::add_user(agreement_request); + + } else if (agreement_request->m_mph->mp_type() == mp::MP_REQUEST_REGISTER) { + auto sri = service.register_(agreement_request->m_body.account(), agreement_request->m_body.password()); + agreement_response->set(mp::MP_RESPONSE_REGISTER, sri, agreement_request->m_bev); + + } else if (agreement_request->m_mph->mp_type() == mp::MP_REQUEST_LOGOUT) { + auto sri = service.logout(agreement_request->m_body.account()); + agreement_response->set(mp::MP_RESPONSE_LOGOUT, sri, agreement_request->m_bev); + handler::remove_user(agreement_request); + } +} + + diff --git a/MS/works/controller/UserController.h b/MS/works/controller/UserController.h new file mode 100644 index 0000000..e3aaef2 --- /dev/null +++ b/MS/works/controller/UserController.h @@ -0,0 +1,18 @@ +// +// Created by dongl on 23-4-25. +// + +#ifndef IM2_USERCONTROLLER_H +#define IM2_USERCONTROLLER_H + +#include "../../mmm/handler.h" +#include "service/UserService.h" + +class UserController : public handler { +public: + void run(std::shared_ptr agreement_request, std::shared_ptr response) override; +private: + UserService service = UserService(); +}; + +#endif //IM2_USERCONTROLLER_H diff --git a/MS/works/controller/works.h b/MS/works/controller/works.h new file mode 100644 index 0000000..17b0a44 --- /dev/null +++ b/MS/works/controller/works.h @@ -0,0 +1,10 @@ +// +// Created by dongl on 23-4-26. +// + +#ifndef IM2_WORKS_H +#define IM2_WORKS_H + +#include "UserController.h" + +#endif //IM2_WORKS_H diff --git a/MS/works/db/UserDB.cpp b/MS/works/db/UserDB.cpp new file mode 100644 index 0000000..7fac284 --- /dev/null +++ b/MS/works/db/UserDB.cpp @@ -0,0 +1,104 @@ +// +// Created by dongl on 23-4-23. +// + +#include "UserDB.h" +#include "template_table/im_user.h" +#include "proto/mp.sri.pb.h" + +UserDB::~UserDB() { + delete sri; +} + + +mp::sri* UserDB::login(uint64_t account, const std::string& password) { + auto query = conn->query("select * from im_user where account=%0:account;"); + query.parse(); + + std::vector v; + query.storein(v, account); + printf("info: %s\n", query.info().c_str()); + + sri = new mp::sri(); + // 无账户 + if (v.empty()) { + printf("无此用户\n"); + sri->set_sri_msg("account null!"); + sri->set_sri_code(mp::MP_LOGIN_ACCOUNT_NOT); + return sri; + } + + // 判断密码 + im_user user = v[0]; + std::string source = std::to_string(account) + password + user.password_salt; + size_t password_hash = std::hash()(source); +// hash_password(&password_hash, source.c_str(), source.size()); + + if (user.password == std::to_string(password_hash)) { + printf("登陆成功\n"); + sri->set_sri_msg("登陆成功!"); + sri->set_sri_code(mp::MP_LOGIN_SUCCESS); + sri->set_sri_token("token"); + sri->set_sri_username(user.username); + } else { + printf("登陆失败\n"); + sri->set_sri_msg("登陆失败!"); + sri->set_sri_code(mp::MP_LOGIN_FAIL); + sri->set_sri_username("null"); + sri->set_sri_token("null"); + } + + return sri; +} + +mp::sri *UserDB::register_(uint64_t account, const std::string &password, const std::string &password_salt, + const std::string& client_info) { + mysqlpp::String info(client_info); + if (!sri) { + sri = new mp::sri(); + } + + // 检验重复账户 + auto query = conn->query("select account from im_user where account=%0:account;"); + query.parse(); + auto is_exist = query.store(account); + printf("error: %s, row: %zu\n", conn->error(), is_exist.num_rows()); + + if (!is_exist.empty()) { + sri->set_sri_msg("帐号已经注册!"); + sri->set_sri_code(mp::MP_REGISTER_EXIST); + sri->set_sri_username("null"); + sri->set_sri_token("null"); + + printf("帐号已经注册!\n"); + return sri; + } + + // 添加账户 + query.insert(im_user(account, "用户"+ std::to_string(account), password, password_salt, info)); + auto ret = query.exec(); + if (ret) { + sri->set_sri_msg("注册成功!"); + sri->set_sri_code(mp::MP_REGISTER_SUCCESS); + sri->set_sri_username("null"); + sri->set_sri_token("null"); + printf("注册成功!\n"); + } else { + sri->set_sri_msg("注册失败!"); +// sri->set_sri_code(mp::MP_REGISTER_EXIST); + sri->set_sri_username("null"); + sri->set_sri_token("null"); + printf("注册失败!\n"); + } + + return sri; +} + +mp::sri *UserDB::logout(uint64_t account) { + return nullptr; +} + + + + + diff --git a/MS/works/db/UserDB.h b/MS/works/db/UserDB.h new file mode 100644 index 0000000..878b78e --- /dev/null +++ b/MS/works/db/UserDB.h @@ -0,0 +1,26 @@ +// +// Created by dongl on 23-4-23. +// + +#ifndef IM2_USERDB_H +#define IM2_USERDB_H + +#include "linkDB.h" +#include "Sri.h" + +class UserDB { +public: + virtual ~UserDB(); + +public: + virtual mp::sri* login(uint64_t account, const std::string& password); + virtual mp::sri* register_(uint64_t account, const std::string& password, + const std::string& password_salt, const std::string& client_info); + virtual mp::sri* logout(uint64_t account); +private: + mysqlpp::Connection* conn = DB::link(); + mp::sri* sri{}; +}; + + +#endif //IM2_USERDB_H diff --git a/MS/works/db/linkDB.cpp b/MS/works/db/linkDB.cpp new file mode 100644 index 0000000..72aa039 --- /dev/null +++ b/MS/works/db/linkDB.cpp @@ -0,0 +1,20 @@ +// +// Created by dongl on 23-4-25. +// +#include "linkDB.h" + +DB::DB() {} +DB::~DB() { + delete pool; +} + +ConnectionPool* DB::pool = nullptr; + +mysqlpp::Connection* DB::link() { + if (pool == nullptr) { + pool = new ConnectionPool("124.221.152.192", "ims", "IMS", "WimTFC8N58kznx2k"); + } + + return pool->safe_grab(); +} + diff --git a/MS/works/db/linkDB.h b/MS/works/db/linkDB.h new file mode 100644 index 0000000..cb12b16 --- /dev/null +++ b/MS/works/db/linkDB.h @@ -0,0 +1,22 @@ +// +// Created by dongl on 23-4-23. +// + +#ifndef IM2_LINKDB_H +#define IM2_LINKDB_H + +#include "ConnectionPool.h" + +class DB { +public: + static mysqlpp::Connection* link(); +private: + DB(); + + virtual ~DB(); +private: + static ConnectionPool* pool; +}; + + +#endif //IM2_LINKDB_H diff --git a/MS/works/service/UserService.cpp b/MS/works/service/UserService.cpp new file mode 100644 index 0000000..53a16f5 --- /dev/null +++ b/MS/works/service/UserService.cpp @@ -0,0 +1,31 @@ +// +// Created by dongl on 23-4-23. +// + +#include "UserService.h" +#include + +mp::sri* UserService::login(uint64_t account, const std::string& password) { + return userDb.login(account, password); +} + +mp::sri* UserService::register_(uint64_t account, const std::string &password) { + // 生成salt + std::string password_salt; + for (int i = 0; i < std::experimental::randint(5, 8); ++i) { + password_salt.push_back((char )std::experimental::randint(33, 126)); + } + + // 加密密码 生成hash + std::string source = std::to_string(account) + password + password_salt; + size_t password_hash = std::hash()(source); +// hash_password(&password_hash, source.c_str(), source.size()); + + printf("password_hash: %zu, password_salt: %s\n", password_hash, password_salt.c_str()); + + return userDb.register_(account, std::to_string(password_hash), password_salt, " "); +} + +mp::sri* UserService::logout(uint64_t account) { + return nullptr; +} diff --git a/MS/works/service/UserService.h b/MS/works/service/UserService.h new file mode 100644 index 0000000..fa11e11 --- /dev/null +++ b/MS/works/service/UserService.h @@ -0,0 +1,19 @@ +// +// Created by dongl on 23-4-23. +// + +#ifndef IM2_USERSERVICE_H +#define IM2_USERSERVICE_H +#include "db/UserDB.h" + +class UserService { + +public: + virtual mp::sri* login(uint64_t account, const std::string& password); + virtual mp::sri* register_(uint64_t account, const std::string& password); + virtual mp::sri* logout(uint64_t account); +private: + UserDB userDb = UserDB(); +}; + +#endif //IM2_USERSERVICE_H diff --git a/include/ini/ConvertUTF.c b/include/ini/ConvertUTF.c new file mode 100644 index 0000000..9b3deeb --- /dev/null +++ b/include/ini/ConvertUTF.c @@ -0,0 +1,539 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "ConvertUTF.h" +#ifdef CVTUTF_DEBUG +#include +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); +} +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ diff --git a/include/ini/ConvertUTF.h b/include/ini/ConvertUTF.h new file mode 100644 index 0000000..14d7b70 --- /dev/null +++ b/include/ini/ConvertUTF.h @@ -0,0 +1,149 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: , , + or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned int UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/ini/SimpleIni.h b/include/ini/SimpleIni.h new file mode 100644 index 0000000..39fcd73 --- /dev/null +++ b/include/ini/SimpleIni.h @@ -0,0 +1,3625 @@ +/** @mainpage + + +
Library SimpleIni +
File SimpleIni.h +
Author Brodie Thiesfield +
Source https://github.com/brofield/simpleini +
Version 4.19 +
+ + Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation. + + @section intro INTRODUCTION + + This component allows an INI-style configuration file to be used on both + Windows and Linux/Unix. It is fast, simple and source code using this + component will compile unchanged on either OS. + + + @section features FEATURES + + - MIT Licence allows free use in all software (including GPL and commercial) + - multi-platform (Windows CE/9x/NT..10/etc, Linux, MacOSX, Unix) + - loading and saving of INI-style configuration files + - configuration files can have any newline format on all platforms + - liberal acceptance of file format + - key/values with no section + - removal of whitespace around sections, keys and values + - support for multi-line values (values with embedded newline characters) + - optional support for multiple keys with the same name + - optional case-insensitive sections and keys (for ASCII characters only) + - saves files with sections and keys in the same order as they were loaded + - preserves comments on the file, section and keys where possible. + - supports both char or wchar_t programming interfaces + - supports both MBCS (system locale) and UTF-8 file encodings + - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file + - support for non-ASCII characters in section, keys, values and comments + - support for non-standard character types or file encodings + via user-written converter classes + - support for adding/modifying values programmatically + - compiles cleanly in the following compilers: + - Windows/VC6 (warning level 3) + - Windows/VC.NET 2003 (warning level 4) + - Windows/VC 2005 (warning level 4) + - Windows/VC 2019 (warning level 4) + - Linux/gcc (-Wall) + + + @section usage USAGE SUMMARY + + -# Decide if you will be using utf8 or MBCS files, and working with the + data in utf8, wchar_t or ICU chars. + -# If you will only be using straight utf8 files and access the data via the + char interface, then you do not need any conversion library and could define + SI_NO_CONVERSION. Note that no conversion also means no validation of the data. + If no converter is specified then the default converter is SI_CONVERT_GENERIC + on Mac/Linux and SI_CONVERT_WIN32 on Windows. If you need widechar support on + Mac/Linux then use either SI_CONVERT_GENERIC or SI_CONVERT_ICU. These are also + supported on all platforms. + -# Define the appropriate symbol for the converter you wish to use and + DB the SimpleIni.h header file. + -# Declare an instance of the appropriate class. Note that the following + definitions are just shortcuts for commonly used types. Other types + (PRUnichar, unsigned short, unsigned char) are also possible. + +
Interface Case-sensitive Load UTF-8 Load MBCS Typedef +
SI_NO_CONVERSION +
char No Yes No CSimpleIniA +
char Yes Yes No CSimpleIniCaseA +
SI_CONVERT_GENERIC +
char No Yes Yes #1 CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_WIN32 +
char No No #2 Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_ICU +
char No Yes Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
UChar No Yes Yes CSimpleIniW +
UChar Yes Yes Yes CSimpleIniCaseW +
+ #1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.
+ #2 Only affects Windows. On Windows this uses MBCS functions and + so may fold case incorrectly leading to uncertain results. + -# Call LoadData() or LoadFile() to load and parse the INI configuration file + -# Access and modify the data of the file using the following functions + +
GetAllSections Return all section names +
GetAllKeys Return all key names within a section +
GetAllValues Return all values within a section & key +
GetSection Return all key names and values in a section +
GetSectionSize Return the number of keys in a section +
GetValue Return a value for a section & key +
SetValue Add or update a value for a section & key +
Delete Remove a section, or a key from a section +
SectionExists Does a section exist? +
KeyExists Does a key exist? +
+ -# Call Save() or SaveFile() to save the INI configuration data + + @section iostreams IO STREAMS + + SimpleIni supports reading from and writing to STL IO streams. Enable this + by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header + file. Ensure that if the streams are backed by a file (e.g. ifstream or + ofstream) then the flag ios_base::binary has been used when the file was + opened. + + @section multiline MULTI-LINE VALUES + + Values that span multiple lines are created using the following format. + +
+        key = <<
+
+    Note the following:
+    - The text used for ENDTAG can be anything and is used to find
+      where the multi-line text ends.
+    - The newline after ENDTAG in the start tag, and the newline
+      before ENDTAG in the end tag is not included in the data value.
+    - The ending tag must be on it's own line with no whitespace before
+      or after it.
+    - The multi-line value is modified at load so that each line in the value
+      is delimited by a single '\\n' character on all platforms. At save time
+      it will be converted into the newline format used by the current
+      platform.
+
+    @section comments COMMENTS
+
+    Comments are preserved in the file within the following restrictions:
+    - Every file may have a single "file comment". It must start with the
+      first character in the file, and will end with the first non-comment
+      line in the file.
+    - Every section may have a single "section comment". It will start
+      with the first comment line following the file comment, or the last
+      data entry. It ends at the beginning of the section.
+    - Every key may have a single "key comment". This comment will start
+      with the first comment line following the section start, or the file
+      comment if there is no section name.
+    - Comments are set at the time that the file, section or key is first
+      created. The only way to modify a comment on a section or a key is to
+      delete that entry and recreate it with the new comment. There is no
+      way to change the file comment.
+
+    @section save SAVE ORDER
+
+    The sections and keys are written out in the same order as they were
+    read in from the file. Sections and keys added to the data after the
+    file has been loaded will be added to the end of the file when it is
+    written. There is no way to specify the location of a section or key
+    other than in first-created, first-saved order.
+
+    @section notes NOTES
+
+    - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
+      Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
+    - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
+    - When using SI_CONVERT_ICU, ICU header files must be on the DB
+      path and icuuc.lib must be linked in.
+    - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
+      you should use SI_CONVERT_GENERIC.
+    - The collation (sorting) order used for sections and keys returned from
+      iterators is NOT DEFINED. If collation order of the text is important
+      then it should be done yourself by either supplying a replacement
+      SI_STRLESS class, or by sorting the strings external to this library.
+    - Usage of the  header on Windows can be disabled by defining
+      SI_NO_MBCS. This is defined automatically on Windows CE platforms.
+    - Not thread-safe so manage your own locking
+
+    @section contrib CONTRIBUTIONS
+    
+    - 2010/05/03: Tobias Gehrig: added GetDoubleValue()
+
+    @section licence MIT LICENCE
+
+    The licence text below is the boilerplate "MIT Licence" used from:
+    http://www.opensource.org/licenses/mit-license.php
+
+    Copyright (c) 2006-2012, Brodie Thiesfield
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is furnished
+    to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+    FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+    COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef INCLUDED_SimpleIni_h
+#define INCLUDED_SimpleIni_h
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+// Disable these warnings in MSVC:
+//  4127 "conditional expression is constant" as the conversion classes trigger
+//  it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
+//  be optimized away in a release build.
+//  4503 'insert' : decorated name length exceeded, name was truncated
+//  4702 "unreachable code" as the MS STL header causes it in release mode.
+//  Again, the code causing the warning will be cleaned up by the compiler.
+//  4786 "identifier truncated to 256 characters" as this is thrown hundreds
+//  of times VC6 as soon as STL is used.
+#ifdef _MSC_VER
+# pragma warning (push)
+# pragma warning (disable: 4127 4503 4702 4786)
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef SI_SUPPORT_IOSTREAMS
+# DB 
+#endif // SI_SUPPORT_IOSTREAMS
+
+#ifdef _DEBUG
+# ifndef assert
+#  DB 
+# endif
+# define SI_ASSERT(x)   assert(x)
+#else
+# define SI_ASSERT(x)
+#endif
+
+using SI_Error = int;
+
+constexpr int SI_OK = 0;        //!< No error
+constexpr int SI_UPDATED = 1;   //!< An existing value was updated
+constexpr int SI_INSERTED = 2;  //!< A new value was inserted
+
+// note: test for any error with (retval < 0)
+constexpr int SI_FAIL = -1;     //!< Generic failure
+constexpr int SI_NOMEM = -2;    //!< Out of memory error
+constexpr int SI_FILE = -3;     //!< File error (see errno for detail error)
+
+#define SI_UTF8_SIGNATURE     "\xEF\xBB\xBF"
+
+#ifdef _WIN32
+# define SI_NEWLINE_A   "\r\n"
+# define SI_NEWLINE_W   L"\r\n"
+#else // !_WIN32
+# define SI_NEWLINE_A   "\n"
+# define SI_NEWLINE_W   L"\n"
+#endif // _WIN32
+
+#if defined(SI_CONVERT_ICU)
+# DB 
+#endif
+
+#if defined(_WIN32)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     wchar_t
+#elif defined(SI_CONVERT_ICU)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     UChar
+#endif
+
+
+// ---------------------------------------------------------------------------
+//                              MAIN TEMPLATE CLASS
+// ---------------------------------------------------------------------------
+
+/** Simple INI file reader.
+
+    This can be instantiated with the choice of unicode or native characterset,
+    and case sensitive or insensitive comparisons of section and key names.
+    The supported combinations are pre-defined with the following typedefs:
+
+    
+        
Interface Case-sensitive Typedef +
char No CSimpleIniA +
char Yes CSimpleIniCaseA +
wchar_t No CSimpleIniW +
wchar_t Yes CSimpleIniCaseW +
+ + Note that using other types for the SI_CHAR is supported. For instance, + unsigned char, unsigned short, etc. Note that where the alternative type + is a different size to char/wchar_t you may need to supply new helper + classes for SI_STRLESS and SI_CONVERTER. + */ +template +class CSimpleIniTempl +{ +public: + typedef SI_CHAR SI_CHAR_T; + + /** key entry */ + struct Entry { + const SI_CHAR * pItem; + const SI_CHAR * pComment; + int nOrder; + + Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0) + : pItem(a_pszItem) + , pComment(NULL) + , nOrder(a_nOrder) + { } + Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder) + : pItem(a_pszItem) + , pComment(a_pszComment) + , nOrder(a_nOrder) + { } + Entry(const Entry & rhs) { operator=(rhs); } + Entry & operator=(const Entry & rhs) { + pItem = rhs.pItem; + pComment = rhs.pComment; + nOrder = rhs.nOrder; + return *this; + } + +#if defined(_MSC_VER) && _MSC_VER <= 1200 + /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ + bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); } + bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); } +#endif + + /** Strict less ordering by name of key only */ + struct KeyOrder { + bool operator()(const Entry & lhs, const Entry & rhs) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(lhs.pItem, rhs.pItem); + } + }; + + /** Strict less ordering by order, and then name of key */ + struct LoadOrder { + bool operator()(const Entry & lhs, const Entry & rhs) const { + if (lhs.nOrder != rhs.nOrder) { + return lhs.nOrder < rhs.nOrder; + } + return KeyOrder()(lhs.pItem, rhs.pItem); + } + }; + }; + + /** map keys to values */ + typedef std::multimap TKeyVal; + + /** map sections to key/value map */ + typedef std::map TSection; + + /** set of dependent string pointers. Note that these pointers are + dependent on memory owned by CSimpleIni. + */ + typedef std::list TNamesDepend; + + /** interface definition for the OutputWriter object to pass to Save() + in order to output the INI file data. + */ + class OutputWriter { + public: + OutputWriter() { } + virtual ~OutputWriter() { } + virtual void Write(const char * a_pBuf) = 0; + private: + OutputWriter(const OutputWriter &); // disable + OutputWriter & operator=(const OutputWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a file */ + class FileWriter : public OutputWriter { + FILE * m_file; + public: + FileWriter(FILE * a_file) : m_file(a_file) { } + void Write(const char * a_pBuf) { + fputs(a_pBuf, m_file); + } + private: + FileWriter(const FileWriter &); // disable + FileWriter & operator=(const FileWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a string */ + class StringWriter : public OutputWriter { + std::string & m_string; + public: + StringWriter(std::string & a_string) : m_string(a_string) { } + void Write(const char * a_pBuf) { + m_string.append(a_pBuf); + } + private: + StringWriter(const StringWriter &); // disable + StringWriter & operator=(const StringWriter &); // disable + }; + +#ifdef SI_SUPPORT_IOSTREAMS + /** OutputWriter class to write the INI data to an ostream */ + class StreamWriter : public OutputWriter { + std::ostream & m_ostream; + public: + StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { } + void Write(const char * a_pBuf) { + m_ostream << a_pBuf; + } + private: + StreamWriter(const StreamWriter &); // disable + StreamWriter & operator=(const StreamWriter &); // disable + }; +#endif // SI_SUPPORT_IOSTREAMS + + /** Characterset conversion utility class to convert strings to the + same format as is used for the storage. + */ + class Converter : private SI_CONVERTER { + public: + Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) { + m_scratch.resize(1024); + } + Converter(const Converter & rhs) { operator=(rhs); } + Converter & operator=(const Converter & rhs) { + m_scratch = rhs.m_scratch; + return *this; + } + bool ConvertToStore(const SI_CHAR * a_pszString) { + size_t uLen = SI_CONVERTER::SizeToStore(a_pszString); + if (uLen == (size_t)(-1)) { + return false; + } + while (uLen > m_scratch.size()) { + m_scratch.resize(m_scratch.size() * 2); + } + return SI_CONVERTER::ConvertToStore( + a_pszString, + const_cast(m_scratch.data()), + m_scratch.size()); + } + const char * Data() { return m_scratch.data(); } + private: + std::string m_scratch; + }; + +public: + /*-----------------------------------------------------------------------*/ + + /** Default constructor. + + @param a_bIsUtf8 See the method SetUnicode() for details. + @param a_bMultiKey See the method SetMultiKey() for details. + @param a_bMultiLine See the method SetMultiLine() for details. + */ + CSimpleIniTempl( + bool a_bIsUtf8 = false, + bool a_bMultiKey = false, + bool a_bMultiLine = false + ); + + /** Destructor */ + ~CSimpleIniTempl(); + + /** Deallocate all memory stored by this object */ + void Reset(); + + /** Has any data been loaded */ + bool IsEmpty() const { return m_data.empty(); } + + /*-----------------------------------------------------------------------*/ + /** @{ @name Settings */ + + /** Set the storage format of the INI data. This affects both the loading + and saving of the INI data using all of the Load/Save API functions. + This value cannot be changed after any INI data has been loaded. + + If the file is not set to Unicode (UTF-8), then the data encoding is + assumed to be the OS native encoding. This encoding is the system + locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP. + If the storage format is set to Unicode then the file will be loaded + as UTF-8 encoded data regardless of the native file encoding. If + SI_CHAR == char then all of the char* parameters take and return UTF-8 + encoded data regardless of the system locale. + + \param a_bIsUtf8 Assume UTF-8 encoding for the source? + */ + void SetUnicode(bool a_bIsUtf8 = true) { + if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8; + } + + /** Get the storage format of the INI data. */ + bool IsUnicode() const { return m_bStoreIsUtf8; } + + /** Should multiple identical keys be permitted in the file. If set to false + then the last value encountered will be used as the value of the key. + If set to true, then all values will be available to be queried. For + example, with the following input: + +
+        [section]
+        test=value1
+        test=value2
+        
+ + Then with SetMultiKey(true), both of the values "value1" and "value2" + will be returned for the key test. If SetMultiKey(false) is used, then + the value for "test" will only be "value2". This value may be changed + at any time. + + \param a_bAllowMultiKey Allow multi-keys in the source? + */ + void SetMultiKey(bool a_bAllowMultiKey = true) { + m_bAllowMultiKey = a_bAllowMultiKey; + } + + /** Get the storage format of the INI data. */ + bool IsMultiKey() const { return m_bAllowMultiKey; } + + /** Should data values be permitted to span multiple lines in the file. If + set to false then the multi-line construct << + SI_CHAR FORMAT + char same format as when loaded (MBCS or UTF-8) + wchar_t UTF-8 + other UTF-8 + + + Note that comments from the original data is preserved as per the + documentation on comments. The order of the sections and values + from the original file will be preserved. + + Any data prepended or appended to the output device must use the the + same format (MBCS or UTF-8). You may use the GetConverter() method to + convert text to the correct format regardless of the output format + being used by SimpleIni. + + To add a BOM to UTF-8 data, write it out manually at the very beginning + like is done in SaveFile when a_bUseBOM is true. + + @param a_oOutput Output writer to write the data to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the OutputWriter. + + @return SI_Error See error definitions + */ + SI_Error Save( + OutputWriter & a_oOutput, + bool a_bAddSignature = false + ) const; + +#ifdef SI_SUPPORT_IOSTREAMS + /** Save the INI data to an ostream. See Save() for details. + + @param a_ostream String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the stream. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::ostream & a_ostream, + bool a_bAddSignature = false + ) const + { + StreamWriter writer(a_ostream); + return Save(writer, a_bAddSignature); + } +#endif // SI_SUPPORT_IOSTREAMS + + /** Append the INI data to a string. See Save() for details. + + @param a_sBuffer String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the string. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::string & a_sBuffer, + bool a_bAddSignature = false + ) const + { + StringWriter writer(a_sBuffer); + return Save(writer, a_bAddSignature); + } + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Accessing INI Data */ + + /** Retrieve all section names. The list is returned as an STL vector of + names and can be iterated or searched as necessary. Note that the + sort order of the returned strings is NOT DEFINED. You can sort + the names into the load order if desired. Search this file for ".sort" + for an example. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these pointers + are in use! + + @param a_names Vector that will receive all of the section + names. See note above! + */ + void GetAllSections( + TNamesDepend & a_names + ) const; + + /** Retrieve all unique key names in a section. The sort order of the + returned strings is NOT DEFINED. You can sort the names into the load + order if desired. Search this file for ".sort" for an example. Only + unique key names are returned. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Section to request data for + @param a_names List that will receive all of the key + names. See note above! + + @return true Section was found. + @return false Matching section was not found. + */ + bool GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const; + + /** Retrieve all values for a specific key. This method can be used when + multiple keys are both enabled and disabled. Note that the sort order + of the returned strings is NOT DEFINED. You can sort the names into + the load order if desired. Search this file for ".sort" for an example. + + NOTE! The returned values are pointers to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_values List to return if the key is not found + + @return true Key was found. + @return false Matching section/key was not found. + */ + bool GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const; + + /** Query the number of keys in a specific section. Note that if multiple + keys are enabled, then this value may be different to the number of + keys returned by GetAllKeys. + + @param a_pSection Section to request data for + + @return -1 Section does not exist in the file + @return >=0 Number of keys in the section + */ + int GetSectionSize( + const SI_CHAR * a_pSection + ) const; + + /** Retrieve all key and value pairs for a section. The data is returned + as a pointer to an STL map and can be iterated or searched as + desired. Note that multiple entries for the same key may exist when + multiple keys have been enabled. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Name of the section to return + @return Section data + */ + const TKeyVal * GetSection( + const SI_CHAR * a_pSection + ) const; + + /** Test if a section exists. Convenience function */ + inline bool SectionExists( + const SI_CHAR * a_pSection + ) const { + return GetSection(a_pSection) != NULL; + } + + /** Test if the key exists in a section. Convenience function. */ + inline bool KeyExists( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey + ) const { + return GetValue(a_pSection, a_pKey) != NULL; + } + + /** Retrieve the value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + NOTE! The returned value is a pointer to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_pDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_pDefault Key was not found in the section + @return other Value of the key + */ + const SI_CHAR * GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault = NULL, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + long GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + double GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a boolean value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + Strings starting with "t", "y", "on" or "1" are returned as logically true. + Strings starting with "f", "n", "of" or "0" are returned as logically false. + For all other values the default is returned. Character comparisons are + case-insensitive. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_bDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + bool GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault = false, + bool * a_pHasMultiple = NULL + ) const; + + /** Add or update a section or value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. Set to NULL to + create an empty section. + @param a_pValue Value to set. Set to NULL to create an + empty section. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. Note that a + comment may be set ONLY when the section or key is + first created (i.e. when this function returns the + value SI_INSERTED). If you wish to create a section + with a comment then you need to create the section + separately to the key. The comment string must be + in full comment form already (have a comment + character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetValue and SetValue + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ) + { + return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true); + } + + /** Add or update a numeric value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bUseHex By default the value will be written to the file + in decimal format. Set this to true to write it + as hexadecimal. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetLongValue and + SetLongValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bUseHex = false, + bool a_bForceReplace = false + ); + + /** Add or update a double value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetDoubleValue and + SetDoubleValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Add or update a boolean value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_bValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetBoolValue and + SetBoolValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Delete an entire section, or a key from a section. Note that the + data returned by GetSection is invalid and must not be used after + anything has been deleted from that section using this method. + Note when multiple keys is enabled, this will delete all keys with + that name; to selectively delete individual key/values, use + DeleteValue. + + @param a_pSection Section to delete key from, or if + a_pKey is NULL, the section to remove. + @param a_pKey Key to remove from the section. Set to + NULL to remove the entire section. + @param a_bRemoveEmpty If the section is empty after this key has + been deleted, should the empty section be + removed? + + @return true Key or section was deleted. + @return false Key or section was not found. + */ + bool Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty = false + ); + + /** Delete an entire section, or a key from a section. If value is + provided, only remove keys with the value. Note that the data + returned by GetSection is invalid and must not be used after + anything has been deleted from that section using this method. + Note when multiple keys is enabled, all keys with the value will + be deleted. + + @param a_pSection Section to delete key from, or if + a_pKey is NULL, the section to remove. + @param a_pKey Key to remove from the section. Set to + NULL to remove the entire section. + @param a_pValue Value of key to remove from the section. + Set to NULL to remove all keys. + @param a_bRemoveEmpty If the section is empty after this key has + been deleted, should the empty section be + removed? + + @return true Key/value or section was deleted. + @return false Key/value or section was not found. + */ + bool DeleteValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + bool a_bRemoveEmpty = false + ); + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Converter */ + + /** Return a conversion object to convert text to the same encoding + as is used by the Save(), SaveFile() and SaveString() functions. + Use this to prepare the strings that you wish to append or prepend + to the output INI data. + */ + Converter GetConverter() const { + return Converter(m_bStoreIsUtf8); + } + + /*-----------------------------------------------------------------------*/ + /** @} */ + +private: + // copying is not permitted + CSimpleIniTempl(const CSimpleIniTempl &); // disabled + CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled + + /** Parse the data looking for a file comment and store it if found. + */ + SI_Error FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ); + + /** Parse the data looking for the next valid entry. The memory pointed to + by a_pData is modified by inserting NULL characters. The pointer is + updated to the current location in the block of text. + */ + bool FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const; + + /** Add the section/key/value to our data. + + @param a_pSection Section name. Sections will be created if they + don't already exist. + @param a_pKey Key name. May be NULL to create an empty section. + Existing entries will be updated. New entries will + be created. + @param a_pValue Value for the key. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. This must be + a string in full comment form already (have a + comment character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/AddEntry and AddEntry + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + @param a_bCopyStrings Should copies of the strings be made or not. + If false then the pointers will be used as is. + */ + SI_Error AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ); + + /** Is the supplied character a whitespace character? */ + inline bool IsSpace(SI_CHAR ch) const { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); + } + + /** Does the supplied character start a comment line? */ + inline bool IsComment(SI_CHAR ch) const { + return (ch == ';' || ch == '#'); + } + + + /** Skip over a newline character (or characters) for either DOS or UNIX */ + inline void SkipNewLine(SI_CHAR *& a_pData) const { + a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1; + } + + /** Make a copy of the supplied string, replacing the original pointer */ + SI_Error CopyString(const SI_CHAR *& a_pString); + + /** Delete a string from the copied strings buffer if necessary */ + void DeleteString(const SI_CHAR * a_pString); + + /** Internal use of our string comparison function */ + bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(a_pLeft, a_pRight); + } + + bool IsMultiLineTag(const SI_CHAR * a_pData) const; + bool IsMultiLineData(const SI_CHAR * a_pData) const; + bool IsSingleLineQuotedValue(const SI_CHAR* a_pData) const; + bool LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment = false + ) const; + bool IsNewLineChar(SI_CHAR a_c) const; + + bool OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const; + +private: + /** Copy of the INI file data in our character format. This will be + modified when parsed to have NULL characters added after all + interesting string entries. All of the string pointers to sections, + keys and values point into this block of memory. + */ + SI_CHAR * m_pData; + + /** Length of the data that we have stored. Used when deleting strings + to determine if the string is stored here or in the allocated string + buffer. + */ + size_t m_uDataLen; + + /** File comment for this data, if one exists. */ + const SI_CHAR * m_pFileComment; + + /** constant empty string */ + const SI_CHAR m_cEmptyString; + + /** Parsed INI data. Section -> (Key -> Value). */ + TSection m_data; + + /** This vector stores allocated memory for copies of strings that have + been supplied after the file load. It will be empty unless SetValue() + has been called. + */ + TNamesDepend m_strings; + + /** Is the format of our datafile UTF-8 or MBCS? */ + bool m_bStoreIsUtf8; + + /** Are multiple values permitted for the same key? */ + bool m_bAllowMultiKey; + + /** Are data values permitted to span multiple lines? */ + bool m_bAllowMultiLine; + + /** Should spaces be written out surrounding the equals sign? */ + bool m_bSpaces; + + /** Should quoted data in values be recognized and parsed? */ + bool m_bParseQuotes; + + /** Do keys always need to have an equals sign when reading/writing? */ + bool m_bAllowKeyOnly; + + /** Next order value, used to ensure sections and keys are output in the + same order that they are loaded/added. + */ + int m_nOrder; +}; + +// --------------------------------------------------------------------------- +// IMPLEMENTATION +// --------------------------------------------------------------------------- + +template +CSimpleIniTempl::CSimpleIniTempl( + bool a_bIsUtf8, + bool a_bAllowMultiKey, + bool a_bAllowMultiLine + ) + : m_pData(0) + , m_uDataLen(0) + , m_pFileComment(NULL) + , m_cEmptyString(0) + , m_bStoreIsUtf8(a_bIsUtf8) + , m_bAllowMultiKey(a_bAllowMultiKey) + , m_bAllowMultiLine(a_bAllowMultiLine) + , m_bSpaces(true) + , m_bParseQuotes(false) + , m_bAllowKeyOnly(false) + , m_nOrder(0) +{ } + +template +CSimpleIniTempl::~CSimpleIniTempl() +{ + Reset(); +} + +template +void +CSimpleIniTempl::Reset() +{ + // remove all data + delete[] m_pData; + m_pData = NULL; + m_uDataLen = 0; + m_pFileComment = NULL; + if (!m_data.empty()) { + m_data.erase(m_data.begin(), m_data.end()); + } + + // remove all strings + if (!m_strings.empty()) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (; i != m_strings.end(); ++i) { + delete[] const_cast(i->pItem); + } + m_strings.erase(m_strings.begin(), m_strings.end()); + } +} + +template +SI_Error +CSimpleIniTempl::LoadFile( + const char * a_pszFile + ) +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) { + return SI_FILE; + } + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::LoadFile( + const SI_WCHAR_T * a_pwszFile + ) +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return LoadFile(szFile); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::LoadFile( + FILE * a_fpFile + ) +{ + // load the raw file data + int retval = fseek(a_fpFile, 0, SEEK_END); + if (retval != 0) { + return SI_FILE; + } + long lSize = ftell(a_fpFile); + if (lSize < 0) { + return SI_FILE; + } + if (lSize == 0) { + return SI_OK; + } + + // allocate and ensure NULL terminated + char * pData = new(std::nothrow) char[lSize+static_cast(1)]; + if (!pData) { + return SI_NOMEM; + } + pData[lSize] = 0; + + // load data into buffer + fseek(a_fpFile, 0, SEEK_SET); + size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); + if (uRead != (size_t) lSize) { + delete[] pData; + return SI_FILE; + } + + // convert the raw data to unicode + SI_Error rc = LoadData(pData, uRead); + delete[] pData; + return rc; +} + +template +SI_Error +CSimpleIniTempl::LoadData( + const char * a_pData, + size_t a_uDataLen + ) +{ + if (!a_pData) { + return SI_OK; + } + + // if the UTF-8 BOM exists, consume it and set mode to unicode, if we have + // already loaded data and try to change mode half-way through then this will + // be ignored and we will assert in debug versions + if (a_uDataLen >= 3 && memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) { + a_pData += 3; + a_uDataLen -= 3; + SI_ASSERT(m_bStoreIsUtf8 || !m_pData); // we don't expect mixed mode data + SetUnicode(); + } + + if (a_uDataLen == 0) { + return SI_OK; + } + + // determine the length of the converted data + SI_CONVERTER converter(m_bStoreIsUtf8); + size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen); + if (uLen == (size_t)(-1)) { + return SI_FAIL; + } + + // allocate memory for the data, ensure that there is a NULL + // terminator wherever the converted data ends + SI_CHAR * pData = new(std::nothrow) SI_CHAR[uLen+1]; + if (!pData) { + return SI_NOMEM; + } + memset(pData, 0, sizeof(SI_CHAR)*(uLen+1)); + + // convert the data + if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) { + delete[] pData; + return SI_FAIL; + } + + // parse it + const static SI_CHAR empty = 0; + SI_CHAR * pWork = pData; + const SI_CHAR * pSection = ∅ + const SI_CHAR * pItem = NULL; + const SI_CHAR * pVal = NULL; + const SI_CHAR * pComment = NULL; + + // We copy the strings if we are loading data into this class when we + // already have stored some. + bool bCopyStrings = (m_pData != NULL); + + // find a file comment if it exists, this is a comment that starts at the + // beginning of the file and continues until the first blank line. + SI_Error rc = FindFileComment(pWork, bCopyStrings); + if (rc < 0) return rc; + + // add every entry in the file to the data table + while (FindEntry(pWork, pSection, pItem, pVal, pComment)) { + rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings); + if (rc < 0) return rc; + } + + // store these strings if we didn't copy them + if (bCopyStrings) { + delete[] pData; + } + else { + m_pData = pData; + m_uDataLen = uLen+1; + } + + return SI_OK; +} + +#ifdef SI_SUPPORT_IOSTREAMS +template +SI_Error +CSimpleIniTempl::LoadData( + std::istream & a_istream + ) +{ + std::string strData; + char szBuf[512]; + do { + a_istream.get(szBuf, sizeof(szBuf), '\0'); + strData.append(szBuf); + } + while (a_istream.good()); + return LoadData(strData); +} +#endif // SI_SUPPORT_IOSTREAMS + +template +SI_Error +CSimpleIniTempl::FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ) +{ + // there can only be a single file comment + if (m_pFileComment) { + return SI_OK; + } + + // Load the file comment as multi-line text, this will modify all of + // the newline characters to be single \n chars + if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) { + return SI_OK; + } + + // copy the string if necessary + if (a_bCopyStrings) { + SI_Error rc = CopyString(m_pFileComment); + if (rc < 0) return rc; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const +{ + a_pComment = NULL; + + bool bHaveValue = false; + SI_CHAR * pTrail = NULL; + while (*a_pData) { + // skip spaces and empty lines + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + if (!*a_pData) { + break; + } + + // skip processing of comment lines but keep a pointer to + // the start of the comment. + if (IsComment(*a_pData)) { + LoadMultiLineText(a_pData, a_pComment, NULL, true); + continue; + } + + // process section names + if (*a_pData == '[') { + // skip leading spaces + ++a_pData; + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the section name (it may contain spaces) + // and convert it to lowercase as necessary + a_pSection = a_pData; + while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // if it's an invalid line, just skip it + if (*a_pData != ']') { + continue; + } + + // remove trailing spaces from the section + pTrail = a_pData - 1; + while (pTrail >= a_pSection && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // skip to the end of the line + ++a_pData; // safe as checked that it == ']' above + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + a_pKey = NULL; + a_pVal = NULL; + return true; + } + + // find the end of the key name (it may contain spaces) + a_pKey = a_pData; + while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + // *a_pData is null, equals, or newline + + // if no value and we don't allow no value, then invalid + bHaveValue = (*a_pData == '='); + if (!bHaveValue && !m_bAllowKeyOnly) { + continue; + } + + // empty keys are invalid + if (bHaveValue && a_pKey == a_pData) { + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + continue; + } + + // remove trailing spaces from the key + pTrail = a_pData - 1; + while (pTrail >= a_pKey && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + + if (bHaveValue) { + // process the value + *pTrail = 0; + + // skip leading whitespace on the value + ++a_pData; // safe as checked that it == '=' above + while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the value which is the end of this line + a_pVal = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // remove trailing spaces from the value + pTrail = a_pData - 1; + if (*a_pData) { // prepare for the next round + SkipNewLine(a_pData); + } + while (pTrail >= a_pVal && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // check for multi-line entries + if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) { + // skip the "<<<" to get the tag that will end the multiline + const SI_CHAR* pTagName = a_pVal + 3; + return LoadMultiLineText(a_pData, a_pVal, pTagName); + } + + // check for quoted values, we are not supporting escapes in quoted values (yet) + if (m_bParseQuotes) { + --pTrail; + if (pTrail > a_pVal && *a_pVal == '"' && *pTrail == '"') { + ++a_pVal; + *pTrail = 0; + } + } + } + else { + // no value to process, just prepare for the next + if (*a_pData) { + SkipNewLine(a_pData); + } + *pTrail = 0; + } + + // return the standard entry + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsMultiLineTag( + const SI_CHAR * a_pVal + ) const +{ + // check for the "<<<" prefix for a multi-line entry + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + return true; +} + +template +bool +CSimpleIniTempl::IsMultiLineData( + const SI_CHAR * a_pData + ) const +{ + // data is multi-line if it has any of the following features: + // * whitespace prefix + // * embedded newlines + // * whitespace suffix + + // empty string + if (!*a_pData) { + return false; + } + + // check for prefix + if (IsSpace(*a_pData)) { + return true; + } + + // embedded newlines + while (*a_pData) { + if (IsNewLineChar(*a_pData)) { + return true; + } + ++a_pData; + } + + // check for suffix + if (IsSpace(*--a_pData)) { + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsSingleLineQuotedValue( + const SI_CHAR* a_pData +) const +{ + // data needs quoting if it starts or ends with whitespace + // and doesn't have embedded newlines + + // empty string + if (!*a_pData) { + return false; + } + + // check for prefix + if (IsSpace(*a_pData)) { + return true; + } + + // embedded newlines + while (*a_pData) { + if (IsNewLineChar(*a_pData)) { + return false; + } + ++a_pData; + } + + // check for suffix + if (IsSpace(*--a_pData)) { + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsNewLineChar( + SI_CHAR a_c + ) const +{ + return (a_c == '\n' || a_c == '\r'); +} + +template +bool +CSimpleIniTempl::LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment + ) const +{ + // we modify this data to strip all newlines down to a single '\n' + // character. This means that on Windows we need to strip out some + // characters which will make the data shorter. + // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become + // LINE1-LINE1\nLINE2-LINE2\0 + // The pDataLine entry is the pointer to the location in memory that + // the current line needs to start to run following the existing one. + // This may be the same as pCurrLine in which case no move is needed. + SI_CHAR * pDataLine = a_pData; + SI_CHAR * pCurrLine; + + // value starts at the current line + a_pVal = a_pData; + + // find the end tag. This tag must start in column 1 and be + // followed by a newline. We ignore any whitespace after the end + // tag but not whitespace before it. + SI_CHAR cEndOfLineChar = *a_pData; + for(;;) { + // if we are loading comments then we need a comment character as + // the first character on every line + if (!a_pTagName && !IsComment(*a_pData)) { + // if we aren't allowing blank lines then we're done + if (!a_bAllowBlankLinesInComment) { + break; + } + + // if we are allowing blank lines then we only DB them + // in this comment if another comment follows, so read ahead + // to find out. + SI_CHAR * pCurr = a_pData; + int nNewLines = 0; + while (IsSpace(*pCurr)) { + if (IsNewLineChar(*pCurr)) { + ++nNewLines; + SkipNewLine(pCurr); + } + else { + ++pCurr; + } + } + + // we have a comment, add the blank lines to the output + // and continue processing from here + if (IsComment(*pCurr)) { + for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n'; + a_pData = pCurr; + continue; + } + + // the comment ends here + break; + } + + // find the end of this line + pCurrLine = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData; + + // move this line down to the location that it should be if necessary + if (pDataLine < pCurrLine) { + size_t nLen = (size_t) (a_pData - pCurrLine); + memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR)); + pDataLine[nLen] = '\0'; + } + + // end the line with a NULL + cEndOfLineChar = *a_pData; + *a_pData = 0; + + // if are looking for a tag then do the check now. This is done before + // checking for end of the data, so that if we have the tag at the end + // of the data then the tag is removed correctly. + if (a_pTagName) { + // strip whitespace from the end of this tag + SI_CHAR* pc = a_pData - 1; + while (pc > pDataLine && IsSpace(*pc)) --pc; + SI_CHAR ch = *++pc; + *pc = 0; + + if (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)) { + break; + } + + *pc = ch; + } + + // if we are at the end of the data then we just automatically end + // this entry and return the current data. + if (!cEndOfLineChar) { + return true; + } + + // otherwise we need to process this newline to ensure that it consists + // of just a single \n character. + pDataLine += (a_pData - pCurrLine); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + *pDataLine++ = '\n'; + } + + // if we didn't find a comment at all then return false + if (a_pVal == a_pData) { + a_pVal = NULL; + return false; + } + + // the data (which ends at the end of the last line) needs to be + // null-terminated BEFORE before the newline character(s). If the + // user wants a new line in the multi-line data then they need to + // add an empty line before the tag. + *--pDataLine = '\0'; + + // if looking for a tag and if we aren't at the end of the data, + // then move a_pData to the start of the next line. + if (a_pTagName && cEndOfLineChar) { + SI_ASSERT(IsNewLineChar(cEndOfLineChar)); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::CopyString( + const SI_CHAR *& a_pString + ) +{ + size_t uLen = 0; + if (sizeof(SI_CHAR) == sizeof(char)) { + uLen = strlen((const char *)a_pString); + } + else if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + uLen = wcslen((const wchar_t *)a_pString); + } + else { + for ( ; a_pString[uLen]; ++uLen) /*loop*/ ; + } + ++uLen; // NULL character + SI_CHAR * pCopy = new(std::nothrow) SI_CHAR[uLen]; + if (!pCopy) { + return SI_NOMEM; + } + memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen); + m_strings.push_back(pCopy); + a_pString = pCopy; + return SI_OK; +} + +template +SI_Error +CSimpleIniTempl::AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ) +{ + SI_Error rc; + bool bInserted = false; + + SI_ASSERT(!a_pComment || IsComment(*a_pComment)); + + // if we are copying strings then make a copy of the comment now + // because we will need it when we add the entry. + if (a_bCopyStrings && a_pComment) { + rc = CopyString(a_pComment); + if (rc < 0) return rc; + } + + // create the section entry if necessary + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + // if the section doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + if (a_bCopyStrings) { + rc = CopyString(a_pSection); + if (rc < 0) return rc; + } + + // only set the comment if this is a section only entry + Entry oSection(a_pSection, ++m_nOrder); + if (a_pComment && !a_pKey) { + oSection.pComment = a_pComment; + } + + typename TSection::value_type oEntry(oSection, TKeyVal()); + typedef typename TSection::iterator SectionIterator; + std::pair i = m_data.insert(oEntry); + iSection = i.first; + bInserted = true; + } + if (!a_pKey) { + // section only entries are specified with pItem as NULL + return bInserted ? SI_INSERTED : SI_UPDATED; + } + + // check for existence of the key + TKeyVal & keyval = iSection->second; + typename TKeyVal::iterator iKey = keyval.find(a_pKey); + bInserted = iKey == keyval.end(); + + // remove all existing entries but save the load order and + // comment of the first entry + int nLoadOrder = ++m_nOrder; + if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) { + const SI_CHAR * pComment = NULL; + while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) { + if (iKey->first.nOrder < nLoadOrder) { + nLoadOrder = iKey->first.nOrder; + pComment = iKey->first.pComment; + } + ++iKey; + } + if (pComment) { + DeleteString(a_pComment); + a_pComment = pComment; + CopyString(a_pComment); + } + Delete(a_pSection, a_pKey); + iKey = keyval.end(); + } + + // values need to be a valid string, even if they are an empty string + if (!a_pValue) { + a_pValue = &m_cEmptyString; + } + + // make string copies if necessary + bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace; + if (a_bCopyStrings) { + if (bForceCreateNewKey || iKey == keyval.end()) { + // if the key doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + // because we will be inserting the key next + rc = CopyString(a_pKey); + if (rc < 0) return rc; + } + + // we always need a copy of the value + rc = CopyString(a_pValue); + if (rc < 0) return rc; + } + + // create the key entry + if (iKey == keyval.end() || bForceCreateNewKey) { + Entry oKey(a_pKey, nLoadOrder); + if (a_pComment) { + oKey.pComment = a_pComment; + } + typename TKeyVal::value_type oEntry(oKey, static_cast(NULL)); + iKey = keyval.insert(oEntry); + } + + iKey->second = a_pValue; + return bInserted ? SI_INSERTED : SI_UPDATED; +} + +template +const SI_CHAR * +CSimpleIniTempl::GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault, + bool * a_pHasMultiple + ) const +{ + if (a_pHasMultiple) { + *a_pHasMultiple = false; + } + if (!a_pSection || !a_pKey) { + return a_pDefault; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return a_pDefault; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return a_pDefault; + } + + // check for multiple entries with the same key + if (m_bAllowMultiKey && a_pHasMultiple) { + typename TKeyVal::const_iterator iTemp = iKeyVal; + if (++iTemp != iSection->second.end()) { + if (!IsLess(a_pKey, iTemp->first.pItem)) { + *a_pHasMultiple = true; + } + } + } + + return iKeyVal->second; +} + +template +long +CSimpleIniTempl::GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + // handle the value as hex if prefaced with "0x" + long nValue = a_nDefault; + char * pszSuffix = szValue; + if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) { + if (!szValue[2]) return a_nDefault; + nValue = strtol(&szValue[2], &pszSuffix, 16); + } + else { + nValue = strtol(szValue, &pszSuffix, 10); + } + + // any invalid strings will return the default value + if (*pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment, + bool a_bUseHex, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +double +CSimpleIniTempl::GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + char * pszSuffix = NULL; + double nValue = strtod(szValue, &pszSuffix); + + // any invalid strings will return the default value + if (!pszSuffix || *pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, "%f", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, "%f", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_bDefault; + + // we only look at the minimum number of characters + switch (pszValue[0]) { + case 't': case 'T': // true + case 'y': case 'Y': // yes + case '1': // 1 (one) + return true; + + case 'f': case 'F': // false + case 'n': case 'N': // no + case '0': // 0 (zero) + return false; + + case 'o': case 'O': + if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on + if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off + break; + } + + // no recognized value, return the default + return a_bDefault; +} + +template +SI_Error +CSimpleIniTempl::SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + const char * pszInput = a_bValue ? "true" : "false"; + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(pszInput, strlen(pszInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const +{ + a_values.clear(); + + if (!a_pSection || !a_pKey) { + return false; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + // insert all values for this key + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + if (m_bAllowMultiKey) { + ++iKeyVal; + while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) { + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + ++iKeyVal; + } + } + + return true; +} + +template +int +CSimpleIniTempl::GetSectionSize( + const SI_CHAR * a_pSection + ) const +{ + if (!a_pSection) { + return -1; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return -1; + } + const TKeyVal & section = iSection->second; + + // if multi-key isn't permitted then the section size is + // the number of keys that we have. + if (!m_bAllowMultiKey || section.empty()) { + return (int) section.size(); + } + + // otherwise we need to count them + int nCount = 0; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + ++nCount; + pLastKey = iKeyVal->first.pItem; + } + } + return nCount; +} + +template +const typename CSimpleIniTempl::TKeyVal * +CSimpleIniTempl::GetSection( + const SI_CHAR * a_pSection + ) const +{ + if (a_pSection) { + typename TSection::const_iterator i = m_data.find(a_pSection); + if (i != m_data.end()) { + return &(i->second); + } + } + return 0; +} + +template +void +CSimpleIniTempl::GetAllSections( + TNamesDepend & a_names + ) const +{ + a_names.clear(); + typename TSection::const_iterator i = m_data.begin(); + for (int n = 0; i != m_data.end(); ++i, ++n ) { + a_names.push_back(i->first); + } +} + +template +bool +CSimpleIniTempl::GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const +{ + a_names.clear(); + + if (!a_pSection) { + return false; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + const TKeyVal & section = iSection->second; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + a_names.push_back(iKeyVal->first); + pLastKey = iKeyVal->first.pItem; + } + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::SaveFile( + const char * a_pszFile, + bool a_bAddSignature + ) const +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::SaveFile( + const SI_WCHAR_T * a_pwszFile, + bool a_bAddSignature + ) const +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return SaveFile(szFile, a_bAddSignature); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::SaveFile( + FILE * a_pFile, + bool a_bAddSignature + ) const +{ + FileWriter writer(a_pFile); + return Save(writer, a_bAddSignature); +} + +template +SI_Error +CSimpleIniTempl::Save( + OutputWriter & a_oOutput, + bool a_bAddSignature + ) const +{ + Converter convert(m_bStoreIsUtf8); + + // add the UTF-8 signature if it is desired + if (m_bStoreIsUtf8 && a_bAddSignature) { + a_oOutput.Write(SI_UTF8_SIGNATURE); + } + + // get all of the sections sorted in load order + TNamesDepend oSections; + GetAllSections(oSections); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oSections.sort(); +#elif defined(__BORLANDC__) + oSections.sort(Entry::LoadOrder()); +#else + oSections.sort(typename Entry::LoadOrder()); +#endif + + // if there is an empty section name, then it must be written out first + // regardless of the load order + typename TNamesDepend::iterator is = oSections.begin(); + for (; is != oSections.end(); ++is) { + if (!*is->pItem) { + // move the empty section name to the front of the section list + if (is != oSections.begin()) { + oSections.splice(oSections.begin(), oSections, is, std::next(is)); + } + break; + } + } + + // write the file comment if we have one + bool bNeedNewLine = false; + if (m_pFileComment) { + if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) { + return SI_FAIL; + } + bNeedNewLine = true; + } + + // iterate through our sections and output the data + typename TNamesDepend::const_iterator iSection = oSections.begin(); + for ( ; iSection != oSections.end(); ++iSection ) { + // write out the comment if there is one + if (iSection->pComment) { + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + } + if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) { + return SI_FAIL; + } + bNeedNewLine = false; + } + + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + bNeedNewLine = false; + } + + // write the section (unless there is no section name) + if (*iSection->pItem) { + if (!convert.ConvertToStore(iSection->pItem)) { + return SI_FAIL; + } + a_oOutput.Write("["); + a_oOutput.Write(convert.Data()); + a_oOutput.Write("]"); + a_oOutput.Write(SI_NEWLINE_A); + } + + // get all of the keys sorted in load order + TNamesDepend oKeys; + GetAllKeys(iSection->pItem, oKeys); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oKeys.sort(); +#elif defined(__BORLANDC__) + oKeys.sort(Entry::LoadOrder()); +#else + oKeys.sort(typename Entry::LoadOrder()); +#endif + + // write all keys and values + typename TNamesDepend::const_iterator iKey = oKeys.begin(); + for ( ; iKey != oKeys.end(); ++iKey) { + // get all values for this key + TNamesDepend oValues; + GetAllValues(iSection->pItem, iKey->pItem, oValues); + + typename TNamesDepend::const_iterator iValue = oValues.begin(); + for ( ; iValue != oValues.end(); ++iValue) { + // write out the comment if there is one + if (iValue->pComment) { + a_oOutput.Write(SI_NEWLINE_A); + if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) { + return SI_FAIL; + } + } + + // write the key + if (!convert.ConvertToStore(iKey->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(convert.Data()); + + // write the value as long + if (*iValue->pItem || !m_bAllowKeyOnly) { + if (!convert.ConvertToStore(iValue->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(m_bSpaces ? " = " : "="); + if (m_bParseQuotes && IsSingleLineQuotedValue(iValue->pItem)) { + // the only way to preserve external whitespace on a value (i.e. before or after) + // is to quote it. This is simple quoting, we don't escape quotes within the data. + a_oOutput.Write("\""); + a_oOutput.Write(convert.Data()); + a_oOutput.Write("\""); + } + else if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) { + // multi-line data needs to be processed specially to ensure + // that we use the correct newline format for the current system + a_oOutput.Write("<<pItem)) { + return SI_FAIL; + } + a_oOutput.Write("END_OF_TEXT"); + } + else { + a_oOutput.Write(convert.Data()); + } + } + a_oOutput.Write(SI_NEWLINE_A); + } + } + + bNeedNewLine = true; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const +{ + const SI_CHAR * pEndOfLine; + SI_CHAR cEndOfLineChar = *a_pText; + while (cEndOfLineChar) { + // find the end of this line + pEndOfLine = a_pText; + for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ; + cEndOfLineChar = *pEndOfLine; + + // temporarily null terminate, convert and output the line + *const_cast(pEndOfLine) = 0; + if (!a_oConverter.ConvertToStore(a_pText)) { + return false; + } + *const_cast(pEndOfLine) = cEndOfLineChar; + a_pText += (pEndOfLine - a_pText) + 1; + a_oOutput.Write(a_oConverter.Data()); + a_oOutput.Write(SI_NEWLINE_A); + } + return true; +} + +template +bool +CSimpleIniTempl::Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty + ) +{ + return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty); +} + +template +bool +CSimpleIniTempl::DeleteValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + bool a_bRemoveEmpty + ) +{ + if (!a_pSection) { + return false; + } + + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + // remove a single key if we have a keyname + if (a_pKey) { + typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + const static SI_STRLESS isLess = SI_STRLESS(); + + // remove any copied strings and then the key + typename TKeyVal::iterator iDelete; + bool bDeleted = false; + do { + iDelete = iKeyVal++; + + if(a_pValue == NULL || + (isLess(a_pValue, iDelete->second) == false && + isLess(iDelete->second, a_pValue) == false)) { + DeleteString(iDelete->first.pItem); + DeleteString(iDelete->second); + iSection->second.erase(iDelete); + bDeleted = true; + } + } + while (iKeyVal != iSection->second.end() + && !IsLess(a_pKey, iKeyVal->first.pItem)); + + if(!bDeleted) { + return false; + } + + // done now if the section is not empty or we are not pruning away + // the empty sections. Otherwise let it fall through into the section + // deletion code + if (!a_bRemoveEmpty || !iSection->second.empty()) { + return true; + } + } + else { + // delete all copied strings from this section. The actual + // entries will be removed when the section is removed. + typename TKeyVal::iterator iKeyVal = iSection->second.begin(); + for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) { + DeleteString(iKeyVal->first.pItem); + DeleteString(iKeyVal->second); + } + } + + // delete the section itself + DeleteString(iSection->first.pItem); + m_data.erase(iSection); + + return true; +} + +template +void +CSimpleIniTempl::DeleteString( + const SI_CHAR * a_pString + ) +{ + // strings may exist either inside the data block, or they will be + // individually allocated and stored in m_strings. We only physically + // delete those stored in m_strings. + if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (;i != m_strings.end(); ++i) { + if (a_pString == i->pItem) { + delete[] const_cast(i->pItem); + m_strings.erase(i); + break; + } + } + } +} + +// --------------------------------------------------------------------------- +// CONVERSION FUNCTIONS +// --------------------------------------------------------------------------- + +// Defines the conversion classes for different libraries. Before including +// SimpleIni.h, set the converter that you wish you use by defining one of the +// following symbols. +// +// SI_NO_CONVERSION Do not make the "W" wide character version of the +// library available. Only CSimpleIniA etc is defined. +// SI_CONVERT_GENERIC Use the Unicode reference conversion library in +// the accompanying files ConvertUTF.h/c +// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires +// ICU headers on DB path and icuuc.lib +// SI_CONVERT_WIN32 Use the Win32 API functions for conversion. + +#if !defined(SI_NO_CONVERSION) && !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU) +# ifdef _WIN32 +# define SI_CONVERT_WIN32 +# else +# define SI_CONVERT_GENERIC +# endif +#endif + +/** + * Generic case-sensitive less than comparison. This class returns numerically + * ordered ASCII case-sensitive text for all possible sizes and types of + * SI_CHAR. + */ +template +struct SI_GenericCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) *pLeft - (long) *pRight; + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Generic ASCII case-insensitive less than comparison. This class returns + * numerically ordered ASCII case-insensitive text for all possible sizes + * and types of SI_CHAR. It is not safe for MBCS text comparison where + * ASCII A-Z characters are used in the encoding of multi-byte characters. + */ +template +struct SI_GenericNoCase { + inline SI_CHAR locase(SI_CHAR ch) const { + return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a'); + } + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) locase(*pLeft) - (long) locase(*pRight); + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Null conversion class for MBCS/UTF-8 to char (or equivalent). + */ +template +class SI_ConvertA { + bool m_bStoreIsUtf8; +protected: + SI_ConvertA() { } +public: + SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); } + SI_ConvertA & operator=(const SI_ConvertA & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + (void)a_pInputData; + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + // ASCII/MBCS/UTF-8 needs no conversion + return a_uInputDataLen; + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + // ASCII/MBCS/UTF-8 needs no conversion + if (a_uInputDataLen > a_uOutputDataSize) { + return false; + } + memcpy(a_pOutputData, a_pInputData, a_uInputDataLen); + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + // ASCII/MBCS/UTF-8 needs no conversion + return strlen((const char *)a_pInputData) + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = strlen((const char *)a_pInputData) + 1; + if (uInputLen > a_uOutputDataSize) { + return false; + } + + // ascii/UTF-8 needs no conversion + memcpy(a_pOutputData, a_pInputData, uInputLen); + return true; + } +}; + + +// --------------------------------------------------------------------------- +// SI_CONVERT_GENERIC +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_GENERIC + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#include +#include "ConvertUTF.h" + +/** + * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference + * library functions. This can be used on all platforms. + */ +template +class SI_ConvertW { + bool m_bStoreIsUtf8; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + if (m_bStoreIsUtf8) { + // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t + // so we just return the same number of characters required as for + // the source text. + return a_uInputDataLen; + } + +#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux)) + // fall back processing for platforms that don't support a NULL dest to mbstowcs + // worst case scenario is 1:1, this will be a sufficient buffer size + (void)a_pInputData; + return a_uInputDataLen; +#else + // get the actual required buffer size + return mbstowcs(NULL, a_pInputData, a_uInputDataLen); +#endif + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + if (m_bStoreIsUtf8) { + // This uses the Unicode reference implementation to do the + // conversion from UTF-8 to wchar_t. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + const UTF8 * pUtf8 = (const UTF8 *) a_pInputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + UTF32 * pUtf32 = (UTF32 *) a_pOutputData; + retval = ConvertUTF8toUTF32( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf32, pUtf32 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + UTF16 * pUtf16 = (UTF16 *) a_pOutputData; + retval = ConvertUTF8toUTF16( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf16, pUtf16 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + + // convert to wchar_t + size_t retval = mbstowcs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t)(-1); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + if (m_bStoreIsUtf8) { + // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char + size_t uLen = 0; + while (a_pInputData[uLen]) { + ++uLen; + } + return (6 * uLen) + 1; + } + else { + size_t uLen = wcstombs(NULL, a_pInputData, 0); + if (uLen == (size_t)(-1)) { + return uLen; + } + return uLen + 1; // DB NULL terminator + } + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize + ) + { + if (m_bStoreIsUtf8) { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = 0; + while (a_pInputData[uInputLen]) { + ++uInputLen; + } + ++uInputLen; // DB the NULL char + + // This uses the Unicode reference implementation to do the + // conversion from wchar_t to UTF-8. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + UTF8 * pUtf8 = (UTF8 *) a_pOutputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + const UTF32 * pUtf32 = (const UTF32 *) a_pInputData; + retval = ConvertUTF32toUTF8( + &pUtf32, pUtf32 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + const UTF16 * pUtf16 = (const UTF16 *) a_pInputData; + retval = ConvertUTF16toUTF8( + &pUtf16, pUtf16 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + else { + size_t retval = wcstombs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t) -1; + } + } +}; + +#endif // SI_CONVERT_GENERIC + + +// --------------------------------------------------------------------------- +// SI_CONVERT_ICU +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_ICU + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#DB + +/** + * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms. + */ +template +class SI_ConvertW { + const char * m_pEncoding; + UConverter * m_pConverter; +protected: + SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) { + m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_pEncoding = rhs.m_pEncoding; + m_pConverter = NULL; + return *this; + } + ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); } + + /** Calculate the number of UChar required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of UChar required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen; + } + + /** Convert the input string from the storage format to UChar. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in UChar. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + UChar * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_toUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const UChar * a_pInputData) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0, + a_pInputData, -1, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const UChar * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_fromUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, -1, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } +}; + +#endif // SI_CONVERT_ICU + + +// --------------------------------------------------------------------------- +// SI_CONVERT_WIN32 +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_WIN32 + +#define SI_Case SI_GenericCase + +// Windows CE doesn't have errno or MBCS libraries +#ifdef _WIN32_WCE +# ifndef SI_NO_MBCS +# define SI_NO_MBCS +# endif +#endif + +#DB +#ifdef SI_NO_MBCS +# define SI_NoCase SI_GenericNoCase +#else // !SI_NO_MBCS +/** + * Case-insensitive comparison class using Win32 MBCS functions. This class + * returns a case-insensitive semi-collation order for MBCS text. It may not + * be safe for UTF-8 text returned in char format as we don't know what + * characters will be folded by the function! Therefore, if you are using + * SI_CHAR == char and SetUnicode(true), then you need to use the generic + * SI_NoCase class instead. + */ +#DB +template +struct SI_NoCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + if (sizeof(SI_CHAR) == sizeof(char)) { + return _mbsicmp((const unsigned char *)pLeft, + (const unsigned char *)pRight) < 0; + } + if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + return _wcsicmp((const wchar_t *)pLeft, + (const wchar_t *)pRight) < 0; + } + return SI_GenericNoCase()(pLeft, pRight); + } +}; +#endif // SI_NO_MBCS + +/** + * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses + * only the Win32 functions and doesn't require the external Unicode UTF-8 + * conversion library. It will not work on Windows 95 without using Microsoft + * Layer for Unicode in your application. + */ +template +class SI_ConvertW { + UINT m_uCodePage; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) { + m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_uCodePage = rhs.m_uCodePage; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + int retval = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + 0, 0); + return (size_t)(retval > 0 ? retval : -1); + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + int nSize = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + (wchar_t *) a_pOutputData, (int) a_uOutputDataSize); + return (nSize > 0); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + 0, 0, 0, 0); + return (size_t) (retval > 0 ? retval : -1); + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + a_pOutputData, (int) a_uOutputDataSize, 0, 0); + return retval > 0; + } +}; + +#endif // SI_CONVERT_WIN32 + + + +// --------------------------------------------------------------------------- +// SI_NO_CONVERSION +// --------------------------------------------------------------------------- +#ifdef SI_NO_CONVERSION + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#endif // SI_NO_CONVERSION + + + +// --------------------------------------------------------------------------- +// TYPE DEFINITIONS +// --------------------------------------------------------------------------- + +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniA; +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniCaseA; + +#if defined(SI_NO_CONVERSION) +// if there is no wide char conversion then we don't need to define the +// widechar "W" versions of CSimpleIni +# define CSimpleIni CSimpleIniA +# define CSimpleIniCase CSimpleIniCaseA +# define SI_NEWLINE SI_NEWLINE_A +#else +# if defined(SI_CONVERT_ICU) +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +# else +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +# endif + +# ifdef _UNICODE +# define CSimpleIni CSimpleIniW +# define CSimpleIniCase CSimpleIniCaseW +# define SI_NEWLINE SI_NEWLINE_W +# else // !_UNICODE +# define CSimpleIni CSimpleIniA +# define CSimpleIniCase CSimpleIniCaseA +# define SI_NEWLINE SI_NEWLINE_A +# endif // _UNICODE +#endif + +#ifdef _MSC_VER +# pragma warning (pop) +#endif + +#endif // INCLUDED_SimpleIni_h + diff --git a/include/libevent/evdns.h b/include/libevent/evdns.h new file mode 100644 index 0000000..8672db0 --- /dev/null +++ b/include/libevent/evdns.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVDNS_H_INCLUDED_ +#define EVENT1_EVDNS_H_INCLUDED_ + +/** @file evdns.h + + A dns subsystem for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other + headers. + */ + +#include +#include +#include +#include + +#endif /* EVENT1_EVDNS_H_INCLUDED_ */ diff --git a/include/libevent/event.h b/include/libevent/event.h new file mode 100644 index 0000000..0e33f90 --- /dev/null +++ b/include/libevent/event.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVENT_H_INCLUDED_ +#define EVENT1_EVENT_H_INCLUDED_ + +/** @file event.h + + A library for writing event-driven network servers. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other event2/ + headers. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif +#ifdef EVENT__HAVE_STDINT_H +#include +#endif +#include + +/* For int types. */ +#include + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#undef WIN32_LEAN_AND_MEAN +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT1_EVENT_H_INCLUDED_ */ diff --git a/include/libevent/event2/buffer.h b/include/libevent/event2/buffer.h new file mode 100644 index 0000000..5a76cf2 --- /dev/null +++ b/include/libevent/event2/buffer.h @@ -0,0 +1,1098 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFER_H_INCLUDED_ +#define EVENT2_BUFFER_H_INCLUDED_ + +/** @file event2/buffer.h + + @brief Functions for buffering data for network sending or receiving. + + An evbuffer can be used for preparing data before sending it to + the network or conversely for reading data from the network. + Evbuffers try to avoid memory copies as much as possible. As a + result, evbuffers can be used to pass data around without actually + incurring the overhead of copying the data. + + A new evbuffer can be allocated with evbuffer_new(), and can be + freed with evbuffer_free(). Most users will be using evbuffers via + the bufferevent interface. To access a bufferevent's evbuffers, use + bufferevent_get_input() and bufferevent_get_output(). + + There are several guidelines for using evbuffers. + + - if you already know how much data you are going to add as a result + of calling evbuffer_add() multiple times, it makes sense to use + evbuffer_expand() first to make sure that enough memory is allocated + before hand. + + - evbuffer_add_buffer() adds the contents of one buffer to the other + without incurring any unnecessary memory copies. + + - evbuffer_add() and evbuffer_add_buffer() do not mix very well: + if you use them, you will wind up with fragmented memory in your + buffer. + + - For high-performance code, you may want to avoid copying data into and out + of buffers. You can skip the copy step by using + evbuffer_reserve_space()/evbuffer_commit_space() when writing into a + buffer, and evbuffer_peek() when reading. + + In Libevent 2.0 and later, evbuffers are represented using a linked + list of memory chunks, with pointers to the first and last chunk in + the chain. + + As the contents of an evbuffer can be stored in multiple different + memory blocks, it cannot be accessed directly. Instead, evbuffer_pullup() + can be used to force a specified number of bytes to be contiguous. This + will cause memory reallocation and memory copies if the data is split + across multiple blocks. It is more efficient, however, to use + evbuffer_peek() if you don't require that the memory to be contiguous. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_UIO_H +#include +#endif +#include + +/** + An evbuffer is an opaque data type for efficiently buffering data to be + sent or received on the network. + + @see event2/event.h for more information +*/ +struct evbuffer +#ifdef EVENT_IN_DOXYGEN_ +{} +#endif +; + +/** + Pointer to a position within an evbuffer. + + Used when repeatedly searching through a buffer. Calling any function + that modifies or re-packs the buffer contents may invalidate all + evbuffer_ptrs for that buffer. Do not modify or contruct these values + except with evbuffer_ptr_set. + + An evbuffer_ptr can represent any position from the start of a buffer up + to a position immediately after the end of a buffer. + + @see evbuffer_ptr_set() + */ +struct evbuffer_ptr { + ev_ssize_t pos; + + /* Do not alter or rely on the values of fields: they are for internal + * use */ + struct { + void *chain; + size_t pos_in_chain; + } internal_; +}; + +/** Describes a single extent of memory inside an evbuffer. Used for + direct-access functions. + + @see evbuffer_reserve_space, evbuffer_commit_space, evbuffer_peek + */ +#ifdef EVENT__HAVE_SYS_UIO_H +#define evbuffer_iovec iovec +/* Internal use -- defined only if we are using the native struct iovec */ +#define EVBUFFER_IOVEC_IS_NATIVE_ +#else +struct evbuffer_iovec { + /** The start of the extent of memory. */ + void *iov_base; + /** The length of the extent of memory. */ + size_t iov_len; +}; +#endif + +/** + Allocate storage for a new evbuffer. + + @return a pointer to a newly allocated evbuffer struct, or NULL if an error + occurred + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer *evbuffer_new(void); +/** + Deallocate storage for an evbuffer. + + @param buf pointer to the evbuffer to be freed + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_free(struct evbuffer *buf); + + +/** + Set maximum read buffer size + + Default is 4096 and it works fine most of time, so before increasing the + default check carefully, since this has some negative effects (like memory + fragmentation and unfair resource distribution, i.e. some events will make + less progress than others). + + @param buf pointer to the evbuffer + @param max buffer size + @return 0 on success, -1 on failure (if max > INT_MAX). + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_set_max_read(struct evbuffer *buf, size_t max); +/** + Get maximum read buffer size + + @param buf pointer to the evbuffer + @return current maximum buffer read + */ +EVENT2_EXPORT_SYMBOL +size_t evbuffer_get_max_read(struct evbuffer *buf); + +/** + Enable locking on an evbuffer so that it can safely be used by multiple + threads at the same time. + + NOTE: when locking is enabled, the lock will be held when callbacks are + invoked. This could result in deadlock if you aren't careful. Plan + accordingly! + + @param buf An evbuffer to make lockable. + @param lock A lock object, or NULL if we should allocate our own. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_enable_locking(struct evbuffer *buf, void *lock); + +/** + Acquire the lock on an evbuffer. Has no effect if locking was not enabled + with evbuffer_enable_locking. +*/ +EVENT2_EXPORT_SYMBOL +void evbuffer_lock(struct evbuffer *buf); + +/** + Release the lock on an evbuffer. Has no effect if locking was not enabled + with evbuffer_enable_locking. +*/ +EVENT2_EXPORT_SYMBOL +void evbuffer_unlock(struct evbuffer *buf); + + +/** If this flag is set, then we will not use evbuffer_peek(), + * evbuffer_remove(), evbuffer_remove_buffer(), and so on to read bytes + * from this buffer: we'll only take bytes out of this buffer by + * writing them to the network (as with evbuffer_write_atmost), by + * removing them without observing them (as with evbuffer_drain), + * or by copying them all out at once (as with evbuffer_add_buffer). + * + * Using this option allows the implementation to use sendfile-based + * operations for evbuffer_add_file(); see that function for more + * information. + * + * This flag is on by default for bufferevents that can take advantage + * of it; you should never actually need to set it on a bufferevent's + * output buffer. + */ +#define EVBUFFER_FLAG_DRAINS_TO_FD 1 + +/** Change the flags that are set for an evbuffer by adding more. + * + * @param buf the evbuffer that the callback is watching. + * @param flags One or more EVBUFFER_FLAG_* options + * @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags); +/** Change the flags that are set for an evbuffer by removing some. + * + * @param buf the evbuffer that the callback is watching. + * @param flags One or more EVBUFFER_FLAG_* options + * @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags); + +/** + Returns the total number of bytes stored in the evbuffer + + @param buf pointer to the evbuffer + @return the number of bytes stored in the evbuffer +*/ +EVENT2_EXPORT_SYMBOL +size_t evbuffer_get_length(const struct evbuffer *buf); + +/** + Returns the number of contiguous available bytes in the first buffer chain. + + This is useful when processing data that might be split into multiple + chains, or that might all be in the first chain. Calls to + evbuffer_pullup() that cause reallocation and copying of data can thus be + avoided. + + @param buf pointer to the evbuffer + @return 0 if no data is available, otherwise the number of available bytes + in the first buffer chain. +*/ +EVENT2_EXPORT_SYMBOL +size_t evbuffer_get_contiguous_space(const struct evbuffer *buf); + +/** + Expands the available space in an evbuffer. + + Expands the available space in the evbuffer to at least datlen, so that + appending datlen additional bytes will not require any new allocations. + + @param buf the evbuffer to be expanded + @param datlen the new minimum length requirement + @return 0 if successful, or -1 if an error occurred +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_expand(struct evbuffer *buf, size_t datlen); + +/** + Reserves space in the last chain or chains of an evbuffer. + + Makes space available in the last chain or chains of an evbuffer that can + be arbitrarily written to by a user. The space does not become + available for reading until it has been committed with + evbuffer_commit_space(). + + The space is made available as one or more extents, represented by + an initial pointer and a length. You can force the memory to be + available as only one extent. Allowing more extents, however, makes the + function more efficient. + + Multiple subsequent calls to this function will make the same space + available until evbuffer_commit_space() has been called. + + It is an error to do anything that moves around the buffer's internal + memory structures before committing the space. + + NOTE: The code currently does not ever use more than two extents. + This may change in future versions. + + @param buf the evbuffer in which to reserve space. + @param size how much space to make available, at minimum. The + total length of the extents may be greater than the requested + length. + @param vec an array of one or more evbuffer_iovec structures to + hold pointers to the reserved extents of memory. + @param n_vec The length of the vec array. Must be at least 1; + 2 is more efficient. + @return the number of provided extents, or -1 on error. + @see evbuffer_commit_space() +*/ +EVENT2_EXPORT_SYMBOL +int +evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size, + struct evbuffer_iovec *vec, int n_vec); + +/** + Commits previously reserved space. + + Commits some of the space previously reserved with + evbuffer_reserve_space(). It then becomes available for reading. + + This function may return an error if the pointer in the extents do + not match those returned from evbuffer_reserve_space, or if data + has been added to the buffer since the space was reserved. + + If you want to commit less data than you got reserved space for, + modify the iov_len pointer of the appropriate extent to a smaller + value. Note that you may have received more space than you + requested if it was available! + + @param buf the evbuffer in which to reserve space. + @param vec one or two extents returned by evbuffer_reserve_space. + @param n_vecs the number of extents. + @return 0 on success, -1 on error + @see evbuffer_reserve_space() +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_commit_space(struct evbuffer *buf, + struct evbuffer_iovec *vec, int n_vecs); + +/** + Append data to the end of an evbuffer. + + @param buf the evbuffer to be appended to + @param data pointer to the beginning of the data buffer + @param datlen the number of bytes to be copied from the data buffer + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen); + + +/** + Read data from an evbuffer and drain the bytes read. + + If more bytes are requested than are available in the evbuffer, we + only extract as many bytes as were available. + + @param buf the evbuffer to be read from + @param data the destination buffer to store the result + @param datlen the maximum size of the destination buffer + @return the number of bytes read, or -1 if we can't drain the buffer. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen); + +/** + Read data from an evbuffer, and leave the buffer unchanged. + + If more bytes are requested than are available in the evbuffer, we + only extract as many bytes as were available. + + @param buf the evbuffer to be read from + @param data_out the destination buffer to store the result + @param datlen the maximum size of the destination buffer + @return the number of bytes read, or -1 if we can't drain the buffer. + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen); + +/** + Read data from the middle of an evbuffer, and leave the buffer unchanged. + + If more bytes are requested than are available in the evbuffer, we + only extract as many bytes as were available. + + @param buf the evbuffer to be read from + @param pos the position to start reading from + @param data_out the destination buffer to store the result + @param datlen the maximum size of the destination buffer + @return the number of bytes read, or -1 if we can't drain the buffer. + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos, void *data_out, size_t datlen); + +/** + Read data from an evbuffer into another evbuffer, draining + the bytes from the source buffer. This function avoids copy + operations to the extent possible. + + If more bytes are requested than are available in src, the src + buffer is drained completely. + + @param src the evbuffer to be read from + @param dst the destination evbuffer to store the result into + @param datlen the maximum numbers of bytes to transfer + @return the number of bytes read + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst, + size_t datlen); + +/** Used to tell evbuffer_readln what kind of line-ending to look for. + */ +enum evbuffer_eol_style { + /** Any sequence of CR and LF characters is acceptable as an + * EOL. + * + * Note that this style can produce ambiguous results: the + * sequence "CRLF" will be treated as a single EOL if it is + * all in the buffer at once, but if you first read a CR from + * the network and later read an LF from the network, it will + * be treated as two EOLs. + */ + EVBUFFER_EOL_ANY, + /** An EOL is an LF, optionally preceded by a CR. This style is + * most useful for implementing text-based internet protocols. */ + EVBUFFER_EOL_CRLF, + /** An EOL is a CR followed by an LF. */ + EVBUFFER_EOL_CRLF_STRICT, + /** An EOL is a LF. */ + EVBUFFER_EOL_LF, + /** An EOL is a NUL character (that is, a single byte with value 0) */ + EVBUFFER_EOL_NUL +}; + +/** + * Read a single line from an evbuffer. + * + * Reads a line terminated by an EOL as determined by the evbuffer_eol_style + * argument. Returns a newly allocated nul-terminated string; the caller must + * free the returned value. The EOL is not included in the returned string. + * + * @param buffer the evbuffer to read from + * @param n_read_out if non-NULL, points to a size_t that is set to the + * number of characters in the returned string. This is useful for + * strings that can contain NUL characters. + * @param eol_style the style of line-ending to use. + * @return pointer to a single line, or NULL if an error occurred + */ +EVENT2_EXPORT_SYMBOL +char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out, + enum evbuffer_eol_style eol_style); + +/** + Move all data from one evbuffer into another evbuffer. + + This is a destructive add. The data from one buffer moves into + the other buffer. However, no unnecessary memory copies occur. + + @param outbuf the output buffer + @param inbuf the input buffer + @return 0 if successful, or -1 if an error occurred + + @see evbuffer_remove_buffer() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf); + +/** + Copy data from one evbuffer into another evbuffer. + + This is a non-destructive add. The data from one buffer is copied + into the other buffer. However, no unnecessary memory copies occur. + + Note that buffers already containing buffer references can't be added + to other buffers. + + @param outbuf the output buffer + @param inbuf the input buffer + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_buffer_reference(struct evbuffer *outbuf, + struct evbuffer *inbuf); + +/** + A cleanup function for a piece of memory added to an evbuffer by + reference. + + @see evbuffer_add_reference() + */ +typedef void (*evbuffer_ref_cleanup_cb)(const void *data, + size_t datalen, void *extra); + +/** + Reference memory into an evbuffer without copying. + + The memory needs to remain valid until all the added data has been + read. This function keeps just a reference to the memory without + actually incurring the overhead of a copy. + + @param outbuf the output buffer + @param data the memory to reference + @param datlen how memory to reference + @param cleanupfn callback to be invoked when the memory is no longer + referenced by this evbuffer. + @param cleanupfn_arg optional argument to the cleanup callback + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_reference(struct evbuffer *outbuf, + const void *data, size_t datlen, + evbuffer_ref_cleanup_cb cleanupfn, void *cleanupfn_arg); + +/** + Copy data from a file into the evbuffer for writing to a socket. + + This function avoids unnecessary data copies between userland and + kernel. If sendfile is available and the EVBUFFER_FLAG_DRAINS_TO_FD + flag is set, it uses those functions. Otherwise, it tries to use + mmap (or CreateFileMapping on Windows). + + The function owns the resulting file descriptor and will close it + when finished transferring data. + + The results of using evbuffer_remove() or evbuffer_pullup() on + evbuffers whose data was added using this function are undefined. + + For more fine-grained control, use evbuffer_add_file_segment. + + @param outbuf the output buffer + @param fd the file descriptor + @param offset the offset from which to read data + @param length how much data to read, or -1 to read as much as possible. + (-1 requires that 'fd' support fstat.) + @return 0 if successful, or -1 if an error occurred +*/ + +EVENT2_EXPORT_SYMBOL +int evbuffer_add_file(struct evbuffer *outbuf, int fd, ev_off_t offset, + ev_off_t length); + +/** + An evbuffer_file_segment holds a reference to a range of a file -- + possibly the whole file! -- for use in writing from an evbuffer to a + socket. It could be implemented with mmap or sendfile, or (if all else + fails) by just pulling all the data into RAM. A single evbuffer_file_segment + can be added more than once, and to more than one evbuffer. + */ +struct evbuffer_file_segment; + +/** + Flag for creating evbuffer_file_segment: If this flag is set, then when + the evbuffer_file_segment is freed and no longer in use by any + evbuffer, the underlying fd is closed. + */ +#define EVBUF_FS_CLOSE_ON_FREE 0x01 +/** + Flag for creating evbuffer_file_segment: Disable memory-map based + implementations. + */ +#define EVBUF_FS_DISABLE_MMAP 0x02 +/** + Flag for creating evbuffer_file_segment: Disable direct fd-to-fd + implementations (sendfile). + + You might want to use this option if data needs to be taken from the + evbuffer by any means other than writing it to the network: the sendfile + backend is fast, but it only works for sending files directly to the + network. + */ +#define EVBUF_FS_DISABLE_SENDFILE 0x04 +/** + Flag for creating evbuffer_file_segment: Do not allocate a lock for this + segment. If this option is set, then neither the segment nor any + evbuffer it is added to may ever be accessed from more than one thread + at a time. + */ +#define EVBUF_FS_DISABLE_LOCKING 0x08 + +/** + A cleanup function for a evbuffer_file_segment added to an evbuffer + for reference. + */ +typedef void (*evbuffer_file_segment_cleanup_cb)( + struct evbuffer_file_segment const* seg, int flags, void* arg); + +/** + Create and return a new evbuffer_file_segment for reading data from a + file and sending it out via an evbuffer. + + This function avoids unnecessary data copies between userland and + kernel. Where available, it uses sendfile. + + The file descriptor must not be closed so long as any evbuffer is using + this segment. + + The results of using evbuffer_remove() or evbuffer_pullup() or any other + function that reads bytes from an evbuffer on any evbuffer containing + the newly returned segment are undefined, unless you pass the + EVBUF_FS_DISABLE_SENDFILE flag to this function. + + @param fd an open file to read from. + @param offset an index within the file at which to start reading + @param length how much data to read, or -1 to read as much as possible. + (-1 requires that 'fd' support fstat.) + @param flags any number of the EVBUF_FS_* flags + @return a new evbuffer_file_segment, or NULL on failure. + **/ +EVENT2_EXPORT_SYMBOL +struct evbuffer_file_segment *evbuffer_file_segment_new( + int fd, ev_off_t offset, ev_off_t length, unsigned flags); + +/** + Free an evbuffer_file_segment + + It is safe to call this function even if the segment has been added to + one or more evbuffers. The evbuffer_file_segment will not be freed + until no more references to it exist. + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_file_segment_free(struct evbuffer_file_segment *seg); + +/** + Add cleanup callback and argument for the callback to an + evbuffer_file_segment. + + The cleanup callback will be invoked when no more references to the + evbuffer_file_segment exist. + **/ +EVENT2_EXPORT_SYMBOL +void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg, + evbuffer_file_segment_cleanup_cb cb, void* arg); + +/** + Insert some or all of an evbuffer_file_segment at the end of an evbuffer + + Note that the offset and length parameters of this function have a + different meaning from those provided to evbuffer_file_segment_new: When + you create the segment, the offset is the offset _within the file_, and + the length is the length _of the segment_, whereas when you add a + segment to an evbuffer, the offset is _within the segment_ and the + length is the length of the _part of the segment you want to use. + + In other words, if you have a 10 KiB file, and you create an + evbuffer_file_segment for it with offset 20 and length 1000, it will + refer to bytes 20..1019 inclusive. If you then pass this segment to + evbuffer_add_file_segment and specify an offset of 20 and a length of + 50, you will be adding bytes 40..99 inclusive. + + @param buf the evbuffer to append to + @param seg the segment to add + @param offset the offset within the segment to start from + @param length the amount of data to add, or -1 to add it all. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_file_segment(struct evbuffer *buf, + struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length); + +/** + Append a formatted string to the end of an evbuffer. + + The string is formated as printf. + + @param buf the evbuffer that will be appended to + @param fmt a format string + @param ... arguments that will be passed to printf(3) + @return The number of bytes added if successful, or -1 if an error occurred. + + @see evutil_printf(), evbuffer_add_vprintf() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 2, 3))) +#endif +; + +/** + Append a va_list formatted string to the end of an evbuffer. + + @param buf the evbuffer that will be appended to + @param fmt a format string + @param ap a varargs va_list argument array that will be passed to vprintf(3) + @return The number of bytes added if successful, or -1 if an error occurred. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) +#ifdef __GNUC__ + __attribute__((format(printf, 2, 0))) +#endif +; + + +/** + Remove a specified number of bytes data from the beginning of an evbuffer. + + @param buf the evbuffer to be drained + @param len the number of bytes to drain from the beginning of the buffer + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_drain(struct evbuffer *buf, size_t len); + + +/** + Write the contents of an evbuffer to a file descriptor. + + The evbuffer will be drained after the bytes have been successfully written. + + @param buffer the evbuffer to be written and drained + @param fd the file descriptor to be written to + @return the number of bytes written, or -1 if an error occurred + @see evbuffer_read() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd); + +/** + Write some of the contents of an evbuffer to a file descriptor. + + The evbuffer will be drained after the bytes have been successfully written. + + @param buffer the evbuffer to be written and drained + @param fd the file descriptor to be written to + @param howmuch the largest allowable number of bytes to write, or -1 + to write as many bytes as we can. + @return the number of bytes written, or -1 if an error occurred + @see evbuffer_read() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd, + ev_ssize_t howmuch); + +/** + Read from a file descriptor and store the result in an evbuffer. + + @param buffer the evbuffer to store the result + @param fd the file descriptor to read from + @param howmuch the number of bytes to be read. If the given number is negative + or out of maximum bytes per one read, as many bytes as we can will be read. + @return the number of bytes read, or -1 if an error occurred + @see evbuffer_write() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch); + +/** + Search for a string within an evbuffer. + + @param buffer the evbuffer to be searched + @param what the string to be searched for + @param len the length of the search string + @param start NULL or a pointer to a valid struct evbuffer_ptr. + @return a struct evbuffer_ptr whose 'pos' field has the offset of the + first occurrence of the string in the buffer after 'start'. The 'pos' + field of the result is -1 if the string was not found. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start); + +/** + Search for a string within part of an evbuffer. + + @param buffer the evbuffer to be searched + @param what the string to be searched for + @param len the length of the search string + @param start NULL or a pointer to a valid struct evbuffer_ptr that + indicates where we should start searching. + @param end NULL or a pointer to a valid struct evbuffer_ptr that + indicates where we should stop searching. + @return a struct evbuffer_ptr whose 'pos' field has the offset of the + first occurrence of the string in the buffer after 'start'. The 'pos' + field of the result is -1 if the string was not found. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_ptr evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end); + +/** + Defines how to adjust an evbuffer_ptr by evbuffer_ptr_set() + + @see evbuffer_ptr_set() */ +enum evbuffer_ptr_how { + /** Sets the pointer to the position; can be called on with an + uninitialized evbuffer_ptr. */ + EVBUFFER_PTR_SET, + /** Advances the pointer by adding to the current position. */ + EVBUFFER_PTR_ADD +}; + +/** + Sets the search pointer in the buffer to position. + + There are two ways to use this function: you can call + evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_SET) + to move 'pos' to a position 'N' bytes after the start of the buffer, or + evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_ADD) + to move 'pos' forward by 'N' bytes. + + If evbuffer_ptr is not initialized, this function can only be called + with EVBUFFER_PTR_SET. + + An evbuffer_ptr can represent any position from the start of the buffer to + a position immediately after the end of the buffer. + + @param buffer the evbuffer to be search + @param ptr a pointer to a struct evbuffer_ptr + @param position the position at which to start the next search + @param how determines how the pointer should be manipulated. + @returns 0 on success or -1 otherwise +*/ +EVENT2_EXPORT_SYMBOL +int +evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *ptr, + size_t position, enum evbuffer_ptr_how how); + +/** + Search for an end-of-line string within an evbuffer. + + @param buffer the evbuffer to be searched + @param start NULL or a pointer to a valid struct evbuffer_ptr to start + searching at. + @param eol_len_out If non-NULL, the pointed-to value will be set to + the length of the end-of-line string. + @param eol_style The kind of EOL to look for; see evbuffer_readln() for + more information + @return a struct evbuffer_ptr whose 'pos' field has the offset of the + first occurrence EOL in the buffer after 'start'. The 'pos' + field of the result is -1 if the string was not found. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer, + struct evbuffer_ptr *start, size_t *eol_len_out, + enum evbuffer_eol_style eol_style); + +/** Function to peek at data inside an evbuffer without removing it or + copying it out. + + Pointers to the data are returned by filling the 'vec_out' array + with pointers to one or more extents of data inside the buffer. + + The total data in the extents that you get back may be more than + you requested (if there is more data last extent than you asked + for), or less (if you do not provide enough evbuffer_iovecs, or if + the buffer does not have as much data as you asked to see). + + @param buffer the evbuffer to peek into, + @param len the number of bytes to try to peek. If len is negative, we + will try to fill as much of vec_out as we can. If len is negative + and vec_out is not provided, we return the number of evbuffer_iovecs + that would be needed to get all the data in the buffer. + @param start_at an evbuffer_ptr indicating the point at which we + should start looking for data. NULL means, "At the start of the + buffer." + @param vec_out an array of evbuffer_iovec + @param n_vec the length of vec_out. If 0, we only count how many + extents would be necessary to point to the requested amount of + data. + @return The number of extents needed. This may be less than n_vec + if we didn't need all the evbuffer_iovecs we were given, or more + than n_vec if we would need more to return all the data that was + requested. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len, + struct evbuffer_ptr *start_at, + struct evbuffer_iovec *vec_out, int n_vec); + + +/** Structure passed to an evbuffer_cb_func evbuffer callback + + @see evbuffer_cb_func, evbuffer_add_cb() + */ +struct evbuffer_cb_info { + /** The number of bytes in this evbuffer when callbacks were last + * invoked. */ + size_t orig_size; + /** The number of bytes added since callbacks were last invoked. */ + size_t n_added; + /** The number of bytes removed since callbacks were last invoked. */ + size_t n_deleted; +}; + +/** Type definition for a callback that is invoked whenever data is added or + removed from an evbuffer. + + An evbuffer may have one or more callbacks set at a time. The order + in which they are executed is undefined. + + A callback function may add more callbacks, or remove itself from the + list of callbacks, or add or remove data from the buffer. It may not + remove another callback from the list. + + If a callback adds or removes data from the buffer or from another + buffer, this can cause a recursive invocation of your callback or + other callbacks. If you ask for an infinite loop, you might just get + one: watch out! + + @param buffer the buffer whose size has changed + @param info a structure describing how the buffer changed. + @param arg a pointer to user data +*/ +typedef void (*evbuffer_cb_func)(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg); + +struct evbuffer_cb_entry; +/** Add a new callback to an evbuffer. + + Subsequent calls to evbuffer_add_cb() add new callbacks. To remove this + callback, call evbuffer_remove_cb or evbuffer_remove_cb_entry. + + @param buffer the evbuffer to be monitored + @param cb the callback function to invoke when the evbuffer is modified, + or NULL to remove all callbacks. + @param cbarg an argument to be provided to the callback function + @return a handle to the callback on success, or NULL on failure. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg); + +/** Remove a callback from an evbuffer, given a handle returned from + evbuffer_add_cb. + + Calling this function invalidates the handle. + + @return 0 if a callback was removed, or -1 if no matching callback was + found. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove_cb_entry(struct evbuffer *buffer, + struct evbuffer_cb_entry *ent); + +/** Remove a callback from an evbuffer, given the function and argument + used to add it. + + @return 0 if a callback was removed, or -1 if no matching callback was + found. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg); + +/** If this flag is not set, then a callback is temporarily disabled, and + * should not be invoked. + * + * @see evbuffer_cb_set_flags(), evbuffer_cb_clear_flags() + */ +#define EVBUFFER_CB_ENABLED 1 + +/** Change the flags that are set for a callback on a buffer by adding more. + + @param buffer the evbuffer that the callback is watching. + @param cb the callback whose status we want to change. + @param flags EVBUFFER_CB_ENABLED to re-enable the callback. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_cb_set_flags(struct evbuffer *buffer, + struct evbuffer_cb_entry *cb, ev_uint32_t flags); + +/** Change the flags that are set for a callback on a buffer by removing some + + @param buffer the evbuffer that the callback is watching. + @param cb the callback whose status we want to change. + @param flags EVBUFFER_CB_ENABLED to disable the callback. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_cb_clear_flags(struct evbuffer *buffer, + struct evbuffer_cb_entry *cb, ev_uint32_t flags); + +#if 0 +/** Postpone calling a given callback until unsuspend is called later. + + This is different from disabling the callback, since the callback will get + invoked later if the buffer size changes between now and when we unsuspend + it. + + @param the buffer that the callback is watching. + @param cb the callback we want to suspend. + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb); +/** Stop postponing a callback that we postponed with evbuffer_cb_suspend. + + If data was added to or removed from the buffer while the callback was + suspended, the callback will get called once now. + + @param the buffer that the callback is watching. + @param cb the callback we want to stop suspending. + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb); +#endif + +/** + Makes the data at the beginning of an evbuffer contiguous. + + @param buf the evbuffer to make contiguous + @param size the number of bytes to make contiguous, or -1 to make the + entire buffer contiguous. + @return a pointer to the contiguous memory array, or NULL if param size + requested more data than is present in the buffer. +*/ + +EVENT2_EXPORT_SYMBOL +unsigned char *evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size); + +/** + Prepends data to the beginning of the evbuffer + + @param buf the evbuffer to which to prepend data + @param data a pointer to the memory to prepend + @param size the number of bytes to prepend + @return 0 if successful, or -1 otherwise +*/ + +EVENT2_EXPORT_SYMBOL +int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size); + +/** + Prepends all data from the src evbuffer to the beginning of the dst + evbuffer. + + @param dst the evbuffer to which to prepend data + @param src the evbuffer to prepend; it will be emptied as a result + @return 0 if successful, or -1 otherwise +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src); + +/** + Prevent calls that modify an evbuffer from succeeding. A buffer may + frozen at the front, at the back, or at both the front and the back. + + If the front of a buffer is frozen, operations that drain data from + the front of the buffer, or that prepend data to the buffer, will + fail until it is unfrozen. If the back a buffer is frozen, operations + that append data from the buffer will fail until it is unfrozen. + + @param buf The buffer to freeze + @param at_front If true, we freeze the front of the buffer. If false, + we freeze the back. + @return 0 on success, -1 on failure. +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_freeze(struct evbuffer *buf, int at_front); +/** + Re-enable calls that modify an evbuffer. + + @param buf The buffer to un-freeze + @param at_front If true, we unfreeze the front of the buffer. If false, + we unfreeze the back. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_unfreeze(struct evbuffer *buf, int at_front); + +struct event_base; +/** + Force all the callbacks on an evbuffer to be run, not immediately after + the evbuffer is altered, but instead from inside the event loop. + + This can be used to serialize all the callbacks to a single thread + of execution. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base); + +/** + Append data from 1 or more iovec's to an evbuffer + + Calculates the number of bytes needed for an iovec structure and guarantees + all data will fit into a single chain. Can be used in lieu of functionality + which calls evbuffer_add() constantly before being used to increase + performance. + + @param buffer the destination buffer + @param vec the source iovec + @param n_vec the number of iovec structures. + @return the number of bytes successfully written to the output buffer. +*/ +EVENT2_EXPORT_SYMBOL +size_t evbuffer_add_iovec(struct evbuffer * buffer, struct evbuffer_iovec * vec, int n_vec); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_BUFFER_H_INCLUDED_ */ diff --git a/include/libevent/event2/buffer_compat.h b/include/libevent/event2/buffer_compat.h new file mode 100644 index 0000000..c4092bf --- /dev/null +++ b/include/libevent/event2/buffer_compat.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EVENT2_BUFFER_COMPAT_H_INCLUDED_ +#define EVENT2_BUFFER_COMPAT_H_INCLUDED_ + +#include + +/** @file event2/buffer_compat.h + + @brief Obsolete and deprecated versions of the functions in buffer.h: provided + only for backward compatibility. + */ + + +/** + Obsolete alias for evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY). + + @deprecated This function is deprecated because its behavior is not correct + for almost any protocol, and also because it's wholly subsumed by + evbuffer_readln(). + + @param buffer the evbuffer to read from + @return pointer to a single line, or NULL if an error occurred + +*/ +EVENT2_EXPORT_SYMBOL +char *evbuffer_readline(struct evbuffer *buffer); + +/** Type definition for a callback that is invoked whenever data is added or + removed from an evbuffer. + + An evbuffer may have one or more callbacks set at a time. The order + in which they are executed is undefined. + + A callback function may add more callbacks, or remove itself from the + list of callbacks, or add or remove data from the buffer. It may not + remove another callback from the list. + + If a callback adds or removes data from the buffer or from another + buffer, this can cause a recursive invocation of your callback or + other callbacks. If you ask for an infinite loop, you might just get + one: watch out! + + @param buffer the buffer whose size has changed + @param old_len the previous length of the buffer + @param new_len the current length of the buffer + @param arg a pointer to user data +*/ +typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_len, void *arg); + +/** + Replace all callbacks on an evbuffer with a single new callback, or + remove them. + + Subsequent calls to evbuffer_setcb() replace callbacks set by previous + calls. Setting the callback to NULL removes any previously set callback. + + @deprecated This function is deprecated because it clears all previous + callbacks set on the evbuffer, which can cause confusing behavior if + multiple parts of the code all want to add their own callbacks on a + buffer. Instead, use evbuffer_add(), evbuffer_del(), and + evbuffer_setflags() to manage your own evbuffer callbacks without + interfering with callbacks set by others. + + @param buffer the evbuffer to be monitored + @param cb the callback function to invoke when the evbuffer is modified, + or NULL to remove all callbacks. + @param cbarg an argument to be provided to the callback function + @return 0 if successful, or -1 on error + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg); + + +/** + Find a string within an evbuffer. + + @param buffer the evbuffer to be searched + @param what the string to be searched for + @param len the length of the search string + @return a pointer to the beginning of the search string, or NULL if the search failed. + */ +EVENT2_EXPORT_SYMBOL +unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len); + +/** deprecated in favor of calling the functions directly */ +#define EVBUFFER_LENGTH(x) evbuffer_get_length(x) +/** deprecated in favor of calling the functions directly */ +#define EVBUFFER_DATA(x) evbuffer_pullup((x), -1) + +#endif + diff --git a/include/libevent/event2/bufferevent.h b/include/libevent/event2/bufferevent.h new file mode 100644 index 0000000..a50944f --- /dev/null +++ b/include/libevent/event2/bufferevent.h @@ -0,0 +1,1061 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFEREVENT_H_INCLUDED_ +#define EVENT2_BUFFEREVENT_H_INCLUDED_ + +/** + @file event2/bufferevent.h + + @brief Functions for buffering data for network sending or receiving. + + Bufferevents are higher level than evbuffers: each has an underlying evbuffer for reading + and one for writing, and callbacks that are invoked under certain + circumstances. + + A bufferevent provides input and output buffers that get filled and + drained automatically. The user of a bufferevent no longer deals + directly with the I/O, but instead is reading from input and writing + to output buffers. + + Once initialized, the bufferevent structure can be used repeatedly + with bufferevent_enable() and bufferevent_disable(). + + When reading is enabled, the bufferevent will try to read from the + file descriptor onto its input buffer, and call the read callback. + When writing is enabled, the bufferevent will try to write data onto its + file descriptor when the output buffer has enough data, and call the write + callback when the output buffer is sufficiently drained. + + Bufferevents come in several flavors, including: + +
+
Socket-based bufferevents
+
A bufferevent that reads and writes data onto a network + socket. Created with bufferevent_socket_new().
+ +
Paired bufferevents
+
A pair of bufferevents that send and receive data to one + another without touching the network. Created with + bufferevent_pair_new().
+ +
Filtering bufferevents
+
A bufferevent that transforms data, and sends or receives it + over another underlying bufferevent. Created with + bufferevent_filter_new().
+ +
SSL-backed bufferevents
+
A bufferevent that uses the openssl library to send and + receive data over an encrypted connection. Created with + bufferevent_openssl_socket_new() or + bufferevent_openssl_filter_new().
+
+ */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** @name Bufferevent event codes + + These flags are passed as arguments to a bufferevent's event callback. + + @{ +*/ +#define BEV_EVENT_READING 0x01 /**< error encountered while reading */ +#define BEV_EVENT_WRITING 0x02 /**< error encountered while writing */ +#define BEV_EVENT_EOF 0x10 /**< eof file reached */ +#define BEV_EVENT_ERROR 0x20 /**< unrecoverable error encountered */ +#define BEV_EVENT_TIMEOUT 0x40 /**< user-specified timeout reached */ +#define BEV_EVENT_CONNECTED 0x80 /**< connect operation finished. */ +/**@}*/ + +/** + An opaque type for handling buffered IO + + @see event2/bufferevent.h + */ +struct bufferevent +#ifdef EVENT_IN_DOXYGEN_ +{} +#endif +; +struct event_base; +struct evbuffer; +struct sockaddr; + +/** + A read or write callback for a bufferevent. + + The read callback is triggered when new data arrives in the input + buffer and the amount of readable data exceed the low watermark + which is 0 by default. + + The write callback is triggered if the write buffer has been + exhausted or fell below its low watermark. + + @param bev the bufferevent that triggered the callback + @param ctx the user-specified context for this bufferevent + */ +typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx); + +/** + An event/error callback for a bufferevent. + + The event callback is triggered if either an EOF condition or another + unrecoverable error was encountered. + + For bufferevents with deferred callbacks, this is a bitwise OR of all errors + that have happened on the bufferevent since the last callback invocation. + + @param bev the bufferevent for which the error condition was reached + @param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING + to indicate if the error was encountered on the read or write path, + and one of the following flags: BEV_EVENT_EOF, BEV_EVENT_ERROR, + BEV_EVENT_TIMEOUT, BEV_EVENT_CONNECTED. + + @param ctx the user-specified context for this bufferevent +*/ +typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx); + +/** Options that can be specified when creating a bufferevent */ +enum bufferevent_options { + /** If set, we close the underlying file + * descriptor/bufferevent/whatever when this bufferevent is freed. */ + BEV_OPT_CLOSE_ON_FREE = (1<<0), + + /** If set, and threading is enabled, operations on this bufferevent + * are protected by a lock */ + BEV_OPT_THREADSAFE = (1<<1), + + /** If set, callbacks are run deferred in the event loop. */ + BEV_OPT_DEFER_CALLBACKS = (1<<2), + + /** If set, callbacks are executed without locks being held on the + * bufferevent. This option currently requires that + * BEV_OPT_DEFER_CALLBACKS also be set; a future version of Libevent + * might remove the requirement.*/ + BEV_OPT_UNLOCK_CALLBACKS = (1<<3) +}; + +/** + Create a new socket bufferevent over an existing socket. + + @param base the event base to associate with the new bufferevent. + @param fd the file descriptor from which data is read and written to. + This file descriptor is not allowed to be a pipe(2). + It is safe to set the fd to -1, so long as you later + set it with bufferevent_setfd or bufferevent_socket_connect(). + @param options Zero or more BEV_OPT_* flags + @return a pointer to a newly allocated bufferevent struct, or NULL if an + error occurred + @see bufferevent_free() + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options); + +/** + Launch a connect() attempt with a socket-based bufferevent. + + When the connect succeeds, the eventcb will be invoked with + BEV_EVENT_CONNECTED set. + + If the bufferevent does not already have a socket set, we allocate a new + socket here and make it nonblocking before we begin. + + If no address is provided, we assume that the socket is already connecting, + and configure the bufferevent so that a BEV_EVENT_CONNECTED event will be + yielded when it is done connecting. + + @param bufev an existing bufferevent allocated with + bufferevent_socket_new(). + @param addr the address we should connect to + @param socklen The length of the address + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_socket_connect(struct bufferevent *bufev, const struct sockaddr *addr, int socklen); + +struct evdns_base; +/** + Resolve the hostname 'hostname' and connect to it as with + bufferevent_socket_connect(). + + @param bufev An existing bufferevent allocated with bufferevent_socket_new() + @param evdns_base Optionally, an evdns_base to use for resolving hostnames + asynchronously. May be set to NULL for a blocking resolve. + @param family A preferred address family to resolve addresses to, or + AF_UNSPEC for no preference. Only AF_INET, AF_INET6, and AF_UNSPEC are + supported. + @param hostname The hostname to resolve; see below for notes on recognized + formats + @param port The port to connect to on the resolved address. + @return 0 if successful, -1 on failure. + + @see bufferevent_socket_connect_hostname_hints() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_socket_connect_hostname(struct bufferevent *bufev, + struct evdns_base *evdns_base, int family, const char *hostname, int port); + +/** + Resolve the hostname 'hostname' and connect to it as with + bufferevent_socket_connect(). + + @param bufev An existing bufferevent allocated with bufferevent_socket_new() + @param evdns_base Optionally, an evdns_base to use for resolving hostnames + asynchronously. May be set to NULL for a blocking resolve. + @param hints_in points to an addrinfo structure that specifies criteria for + selecting the socket address structures to be used + @param hostname The hostname to resolve; see below for notes on recognized + formats + @param port The port to connect to on the resolved address. + @return 0 if successful, -1 on failure. + + Recognized hostname formats are: + + www.example.com (hostname) + 1.2.3.4 (ipv4address) + ::1 (ipv6address) + [::1] ([ipv6address]) + + Performance note: If you do not provide an evdns_base, this function + may block while it waits for a DNS response. This is probably not + what you want. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_socket_connect_hostname_hints(struct bufferevent *bufev, + struct evdns_base *evdns_base, const struct evutil_addrinfo *hints_in, const char *hostname, int port); + + +/** + Return the error code for the last failed DNS lookup attempt made by + bufferevent_socket_connect_hostname(). + + @param bev The bufferevent object. + @return DNS error code. + @see evutil_gai_strerror() +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_socket_get_dns_error(struct bufferevent *bev); + +/** + Assign a bufferevent to a specific event_base. + + NOTE that only socket bufferevents support this function. + + @param base an event_base returned by event_init() + @param bufev a bufferevent struct returned by bufferevent_new() + or bufferevent_socket_new() + @return 0 if successful, or -1 if an error occurred + @see bufferevent_new() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); + +/** + Return the event_base used by a bufferevent +*/ +EVENT2_EXPORT_SYMBOL +struct event_base *bufferevent_get_base(struct bufferevent *bev); + +/** + Assign a priority to a bufferevent. + + Only supported for socket bufferevents. + + @param bufev a bufferevent struct + @param pri the priority to be assigned + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_priority_set(struct bufferevent *bufev, int pri); + +/** + Return the priority of a bufferevent. + + Only supported for socket bufferevents + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_get_priority(const struct bufferevent *bufev); + +/** + Deallocate the storage associated with a bufferevent structure. + + If there is pending data to write on the bufferevent, it probably won't be + flushed before the bufferevent is freed. + + @param bufev the bufferevent structure to be freed. + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_free(struct bufferevent *bufev); + + +/** + Changes the callbacks for a bufferevent. + + @param bufev the bufferevent object for which to change callbacks + @param readcb callback to invoke when there is data to be read, or NULL if + no callback is desired + @param writecb callback to invoke when the file descriptor is ready for + writing, or NULL if no callback is desired + @param eventcb callback to invoke when there is an event on the file + descriptor + @param cbarg an argument that will be supplied to each of the callbacks + (readcb, writecb, and errorcb) + @see bufferevent_new() + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_setcb(struct bufferevent *bufev, + bufferevent_data_cb readcb, bufferevent_data_cb writecb, + bufferevent_event_cb eventcb, void *cbarg); + +/** + Retrieves the callbacks for a bufferevent. + + @param bufev the bufferevent to examine. + @param readcb_ptr if readcb_ptr is nonnull, *readcb_ptr is set to the current + read callback for the bufferevent. + @param writecb_ptr if writecb_ptr is nonnull, *writecb_ptr is set to the + current write callback for the bufferevent. + @param eventcb_ptr if eventcb_ptr is nonnull, *eventcb_ptr is set to the + current event callback for the bufferevent. + @param cbarg_ptr if cbarg_ptr is nonnull, *cbarg_ptr is set to the current + callback argument for the bufferevent. + @see buffervent_setcb() +*/ +EVENT2_EXPORT_SYMBOL +void bufferevent_getcb(struct bufferevent *bufev, + bufferevent_data_cb *readcb_ptr, + bufferevent_data_cb *writecb_ptr, + bufferevent_event_cb *eventcb_ptr, + void **cbarg_ptr); + +/** + Changes the file descriptor on which the bufferevent operates. + Not supported for all bufferevent types. + + @param bufev the bufferevent object for which to change the file descriptor + @param fd the file descriptor to operate on +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd); + +/** + Replaces the file descriptor on which the bufferevent operates. + Not supported for all bufferevent types. + + Unlike bufferevent_setfd() it will close previous file descriptor (if any). + + @param bufev the bufferevent object for which to change the file descriptor + @param fd the file descriptor to operate on +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_replacefd(struct bufferevent *bufev, evutil_socket_t fd); + +/** + Returns the file descriptor associated with a bufferevent, or -1 if + no file descriptor is associated with the bufferevent. + */ +EVENT2_EXPORT_SYMBOL +evutil_socket_t bufferevent_getfd(struct bufferevent *bufev); + +/** + Returns the underlying bufferevent associated with a bufferevent (if + the bufferevent is a wrapper), or NULL if there is no underlying bufferevent. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev); + +/** + Write data to a bufferevent buffer. + + The bufferevent_write() function can be used to write data to the file + descriptor. The data is appended to the output buffer and written to the + descriptor automatically as it becomes available for writing. + + @param bufev the bufferevent to be written to + @param data a pointer to the data to be written + @param size the length of the data, in bytes + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write_buffer() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_write(struct bufferevent *bufev, + const void *data, size_t size); + + +/** + Write data from an evbuffer to a bufferevent buffer. The evbuffer is + being drained as a result. + + @param bufev the bufferevent to be written to + @param buf the evbuffer to be written + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); + + +/** + Read data from a bufferevent buffer. + + The bufferevent_read() function is used to read data from the input buffer. + + @param bufev the bufferevent to be read from + @param data pointer to a buffer that will store the data + @param size the size of the data buffer, in bytes + @return the amount of data read, in bytes. If 0 is returned, it is possible + that there is no data in the buffer or that the read failed. + */ +EVENT2_EXPORT_SYMBOL +size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); + +/** + Read data from a bufferevent buffer into an evbuffer. This avoids + memory copies. + + @param bufev the bufferevent to be read from + @param buf the evbuffer to which to add data + @return 0 if successful, or -1 if an error occurred. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf); + +/** + Returns the input buffer. + + The user MUST NOT set the callback on this buffer. + + @param bufev the bufferevent from which to get the evbuffer + @return the evbuffer object for the input buffer + */ + +EVENT2_EXPORT_SYMBOL +struct evbuffer *bufferevent_get_input(struct bufferevent *bufev); + +/** + Returns the output buffer. + + The user MUST NOT set the callback on this buffer. + + When filters are being used, the filters need to be manually + triggered if the output buffer was manipulated. + + @param bufev the bufferevent from which to get the evbuffer + @return the evbuffer object for the output buffer + */ + +EVENT2_EXPORT_SYMBOL +struct evbuffer *bufferevent_get_output(struct bufferevent *bufev); + +/** + Enable a bufferevent. + + @param bufev the bufferevent to be enabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_disable() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_enable(struct bufferevent *bufev, short event); + +/** + Disable a bufferevent. + + @param bufev the bufferevent to be disabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_enable() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_disable(struct bufferevent *bufev, short event); + +/** + Return the events that are enabled on a given bufferevent. + + @param bufev the bufferevent to inspect + @return A combination of EV_READ | EV_WRITE + */ +EVENT2_EXPORT_SYMBOL +short bufferevent_get_enabled(struct bufferevent *bufev); + +/** + Set the read and write timeout for a bufferevent. + + A bufferevent's timeout will fire the first time that the indicated + amount of time has elapsed since a successful read or write operation, + during which the bufferevent was trying to read or write. + + (In other words, if reading or writing is disabled, or if the + bufferevent's read or write operation has been suspended because + there's no data to write, or not enough bandwidth, or so on, the + timeout isn't active. The timeout only becomes active when we we're + willing to actually read or write.) + + Calling bufferevent_enable or setting a timeout for a bufferevent + whose timeout is already pending resets its timeout. + + If the timeout elapses, the corresponding operation (EV_READ or + EV_WRITE) becomes disabled until you re-enable it again. The + bufferevent's event callback is called with the + BEV_EVENT_TIMEOUT|BEV_EVENT_READING or + BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING. + + @param bufev the bufferevent to be modified + @param timeout_read the read timeout, or NULL + @param timeout_write the write timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_timeouts(struct bufferevent *bufev, + const struct timeval *timeout_read, const struct timeval *timeout_write); + +/** + Sets the watermarks for read and write events. + + On input, a bufferevent does not invoke the user read callback unless + there is at least low watermark data in the buffer. If the read buffer + is beyond the high watermark, the bufferevent stops reading from the network. + But be aware that bufferevent input/read buffer can overrun high watermark + limit (typical example is openssl bufferevent), so you should not relay in + this. + + On output, the user write callback is invoked whenever the buffered data + falls below the low watermark. Filters that write to this bufev will try + not to write more bytes to this buffer than the high watermark would allow, + except when flushing. + + @param bufev the bufferevent to be modified + @param events EV_READ, EV_WRITE or both + @param lowmark the lower watermark to set + @param highmark the high watermark to set +*/ + +EVENT2_EXPORT_SYMBOL +void bufferevent_setwatermark(struct bufferevent *bufev, short events, + size_t lowmark, size_t highmark); + +/** + Retrieves the watermarks for read or write events. + Returns non-zero if events contains not only EV_READ or EV_WRITE. + Returns zero if events equal EV_READ or EV_WRITE + + @param bufev the bufferevent to be examined + @param events EV_READ or EV_WRITE + @param lowmark receives the lower watermark if not NULL + @param highmark receives the high watermark if not NULL +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_getwatermark(struct bufferevent *bufev, short events, + size_t *lowmark, size_t *highmark); + +/** + Acquire the lock on a bufferevent. Has no effect if locking was not + enabled with BEV_OPT_THREADSAFE. + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_lock(struct bufferevent *bufev); + +/** + Release the lock on a bufferevent. Has no effect if locking was not + enabled with BEV_OPT_THREADSAFE. + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_unlock(struct bufferevent *bufev); + + +/** + * Public interface to manually increase the reference count of a bufferevent + * this is useful in situations where a user may reference the bufferevent + * somewhere else (unknown to libevent) + * + * @param bufev the bufferevent to increase the refcount on + * + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_incref(struct bufferevent *bufev); + +/** + * Public interface to manually decrement the reference count of a bufferevent + * + * Warning: make sure you know what you're doing. This is mainly used in + * conjunction with bufferevent_incref(). This will free up all data associated + * with a bufferevent if the reference count hits 0. + * + * @param bufev the bufferevent to decrement the refcount on + * + * @return 1 if the bufferevent was freed, otherwise 0 (still referenced) + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_decref(struct bufferevent *bufev); + +/** + Flags that can be passed into filters to let them know how to + deal with the incoming data. +*/ +enum bufferevent_flush_mode { + /** usually set when processing data */ + BEV_NORMAL = 0, + + /** want to checkpoint all data sent. */ + BEV_FLUSH = 1, + + /** encountered EOF on read or done sending data */ + BEV_FINISHED = 2 +}; + +/** + Triggers the bufferevent to produce more data if possible. + + @param bufev the bufferevent object + @param iotype either EV_READ or EV_WRITE or both. + @param mode either BEV_NORMAL or BEV_FLUSH or BEV_FINISHED + @return -1 on failure, 0 if no data was produces, 1 if data was produced + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_flush(struct bufferevent *bufev, + short iotype, + enum bufferevent_flush_mode mode); + +/** + Flags for bufferevent_trigger(_event) that modify when and how to trigger + the callback. +*/ +enum bufferevent_trigger_options { + /** trigger the callback regardless of the watermarks */ + BEV_TRIG_IGNORE_WATERMARKS = (1<<16), + + /** defer even if the callbacks are not */ + BEV_TRIG_DEFER_CALLBACKS = BEV_OPT_DEFER_CALLBACKS + + /* (Note: for internal reasons, these need to be disjoint from + * bufferevent_options, except when they mean the same thing. */ +}; + +/** + Triggers bufferevent data callbacks. + + The function will honor watermarks unless options contain + BEV_TRIG_IGNORE_WATERMARKS. If the options contain BEV_OPT_DEFER_CALLBACKS, + the callbacks are deferred. + + @param bufev the bufferevent object + @param iotype either EV_READ or EV_WRITE or both. + @param options + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_trigger(struct bufferevent *bufev, short iotype, + int options); + +/** + Triggers the bufferevent event callback. + + If the options contain BEV_OPT_DEFER_CALLBACKS, the callbacks are deferred. + + @param bufev the bufferevent object + @param what the flags to pass onto the event callback + @param options + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_trigger_event(struct bufferevent *bufev, short what, + int options); + +/** + @name Filtering support + + @{ +*/ +/** + Values that filters can return. + */ +enum bufferevent_filter_result { + /** everything is okay */ + BEV_OK = 0, + + /** the filter needs to read more data before output */ + BEV_NEED_MORE = 1, + + /** the filter encountered a critical error, no further data + can be processed. */ + BEV_ERROR = 2 +}; + +/** A callback function to implement a filter for a bufferevent. + + @param src An evbuffer to drain data from. + @param dst An evbuffer to add data to. + @param limit A suggested upper bound of bytes to write to dst. + The filter may ignore this value, but doing so means that + it will overflow the high-water mark associated with dst. + -1 means "no limit". + @param mode Whether we should write data as may be convenient + (BEV_NORMAL), or flush as much data as we can (BEV_FLUSH), + or flush as much as we can, possibly including an end-of-stream + marker (BEV_FINISH). + @param ctx A user-supplied pointer. + + @return BEV_OK if we wrote some data; BEV_NEED_MORE if we can't + produce any more output until we get some input; and BEV_ERROR + on an error. + */ +typedef enum bufferevent_filter_result (*bufferevent_filter_cb)( + struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit, + enum bufferevent_flush_mode mode, void *ctx); + +/** + Allocate a new filtering bufferevent on top of an existing bufferevent. + + @param underlying the underlying bufferevent. + @param input_filter The filter to apply to data we read from the underlying + bufferevent + @param output_filter The filer to apply to data we write to the underlying + bufferevent + @param options A bitfield of bufferevent options. + @param free_context A function to use to free the filter context when + this bufferevent is freed. + @param ctx A context pointer to pass to the filter functions. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent * +bufferevent_filter_new(struct bufferevent *underlying, + bufferevent_filter_cb input_filter, + bufferevent_filter_cb output_filter, + int options, + void (*free_context)(void *), + void *ctx); +/**@}*/ + +/** + Allocate a pair of linked bufferevents. The bufferevents behave as would + two bufferevent_sock instances connected to opposite ends of a + socketpair(), except that no internal socketpair is allocated. + + @param base The event base to associate with the socketpair. + @param options A set of options for this bufferevent + @param pair A pointer to an array to hold the two new bufferevent objects. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_pair_new(struct event_base *base, int options, + struct bufferevent *pair[2]); + +/** + Given one bufferevent returned by bufferevent_pair_new(), returns the + other one if it still exists. Otherwise returns NULL. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_pair_get_partner(struct bufferevent *bev); + +/** + Abstract type used to configure rate-limiting on a bufferevent or a group + of bufferevents. + */ +struct ev_token_bucket_cfg; + +/** + A group of bufferevents which are configured to respect the same rate + limit. +*/ +struct bufferevent_rate_limit_group; + +/** Maximum configurable rate- or burst-limit. */ +#define EV_RATE_LIMIT_MAX EV_SSIZE_MAX + +/** + Initialize and return a new object to configure the rate-limiting behavior + of bufferevents. + + @param read_rate The maximum number of bytes to read per tick on + average. + @param read_burst The maximum number of bytes to read in any single tick. + @param write_rate The maximum number of bytes to write per tick on + average. + @param write_burst The maximum number of bytes to write in any single tick. + @param tick_len The length of a single tick. Defaults to one second. + Any fractions of a millisecond are ignored. + + Note that all rate-limits hare are currently best-effort: future versions + of Libevent may implement them more tightly. + */ +EVENT2_EXPORT_SYMBOL +struct ev_token_bucket_cfg *ev_token_bucket_cfg_new( + size_t read_rate, size_t read_burst, + size_t write_rate, size_t write_burst, + const struct timeval *tick_len); + +/** Free all storage held in 'cfg'. + + Note: 'cfg' is not currently reference-counted; it is not safe to free it + until no bufferevent is using it. + */ +EVENT2_EXPORT_SYMBOL +void ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg); + +/** + Set the rate-limit of a the bufferevent 'bev' to the one specified in + 'cfg'. If 'cfg' is NULL, disable any per-bufferevent rate-limiting on + 'bev'. + + Note that only some bufferevent types currently respect rate-limiting. + They are: socket-based bufferevents (normal and IOCP-based), and SSL-based + bufferevents. + + Return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_rate_limit(struct bufferevent *bev, + struct ev_token_bucket_cfg *cfg); + +/** + Create a new rate-limit group for bufferevents. A rate-limit group + constrains the maximum number of bytes sent and received, in toto, + by all of its bufferevents. + + @param base An event_base to run any necessary timeouts for the group. + Note that all bufferevents in the group do not necessarily need to share + this event_base. + @param cfg The rate-limit for this group. + + Note that all rate-limits hare are currently best-effort: future versions + of Libevent may implement them more tightly. + + Note also that only some bufferevent types currently respect rate-limiting. + They are: socket-based bufferevents (normal and IOCP-based), and SSL-based + bufferevents. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent_rate_limit_group *bufferevent_rate_limit_group_new( + struct event_base *base, + const struct ev_token_bucket_cfg *cfg); +/** + Change the rate-limiting settings for a given rate-limiting group. + + Return 0 on success, -1 on failure. +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_set_cfg( + struct bufferevent_rate_limit_group *, + const struct ev_token_bucket_cfg *); + +/** + Change the smallest quantum we're willing to allocate to any single + bufferevent in a group for reading or writing at a time. + + The rationale is that, because of TCP/IP protocol overheads and kernel + behavior, if a rate-limiting group is so tight on bandwidth that you're + only willing to send 1 byte per tick per bufferevent, you might instead + want to batch up the reads and writes so that you send N bytes per + 1/N of the bufferevents (chosen at random) each tick, so you still wind + up send 1 byte per tick per bufferevent on average, but you don't send + so many tiny packets. + + The default min-share is currently 64 bytes. + + Returns 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_set_min_share( + struct bufferevent_rate_limit_group *, size_t); + +/** + Free a rate-limiting group. The group must have no members when + this function is called. +*/ +EVENT2_EXPORT_SYMBOL +void bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *); + +/** + Add 'bev' to the list of bufferevents whose aggregate reading and writing + is restricted by 'g'. If 'g' is NULL, remove 'bev' from its current group. + + A bufferevent may belong to no more than one rate-limit group at a time. + If 'bev' is already a member of a group, it will be removed from its old + group before being added to 'g'. + + Return 0 on success and -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_add_to_rate_limit_group(struct bufferevent *bev, + struct bufferevent_rate_limit_group *g); + +/** Remove 'bev' from its current rate-limit group (if any). */ +EVENT2_EXPORT_SYMBOL +int bufferevent_remove_from_rate_limit_group(struct bufferevent *bev); + +/** + Set the size limit for single read operation. + + Set to 0 for a reasonable default. + + Return 0 on success and -1 on failure. + + @see evbuffer_set_max_read() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size); + +/** + Set the size limit for single write operation. + + Set to 0 for a reasonable default. + + Return 0 on success and -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size); + +/** Get the current size limit for single read operation. */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_single_read(struct bufferevent *bev); + +/** Get the current size limit for single write operation. */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev); + +/** + @name Rate limit inspection + + Return the current read or write bucket size for a bufferevent. + If it is not configured with a per-bufferevent ratelimit, return + EV_SSIZE_MAX. This function does not inspect the group limit, if any. + Note that it can return a negative value if the bufferevent has been + made to read or write more than its limit. + + @{ + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_read_limit(struct bufferevent *bev); +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_write_limit(struct bufferevent *bev); +/*@}*/ + +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_to_read(struct bufferevent *bev); +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_to_write(struct bufferevent *bev); + +EVENT2_EXPORT_SYMBOL +const struct ev_token_bucket_cfg *bufferevent_get_token_bucket_cfg(const struct bufferevent * bev); + +/** + @name Group Rate limit inspection + + Return the read or write bucket size for a bufferevent rate limit + group. Note that it can return a negative value if bufferevents in + the group have been made to read or write more than their limits. + + @{ + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_rate_limit_group_get_read_limit( + struct bufferevent_rate_limit_group *); +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_rate_limit_group_get_write_limit( + struct bufferevent_rate_limit_group *); +/*@}*/ + +/** + @name Rate limit manipulation + + Subtract a number of bytes from a bufferevent's read or write bucket. + The decrement value can be negative, if you want to manually refill + the bucket. If the change puts the bucket above or below zero, the + bufferevent will resume or suspend reading writing as appropriate. + These functions make no change in the buckets for the bufferevent's + group, if any. + + Returns 0 on success, -1 on internal error. + + @{ + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr); +EVENT2_EXPORT_SYMBOL +int bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr); +/*@}*/ + +/** + @name Group rate limit manipulation + + Subtract a number of bytes from a bufferevent rate-limiting group's + read or write bucket. The decrement value can be negative, if you + want to manually refill the bucket. If the change puts the bucket + above or below zero, the bufferevents in the group will resume or + suspend reading writing as appropriate. + + Returns 0 on success, -1 on internal error. + + @{ + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_decrement_read( + struct bufferevent_rate_limit_group *, ev_ssize_t); +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_decrement_write( + struct bufferevent_rate_limit_group *, ev_ssize_t); +/*@}*/ + + +/** + * Inspect the total bytes read/written on a group. + * + * Set the variable pointed to by total_read_out to the total number of bytes + * ever read on grp, and the variable pointed to by total_written_out to the + * total number of bytes ever written on grp. */ +EVENT2_EXPORT_SYMBOL +void bufferevent_rate_limit_group_get_totals( + struct bufferevent_rate_limit_group *grp, + ev_uint64_t *total_read_out, ev_uint64_t *total_written_out); + +/** + * Reset the total bytes read/written on a group. + * + * Reset the number of bytes read or written on grp as given by + * bufferevent_rate_limit_group_reset_totals(). */ +EVENT2_EXPORT_SYMBOL +void +bufferevent_rate_limit_group_reset_totals( + struct bufferevent_rate_limit_group *grp); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_BUFFEREVENT_H_INCLUDED_ */ diff --git a/include/libevent/event2/bufferevent_compat.h b/include/libevent/event2/bufferevent_compat.h new file mode 100644 index 0000000..e071322 --- /dev/null +++ b/include/libevent/event2/bufferevent_compat.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson + * Copyright (c) 2000-2007 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_ +#define EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_ + +/** @file event2/bufferevent_compat.h + * + * @brief Deprecated versions of the functions in bufferevent.h: provided + * only for backwards compatibility. + */ + +#include + +#define evbuffercb bufferevent_data_cb +#define everrorcb bufferevent_event_cb + +/** + Create a new bufferevent for an fd. + + This function is deprecated. Use bufferevent_socket_new and + bufferevent_set_callbacks instead. + + Libevent provides an abstraction on top of the regular event callbacks. + This abstraction is called a buffered event. A buffered event provides + input and output buffers that get filled and drained automatically. The + user of a buffered event no longer deals directly with the I/O, but + instead is reading from input and writing to output buffers. + + Once initialized, the bufferevent structure can be used repeatedly with + bufferevent_enable() and bufferevent_disable(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + If multiple bases are in use, bufferevent_base_set() must be called before + enabling the bufferevent for the first time. + + @deprecated This function is deprecated because it uses the current + event base, and as such can be error prone for multithreaded programs. + Use bufferevent_socket_new() instead. + + @param fd the file descriptor from which data is read and written to. + This file descriptor is not allowed to be a pipe(2). + @param readcb callback to invoke when there is data to be read, or NULL if + no callback is desired + @param writecb callback to invoke when the file descriptor is ready for + writing, or NULL if no callback is desired + @param errorcb callback to invoke when there is an error on the file + descriptor + @param cbarg an argument that will be supplied to each of the callbacks + (readcb, writecb, and errorcb) + @return a pointer to a newly allocated bufferevent struct, or NULL if an + error occurred + @see bufferevent_base_set(), bufferevent_free() + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_new(evutil_socket_t fd, + evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); + + +/** + Set the read and write timeout for a buffered event. + + @deprecated Use bufferevent_set_timeouts instead. + + @param bufev the bufferevent to be modified + @param timeout_read the read timeout + @param timeout_write the write timeout + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_settimeout(struct bufferevent *bufev, + int timeout_read, int timeout_write); + +#define EVBUFFER_READ BEV_EVENT_READING +#define EVBUFFER_WRITE BEV_EVENT_WRITING +#define EVBUFFER_EOF BEV_EVENT_EOF +#define EVBUFFER_ERROR BEV_EVENT_ERROR +#define EVBUFFER_TIMEOUT BEV_EVENT_TIMEOUT + +/** macro for getting access to the input buffer of a bufferevent */ +#define EVBUFFER_INPUT(x) bufferevent_get_input(x) +/** macro for getting access to the output buffer of a bufferevent */ +#define EVBUFFER_OUTPUT(x) bufferevent_get_output(x) + +#endif diff --git a/include/libevent/event2/bufferevent_ssl.h b/include/libevent/event2/bufferevent_ssl.h new file mode 100644 index 0000000..009de2b --- /dev/null +++ b/include/libevent/event2/bufferevent_ssl.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ +#define EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ + +/** @file event2/bufferevent_ssl.h + + @brief OpenSSL support for bufferevents. + */ +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + The state of an SSL object to be used when creating a new + SSL bufferevent. + */ +enum bufferevent_ssl_state { + BUFFEREVENT_SSL_OPEN = 0, + BUFFEREVENT_SSL_CONNECTING = 1, + BUFFEREVENT_SSL_ACCEPTING = 2 +}; + +/** Control how to report dirty SSL shutdowns. + + If the peer (or the network, or an attacker) closes the TCP + connection before closing the SSL channel, and the protocol is SSL >= v3, + this is a "dirty" shutdown. If BUFFEREVENT_SSL_DIRTY_SHUTDOWN is not set + (default), this is reported as BEV_EVENT_ERROR. + + If instead BUFFEREVENT_SSL_DIRTY_SHUTDOWN is set, a dirty shutdown is + reported as BEV_EVENT_EOF. + + (Note that if the protocol is < SSLv3, you will always receive + BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure + connection close from a dirty one. This is one reason (among many) + not to use SSL 2.) +*/ +#define BUFFEREVENT_SSL_DIRTY_SHUTDOWN 1 +/** Control writes in the SSL bufferevents. + + By default SSL bufferevent will peek bytes from the buffer as the arrived. + with respect to the segment boundaries in the buffer. + However, by ignoring these segment boundaries number of packets to send + can be decreased. + + This flags will ignore the segment boundaries. + + Useful in conjunction with http layer. +*/ +#define BUFFEREVENT_SSL_BATCH_WRITE 2 + +#if defined(EVENT__HAVE_OPENSSL) || defined(EVENT__HAVE_MBEDTLS) +/** + * Get flags of the SSL bufferevent. + * + * @see BUFFEREVENT_SSL_* + * @return flags or SIZE_MAX in case of error (if bufferevent is not SSL). + */ +EVENT2_EXPORT_SYMBOL +ev_uint64_t bufferevent_ssl_get_flags(struct bufferevent *bev); +/** Change the flags that are set for an ssl bufferevent by adding more. + * + * @param bev the ssl bufferevent. + * @param flags One or more BUFFEREVENT_SSL_* options + * @return old flags success, EV_UINT64_MAX on failure. + */ +EVENT2_EXPORT_SYMBOL +ev_uint64_t bufferevent_ssl_set_flags(struct bufferevent *bev, ev_uint64_t flags); +/** Change the flags that are set for an ssl bufferevent by removing some. + * + * @param bev the bufferevent. + * @param flags One or more BUFFEREVENT_SSL_* options + * @return old flags success, EV_UINT64_MAX on failure. + */ +EVENT2_EXPORT_SYMBOL +ev_uint64_t bufferevent_ssl_clear_flags(struct bufferevent *bev, ev_uint64_t flags); + +#endif /* defined(EVENT__HAVE_OPENSSL) || defined(EVENT__HAVE_MBEDTLS) */ + +#if defined(EVENT__HAVE_OPENSSL) || defined(EVENT_IN_DOXYGEN_) +/* This is what openssl's SSL objects are underneath. */ +struct ssl_st; + +/** + Create a new SSL bufferevent to send its data over another bufferevent. + + @param base An event_base to use to detect reading and writing. It + must also be the base for the underlying bufferevent. + @param underlying A socket to use for this SSL + @param ssl A SSL* object from openssl. + @param state The current state of the SSL connection + @param options One or more bufferevent_options + @return A new bufferevent on success, or NULL on failure +*/ +EVENT2_EXPORT_SYMBOL +struct bufferevent * +bufferevent_openssl_filter_new(struct event_base *base, + struct bufferevent *underlying, + struct ssl_st *ssl, + enum bufferevent_ssl_state state, + int options); + +/** + Create a new SSL bufferevent to send its data over an SSL * on a socket. + + @param base An event_base to use to detect reading and writing + @param fd A socket to use for this SSL + @param ssl A SSL* object from openssl. + @param state The current state of the SSL connection + @param options One or more bufferevent_options + @return A new bufferevent on success, or NULL on failure. +*/ +EVENT2_EXPORT_SYMBOL +struct bufferevent * +bufferevent_openssl_socket_new(struct event_base *base, + evutil_socket_t fd, + struct ssl_st *ssl, + enum bufferevent_ssl_state state, + int options); + +/** + * Get value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_get_flags() instead. + * @see bufferevent_ssl_get_flags() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev); +/** + * Set value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_set_flags() instead. + * @see bufferevent_ssl_set_flags() + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev, + int allow_dirty_shutdown); + +/** Return the underlying openssl SSL * object for an SSL bufferevent. */ +EVENT2_EXPORT_SYMBOL +struct ssl_st * +bufferevent_openssl_get_ssl(struct bufferevent *bufev); + +/** Tells a bufferevent to begin SSL renegotiation. */ +EVENT2_EXPORT_SYMBOL +int bufferevent_ssl_renegotiate(struct bufferevent *bev); + +/** Return the most recent OpenSSL error reported on an SSL bufferevent. */ +EVENT2_EXPORT_SYMBOL +unsigned long bufferevent_get_openssl_error(struct bufferevent *bev); + +#endif +#if defined(EVENT__HAVE_MBEDTLS) || defined(EVENT_IN_DOXYGEN_) +struct mbedtls_ssl_context; +struct mbedtls_ssl_config; +typedef struct mbedtls_ssl_context mbedtls_dyncontext; + +/** + Create a new SSL bufferevent to send its data over another bufferevent. + + @param base An event_base to use to detect reading and writing. It + must also be the base for the underlying bufferevent. + @param underlying A socket to use for this SSL + @param ssl A SSL* object from openssl. + @param state The current state of the SSL connection + @param options One or more bufferevent_options + @return A new bufferevent on success, or NULL on failure +*/ +EVENT2_EXPORT_SYMBOL +struct bufferevent * +bufferevent_mbedtls_filter_new(struct event_base *base, + struct bufferevent *underlying, + mbedtls_dyncontext *ssl, + enum bufferevent_ssl_state state, + int options); + +/** + Create a new SSL bufferevent to send its data over an SSL * on a socket. + + @param base An event_base to use to detect reading and writing + @param fd A socket to use for this SSL + @param ssl A SSL* object from mbedtls. + @param state The current state of the SSL connection + @param options One or more bufferevent_options + @return A new bufferevent on success, or NULL on failure. +*/ +EVENT2_EXPORT_SYMBOL +struct bufferevent * +bufferevent_mbedtls_socket_new(struct event_base *base, + evutil_socket_t fd, + mbedtls_dyncontext *ssl, + enum bufferevent_ssl_state state, + int options); + +/** + * Get value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_get_flags() instead. + * @see bufferevent_ssl_get_flags() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_mbedtls_get_allow_dirty_shutdown(struct bufferevent *bev); +/** + * Set value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_set_flags() instead. + * @see bufferevent_ssl_set_flags() + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_mbedtls_set_allow_dirty_shutdown(struct bufferevent *bev, + int allow_dirty_shutdown); + +/** Return the underlying mbedtls SSL * object for an SSL bufferevent. */ +EVENT2_EXPORT_SYMBOL +struct mbedtls_ssl_context * +bufferevent_mbedtls_get_ssl(struct bufferevent *bufev); + +/** Tells a bufferevent to begin SSL renegotiation. */ +EVENT2_EXPORT_SYMBOL +int bufferevent_mbedtls_renegotiate(struct bufferevent *bev); + +/** Return the most recent MbedTLS error reported on an SSL bufferevent. */ +EVENT2_EXPORT_SYMBOL +unsigned long bufferevent_get_mbedtls_error(struct bufferevent *bev); + +/** Create a new heap-based MbedTLS context for use it in bufferevent_mbedtls_* functions */ +EVENT2_EXPORT_SYMBOL +mbedtls_dyncontext * +bufferevent_mbedtls_dyncontext_new(struct mbedtls_ssl_config *conf); + +/** Deallocate heap-based MbedTLS context */ +EVENT2_EXPORT_SYMBOL +void +bufferevent_mbedtls_dyncontext_free(mbedtls_dyncontext *ctx); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ */ diff --git a/include/libevent/event2/bufferevent_struct.h b/include/libevent/event2/bufferevent_struct.h new file mode 100644 index 0000000..546773a --- /dev/null +++ b/include/libevent/event2/bufferevent_struct.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ +#define EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ + +/** @file event2/bufferevent_struct.h + + Data structures for bufferevents. Using these structures may hurt forward + compatibility with later versions of Libevent: be careful! + + @deprecated Use of bufferevent_struct.h is completely deprecated; these + structures are only exposed for backward compatibility with programs + written before Libevent 2.0 that used them. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include +/* For struct event */ +#include + +struct event_watermark { + size_t low; + size_t high; +}; + +/** + Shared implementation of a bufferevent. + + This type is exposed only because it was exposed in previous versions, + and some people's code may rely on manipulating it. Otherwise, you + should really not rely on the layout, size, or contents of this structure: + it is fairly volatile, and WILL change in future versions of the code. +**/ +struct bufferevent { + /** Event base for which this bufferevent was created. */ + struct event_base *ev_base; + /** Pointer to a table of function pointers to set up how this + bufferevent behaves. */ + const struct bufferevent_ops *be_ops; + + /** A read event that triggers when a timeout has happened or a socket + is ready to read data. Only used by some subtypes of + bufferevent. */ + struct event ev_read; + /** A write event that triggers when a timeout has happened or a socket + is ready to write data. Only used by some subtypes of + bufferevent. */ + struct event ev_write; + + /** An input buffer. Only the bufferevent is allowed to add data to + this buffer, though the user is allowed to drain it. */ + struct evbuffer *input; + + /** An output buffer. Only the bufferevent is allowed to drain data + from this buffer, though the user is allowed to add it. */ + struct evbuffer *output; + + struct event_watermark wm_read; + struct event_watermark wm_write; + + bufferevent_data_cb readcb; + bufferevent_data_cb writecb; + /* This should be called 'eventcb', but renaming it would break + * backward compatibility */ + bufferevent_event_cb errorcb; + void *cbarg; + + struct timeval timeout_read; + struct timeval timeout_write; + + /** Events that are currently enabled: currently EV_READ and EV_WRITE + are supported. */ + short enabled; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ */ diff --git a/include/libevent/event2/dns.h b/include/libevent/event2/dns.h new file mode 100644 index 0000000..be61e78 --- /dev/null +++ b/include/libevent/event2/dns.h @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The original DNS code is due to Adam Langley with heavy + * modifications by Nick Mathewson. Adam put his DNS software in the + * public domain. You can find his original copyright below. Please, + * aware that the code as part of Libevent is governed by the 3-clause + * BSD license above. + * + * This software is Public Domain. To view a copy of the public domain dedication, + * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to + * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. + * + * I ask and expect, but do not require, that all derivative works contain an + * attribution similar to: + * Parts developed by Adam Langley + * + * You may wish to replace the word "Parts" with something else depending on + * the amount of original code. + * + * (Derivative works does not include programs which link against, run or include + * the source verbatim in their source distributions) + */ + +/** @file event2/dns.h + * + * @brief Provides a few APIs to use for resolving DNS names, and a facility + * for implementing simple DNS servers. + * + * Welcome, gentle reader + * + * Async DNS lookups are really a whole lot harder than they should be, + * mostly stemming from the fact that the libc resolver has never been + * very good at them. Before you use this library you should see if libc + * can do the job for you with the modern async call getaddrinfo_a + * (see http://www.imperialviolet.org/page25.html#e498). Otherwise, + * please continue. + * + * The library keeps track of the state of nameservers and will avoid + * them when they go down. Otherwise it will round robin between them. + * + * Quick start guide: + * @code + * #include "evdns.h" + * void callback(int result, char type, int count, int ttl, + * void *addresses, void *arg); + * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); + * evdns_resolve("www.hostname.com", 0, callback, NULL); + *@endcode + * When the lookup is complete the callback function is called. The + * first argument will be one of the DNS_ERR_* defines in evdns.h. + * Hopefully it will be DNS_ERR_NONE, in which case type will be + * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time + * which the data can be cached for (in seconds), addresses will point + * to an array of uint32_t's and arg will be whatever you passed to + * evdns_resolve. + * + * Searching: + * + * In order for this library to be a good replacement for glibc's resolver it + * supports searching. This involves setting a list of default domains, in + * which names will be queried for. The number of dots in the query name + * determines the order in which this list is used. + * + * Searching appears to be a single lookup from the point of view of the API, + * although many DNS queries may be generated from a single call to + * evdns_resolve. Searching can also drastically slow down the resolution + * of names. + * + * To disable searching: + * 1. Never set it up. If you never call evdns_resolv_conf_parse or + * evdns_search_add then no searching will occur. + * + * 2. If you do call evdns_resolv_conf_parse then don't pass + * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it). + * + * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag. + * + * The order of searches depends on the number of dots in the name. If the + * number is greater than the ndots setting then the names is first tried + * globally. Otherwise each search domain is appended in turn. + * + * The ndots setting can either be set from a resolv.conf, or by calling + * evdns_search_ndots_set. + * + * For example, with ndots set to 1 (the default) and a search domain list of + * ["myhome.net"]: + * + *
+ *  Query: www
+ *  Order: www.myhome.net, www.
+ *
+ *  Query: www.abc
+ *  Order: www.abc., www.abc.myhome.net
+ * 
+ * Internals: + * + * Requests are kept in two queues. The first is the inflight queue. In + * this queue requests have an allocated transaction id and nameserver. + * They will soon be transmitted if they haven't already been. + * + * The second is the waiting queue. The size of the inflight ring is + * limited and all other requests wait in waiting queue for space. This + * bounds the number of concurrent requests so that we don't flood the + * nameserver. Several algorithms require a full walk of the inflight + * queue and so bounding its size keeps thing going nicely under huge + * (many thousands of requests) loads. + * + * If a nameserver loses too many requests it is considered down and we + * try not to use it. After a while we send a probe to that nameserver + * (a lookup for google.com) and, if it replies, we consider it working + * again. If the nameserver fails a probe we wait longer to try again + * with the next probe. + */ + +#ifndef EVENT2_DNS_H_INCLUDED_ +#define EVENT2_DNS_H_INCLUDED_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* For integer types. */ +#include + +/** Error codes 0-5 are as described in RFC 1035. */ +#define DNS_ERR_NONE 0 +/** The name server was unable to interpret the query */ +#define DNS_ERR_FORMAT 1 +/** The name server was unable to process this query due to a problem with the + * name server */ +#define DNS_ERR_SERVERFAILED 2 +/** The domain name does not exist */ +#define DNS_ERR_NOTEXIST 3 +/** The name server does not support the requested kind of query */ +#define DNS_ERR_NOTIMPL 4 +/** The name server refuses to reform the specified operation for policy + * reasons */ +#define DNS_ERR_REFUSED 5 +/** The reply was truncated or ill-formatted */ +#define DNS_ERR_TRUNCATED 65 +/** An unknown error occurred */ +#define DNS_ERR_UNKNOWN 66 +/** Communication with the server timed out */ +#define DNS_ERR_TIMEOUT 67 +/** The request was canceled because the DNS subsystem was shut down. */ +#define DNS_ERR_SHUTDOWN 68 +/** The request was canceled via a call to evdns_cancel_request */ +#define DNS_ERR_CANCEL 69 +/** There were no answers and no error condition in the DNS packet. + * This can happen when you ask for an address that exists, but a record + * type that doesn't. */ +#define DNS_ERR_NODATA 70 + +#define DNS_IPv4_A 1 +#define DNS_PTR 2 +#define DNS_IPv6_AAAA 3 +#define DNS_CNAME 4 + +/** Disable searching for the query. */ +#define DNS_QUERY_NO_SEARCH 0x01 +/** Use TCP connections ("virtual circuits") for queries rather than UDP datagrams. */ +#define DNS_QUERY_USEVC 0x02 +/** Ignore trancation flag in responses (don't fallback to TCP connections). */ +#define DNS_QUERY_IGNTC 0x04 +/** Make a separate callback for CNAME in answer */ +#define DNS_CNAME_CALLBACK 0x80 + +/* Allow searching */ +#define DNS_OPTION_SEARCH 1 +/* Parse "nameserver" and add default if no such section */ +#define DNS_OPTION_NAMESERVERS 2 +/* Parse additional options like: + * - timeout: + * - getaddrinfo-allow-skew: + * - max-timeouts: + * - max-inflight: + * - attempts: + * - randomize-case: + * - initial-probe-timeout: + * - max-probe-timeout: + * - probe-backoff-factor: + * - tcp-idle-timeout: + * - edns-udp-size: + * - use-vc + * - ignore-tc + */ +#define DNS_OPTION_MISC 4 +/* Load hosts file (i.e. "/etc/hosts") */ +#define DNS_OPTION_HOSTSFILE 8 +/** + * All above: + * - DNS_OPTION_SEARCH + * - DNS_OPTION_NAMESERVERS + * - DNS_OPTION_MISC + * - DNS_OPTION_HOSTSFILE + */ +#define DNS_OPTIONS_ALL ( \ + DNS_OPTION_SEARCH | \ + DNS_OPTION_NAMESERVERS | \ + DNS_OPTION_MISC | \ + DNS_OPTION_HOSTSFILE | \ + 0 \ +) +/* Do not "default" nameserver (i.e. "127.0.0.1:53") if there is no nameservers + * in resolv.conf, (iff DNS_OPTION_NAMESERVERS is set) */ +#define DNS_OPTION_NAMESERVERS_NO_DEFAULT 16 + +/* Obsolete name for DNS_QUERY_NO_SEARCH */ +#define DNS_NO_SEARCH DNS_QUERY_NO_SEARCH + +/** + * The callback that contains the results from a lookup. + * - result is one of the DNS_ERR_* values (DNS_ERR_NONE for success) + * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA + * - count contains the number of addresses of form type + * - ttl is the number of seconds the resolution may be cached for. + * - addresses needs to be cast according to type. It will be an array of + * 4-byte sequences for ipv4, or an array of 16-byte sequences for ipv6, + * or a nul-terminated string for PTR. + */ +typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg); + +struct evdns_base; +struct event_base; + +/** Flag for evdns_base_new: process resolv.conf. */ +#define EVDNS_BASE_INITIALIZE_NAMESERVERS 1 +/** Flag for evdns_base_new: Do not prevent the libevent event loop from + * exiting when we have no active dns requests. */ +#define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000 +/** Flag for evdns_base_new: If EVDNS_BASE_INITIALIZE_NAMESERVERS isset, do not + * add default nameserver if there are no nameservers in resolv.conf + * @see DNS_OPTION_NAMESERVERS_NO_DEFAULT */ +#define EVDNS_BASE_NAMESERVERS_NO_DEFAULT 0x10000 + +/** + Initialize the asynchronous DNS library. + + This function initializes support for non-blocking name resolution by + calling evdns_resolv_conf_parse() on UNIX and + evdns_config_windows_nameservers() on Windows. + + @param event_base the event base to associate the dns client with + @param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS| + EVDNS_BASE_DISABLE_WHEN_INACTIVE|EVDNS_BASE_NAMESERVERS_NO_DEFAULT + @return evdns_base object if successful, or NULL if an error occurred. + @see evdns_base_free() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_base * evdns_base_new(struct event_base *event_base, int flags); + + +/** + Shut down the asynchronous DNS resolver and terminate all active requests. + + If the 'fail_requests' option is enabled, all active requests will return + an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, + the requests will be silently discarded. + + @param base the evdns base to free + @param fail_requests if zero, active requests will be aborted; if non-zero, + active requests will return DNS_ERR_SHUTDOWN. + @see evdns_base_new() + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_free(struct evdns_base *base, int fail_requests); + +/** + Remove all hosts entries that have been loaded into the event_base via + evdns_base_load_hosts or via event_base_resolv_conf_parse. + + @param base the evdns base to remove outdated host addresses from + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_clear_host_addresses(struct evdns_base *base); + +/** + Convert a DNS error code to a string. + + @param err the DNS error code + @return a string containing an explanation of the error code +*/ +EVENT2_EXPORT_SYMBOL +const char *evdns_err_to_string(int err); + + +/** + Add a nameserver. + + The address should be an IPv4 address in network byte order. + The type of address is chosen so that it matches in_addr.s_addr. + + @param base the evdns_base to which to add the name server + @param address an IP address in network byte order + @return 0 if successful, or -1 if an error occurred + @see evdns_base_nameserver_ip_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_nameserver_add(struct evdns_base *base, + unsigned long int address); + +/** + Get the number of configured nameservers. + + This returns the number of configured nameservers (not necessarily the + number of running nameservers). This is useful for double-checking + whether our calls to the various nameserver configuration functions + have been successful. + + @param base the evdns_base to which to apply this operation + @return the number of configured nameservers + @see evdns_base_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_count_nameservers(struct evdns_base *base); + +/** + Remove all configured nameservers, and suspend all pending resolves. + + Resolves will not necessarily be re-attempted until evdns_base_resume() is called. + + @param base the evdns_base to which to apply this operation + @return 0 if successful, or -1 if an error occurred + @see evdns_base_resume() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base); + + +/** + Resume normal operation and continue any suspended resolve requests. + + Re-attempt resolves left in limbo after an earlier call to + evdns_base_clear_nameservers_and_suspend(). + + @param base the evdns_base to which to apply this operation + @return 0 if successful, or -1 if an error occurred + @see evdns_base_clear_nameservers_and_suspend() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_resume(struct evdns_base *base); + +/** + Add a nameserver by string address. + + This function parses a n IPv4 or IPv6 address from a string and adds it as a + nameserver. It supports the following formats: + - [IPv6Address]:port + - [IPv6Address] + - IPv6Address + - IPv4Address:port + - IPv4Address + + If no port is specified, it defaults to 53. + + @param base the evdns_base to which to apply this operation + @return 0 if successful, or -1 if an error occurred + @see evdns_base_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_nameserver_ip_add(struct evdns_base *base, + const char *ip_as_string); + +/** + Add a nameserver by sockaddr. + **/ +EVENT2_EXPORT_SYMBOL +int +evdns_base_nameserver_sockaddr_add(struct evdns_base *base, + const struct sockaddr *sa, ev_socklen_t len, unsigned flags); + +struct evdns_request; + +/** + Lookup an A record for a given name. + + @param base the evdns_base to which to apply this operation + @param name a DNS hostname + @param flags either 0, or combination of DNS_QUERY_* flags. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr); + +/** + Lookup an AAAA record for a given name. + + @param base the evdns_base to which to apply this operation + @param name a DNS hostname + @param flags either 0, or combination of DNS_QUERY_* flags. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_ipv6(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr); + +struct in_addr; +struct in6_addr; + +/** + Lookup a PTR record for a given IP address. + + @param base the evdns_base to which to apply this operation + @param in an IPv4 address + @param flags either 0, or combination of DNS_QUERY_* flags. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); + + +/** + Lookup a PTR record for a given IPv6 address. + + @param base the evdns_base to which to apply this operation + @param in an IPv6 address + @param flags either 0, or combination of DNS_QUERY_* flags. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); + +/** + Cancels a pending DNS resolution request. + + @param base the evdns_base that was used to make the request + @param req the evdns_request that was returned by calling a resolve function + @see evdns_base_resolve_ipv4(), evdns_base_resolve_ipv6, evdns_base_resolve_reverse +*/ +EVENT2_EXPORT_SYMBOL +void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req); + +/** + Set the value of a configuration option. + + The currently available configuration options are: + + ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case, + bind-to, initial-probe-timeout, max-probe-timeout, probe-backoff-factor, + getaddrinfo-allow-skew, so-rcvbuf, so-sndbuf, tcp-idle-timeout, use-vc, + ignore-tc, edns-udp-size. + + - probe-backoff-factor + Backoff factor of probe timeout + + - max-probe-timeout + Maximum timeout between two probe packets will change initial-probe-timeout + when this value is smaller + + In versions before Libevent 2.0.3-alpha, the option name needed to end with + a colon. + + In case of options without values (use-vc, ingore-tc) val should be an empty + string or NULL. + + @param base the evdns_base to which to apply this operation + @param option the name of the configuration option to be modified + @param val the value to be set + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val); + + +/** + Parse a resolv.conf file. + + The 'flags' parameter determines what information is parsed from the + resolv.conf file. See the man page for resolv.conf for the format of this + file. + + The following directives are not parsed from the file: sortlist, rotate, + no-check-names, inet6, debug. + + If this function encounters an error, the possible return values are: 1 = + failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of + memory, 5 = short read from file, 6 = no nameservers listed in the file + + @param base the evdns_base to which to apply this operation + @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| + DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT + @param filename the path to the resolv.conf file + @return 0 if successful, or various positive error codes if an error + occurred (see above) + @see resolv.conf(3), evdns_config_windows_nameservers() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename); + +/** + Load an /etc/hosts-style file from 'hosts_fname' into 'base'. + + If hosts_fname is NULL, add minimal entries for localhost, and nothing + else. + + Note that only evdns_getaddrinfo uses the /etc/hosts entries. + + This function does not replace previously loaded hosts entries; to do that, + call evdns_base_clear_host_addresses first. + + Return 0 on success, negative on failure. +*/ +EVENT2_EXPORT_SYMBOL +int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname); + +#if defined(EVENT_IN_DOXYGEN_) || defined(_WIN32) +/** + Obtain nameserver information using the Windows API. + + Attempt to configure a set of nameservers based on platform settings on + a win32 host. Preferentially tries to use GetNetworkParams; if that fails, + looks in the registry. + + @return 0 if successful, or -1 if an error occurred + @see evdns_resolv_conf_parse() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_config_windows_nameservers(struct evdns_base *); +#define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED +#endif + + +/** + Clear the list of search domains. + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_search_clear(struct evdns_base *base); + + +/** + Add a domain to the list of search domains + + @param domain the domain to be added to the search list + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_search_add(struct evdns_base *base, const char *domain); + + +/** + Set the 'ndots' parameter for searches. + + Sets the number of dots which, when found in a name, causes + the first query to be without any search domain. + + @param ndots the new ndots parameter + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_search_ndots_set(struct evdns_base *base, const int ndots); + +/** + A callback that is invoked when a log message is generated + + @param is_warning indicates if the log message is a 'warning' + @param msg the content of the log message + */ +typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); + + +/** + Set the callback function to handle DNS log messages. If this + callback is not set, evdns log messages are handled with the regular + Libevent logging system. + + @param fn the callback to be invoked when a log message is generated + */ +EVENT2_EXPORT_SYMBOL +void evdns_set_log_fn(evdns_debug_log_fn_type fn); + +/* + * Functions used to implement a DNS server. + */ + +struct evdns_server_request; +struct evdns_server_question; + +/** + A callback to implement a DNS server. The callback function receives a DNS + request. It should then optionally add a number of answers to the reply + using the evdns_server_request_add_*_reply functions, before calling either + evdns_server_request_respond to send the reply back, or + evdns_server_request_drop to decline to answer the request. + + @param req A newly received request + @param user_data A pointer that was passed to + evdns_add_server_port_with_base(). + */ +typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); +#define EVDNS_ANSWER_SECTION 0 +#define EVDNS_AUTHORITY_SECTION 1 +#define EVDNS_ADDITIONAL_SECTION 2 + +#define EVDNS_TYPE_A 1 +#define EVDNS_TYPE_NS 2 +#define EVDNS_TYPE_CNAME 5 +#define EVDNS_TYPE_SOA 6 +#define EVDNS_TYPE_PTR 12 +#define EVDNS_TYPE_MX 15 +#define EVDNS_TYPE_TXT 16 +#define EVDNS_TYPE_AAAA 28 + +#define EVDNS_QTYPE_AXFR 252 +#define EVDNS_QTYPE_ALL 255 + +#define EVDNS_CLASS_INET 1 + +/* flags that can be set in answers; as part of the err parameter */ +#define EVDNS_FLAGS_AA 0x400 +#define EVDNS_FLAGS_RD 0x080 + +/** Create a new UDP DNS server port. + + @param base The event base to handle events for the server port. + @param socket A UDP socket to accept DNS requests. + @param flags Always 0 for now. + @param callback A function to invoke whenever we get a DNS request + on the socket. + @param user_data Data to pass to the callback. + @return an evdns_server_port structure for this server port or NULL if + an error occurred. + */ +EVENT2_EXPORT_SYMBOL +struct evdns_server_port *evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data); + +struct evconnlistener; + +/** Create a new TCP DNS server port. + + @param base The event base to handle events for the server port. + @param listener A TCP listener to accept DNS requests. + @param flags Always 0 for now. + @param callback A function to invoke whenever we get a DNS request + on the socket. + @param user_data Data to pass to the callback. + @return an evdns_server_port structure for this server port or NULL if + an error occurred. + */ +EVENT2_EXPORT_SYMBOL +struct evdns_server_port *evdns_add_server_port_with_listener( + struct event_base *base, struct evconnlistener *listener, int flags, + evdns_request_callback_fn_type callback, void *user_data); + +/** Close down a DNS server port, and free associated structures. */ +EVENT2_EXPORT_SYMBOL +void evdns_close_server_port(struct evdns_server_port *port); + +/** + * List of configurable evdns_server_port options. + * + * @see evdns_server_port_set_option() + */ +enum evdns_server_option { + /** + * Maximum number of simultaneous tcp connections (clients) + * that server can hold. Can be set only for TCP DNS servers. + */ + EVDNS_SOPT_TCP_MAX_CLIENTS, + /** + * Idle timeout (in seconds) of incoming TCP connections. + * If client doesn't send any requests via the connection + * during this period connection is closed by the server. + * Can be set only for TCP DNS servers. + */ + EVDNS_SOPT_TCP_IDLE_TIMEOUT, +}; + +/** + Configure DNS server. + + @param port the evdns_server_port to which to apply this operation + @param option @see evdns_server_option for the list of possible options + @param val value of the option + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evdns_server_port_set_option(struct evdns_server_port *port, enum evdns_server_option option, size_t value); + +/** Sets some flags in a reply we're building. + Allows setting of the AA or RD flags + */ +EVENT2_EXPORT_SYMBOL +void evdns_server_request_set_flags(struct evdns_server_request *req, int flags); + +/* Functions to add an answer to an in-progress DNS reply. + */ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl); + +/** + Send back a response to a DNS request, and free the request structure. +*/ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_respond(struct evdns_server_request *req, int err); +/** + Free a DNS request without sending back a reply. +*/ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_drop(struct evdns_server_request *req); +struct sockaddr; +/** + Get the address that made a DNS request. + */ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len); + +/** Callback for evdns_getaddrinfo. */ +typedef void (*evdns_getaddrinfo_cb)(int result, struct evutil_addrinfo *res, void *arg); + +struct evdns_base; +struct evdns_getaddrinfo_request; +/** Make a non-blocking getaddrinfo request using the dns_base in 'dns_base'. + * + * If we can answer the request immediately (with an error or not!), then we + * invoke cb immediately and return NULL. Otherwise we return + * an evdns_getaddrinfo_request and invoke cb later. + * + * When the callback is invoked, we pass as its first argument the error code + * that getaddrinfo would return (or 0 for no error). As its second argument, + * we pass the evutil_addrinfo structures we found (or NULL on error). We + * pass 'arg' as the third argument. + * + * Limitations: + * + * - The AI_V4MAPPED and AI_ALL flags are not currently implemented. + * - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0. + * - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0. + */ +EVENT2_EXPORT_SYMBOL +struct evdns_getaddrinfo_request *evdns_getaddrinfo( + struct evdns_base *dns_base, + const char *nodename, const char *servname, + const struct evutil_addrinfo *hints_in, + evdns_getaddrinfo_cb cb, void *arg); + +/* Cancel an in-progress evdns_getaddrinfo. This MUST NOT be called after the + * getaddrinfo's callback has been invoked. The resolves will be canceled, + * and the callback will be invoked with the error EVUTIL_EAI_CANCEL. */ +EVENT2_EXPORT_SYMBOL +void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *req); + +/** + Retrieve the address of the 'idx'th configured nameserver. + + @param base The evdns_base to examine. + @param idx The index of the nameserver to get the address of. + @param sa A location to receive the server's address. + @param len The number of bytes available at sa. + + @return the number of bytes written into sa on success. On failure, returns + -1 if idx is greater than the number of configured nameservers, or a + value greater than 'len' if len was not high enough. + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_get_nameserver_addr(struct evdns_base *base, int idx, + struct sockaddr *sa, ev_socklen_t len); + +/** + Retrieve the fd of the 'idx'th configured nameserver. + + @param base The evdns_base to examine. + @param idx The index of the nameserver to get the address of. + + @return the fd value. On failure, returns + -1 if idx is greater than the number of configured nameservers + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_get_nameserver_fd(struct evdns_base *base, int idx); + +#ifdef __cplusplus +} +#endif + +#endif /* !EVENT2_DNS_H_INCLUDED_ */ diff --git a/include/libevent/event2/dns_compat.h b/include/libevent/event2/dns_compat.h new file mode 100644 index 0000000..ea00266 --- /dev/null +++ b/include/libevent/event2/dns_compat.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_DNS_COMPAT_H_INCLUDED_ +#define EVENT2_DNS_COMPAT_H_INCLUDED_ + +/** @file event2/dns_compat.h + + @brief Potentially non-threadsafe versions of the functions in dns.h: provided + only for backwards compatibility. + + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include +#include + +/** + Initialize the asynchronous DNS library. + + This function initializes support for non-blocking name resolution by + calling evdns_resolv_conf_parse() on UNIX and + evdns_config_windows_nameservers() on Windows. + + @deprecated This function is deprecated because it always uses the current + event base, and is easily confused by multiple calls to event_init(), and + so is not safe for multithreaded use. Additionally, it allocates a global + structure that only one thread can use. The replacement is + evdns_base_new(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_shutdown() + */ +EVENT2_EXPORT_SYMBOL +int evdns_init(void); + +struct evdns_base; +/** + Return the global evdns_base created by event_init() and used by the other + deprecated functions. + + @deprecated This function is deprecated because use of the global + evdns_base is error-prone. + */ +EVENT2_EXPORT_SYMBOL +struct evdns_base *evdns_get_global_base(void); + +/** + Shut down the asynchronous DNS resolver and terminate all active requests. + + If the 'fail_requests' option is enabled, all active requests will return + an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, + the requests will be silently discarded. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_shutdown(). + + @param fail_requests if zero, active requests will be aborted; if non-zero, + active requests will return DNS_ERR_SHUTDOWN. + @see evdns_init() + */ +EVENT2_EXPORT_SYMBOL +void evdns_shutdown(int fail_requests); + +/** + Add a nameserver. + + The address should be an IPv4 address in network byte order. + The type of address is chosen so that it matches in_addr.s_addr. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_nameserver_add(). + + @param address an IP address in network byte order + @return 0 if successful, or -1 if an error occurred + @see evdns_nameserver_ip_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_nameserver_add(unsigned long int address); + +/** + Get the number of configured nameservers. + + This returns the number of configured nameservers (not necessarily the + number of running nameservers). This is useful for double-checking + whether our calls to the various nameserver configuration functions + have been successful. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_count_nameservers(). + + @return the number of configured nameservers + @see evdns_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_count_nameservers(void); + +/** + Remove all configured nameservers, and suspend all pending resolves. + + Resolves will not necessarily be re-attempted until evdns_resume() is called. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_clear_nameservers_and_suspend(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_resume() + */ +EVENT2_EXPORT_SYMBOL +int evdns_clear_nameservers_and_suspend(void); + +/** + Resume normal operation and continue any suspended resolve requests. + + Re-attempt resolves left in limbo after an earlier call to + evdns_clear_nameservers_and_suspend(). + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resume(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_clear_nameservers_and_suspend() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resume(void); + +/** + Add a nameserver. + + This wraps the evdns_nameserver_add() function by parsing a string as an IP + address and adds it as a nameserver. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_nameserver_ip_add(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_nameserver_ip_add(const char *ip_as_string); + +/** + Lookup an A record for a given name. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolve_ipv4(). + + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); + +/** + Lookup an AAAA record for a given name. + + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); + +struct in_addr; +struct in6_addr; + +/** + Lookup a PTR record for a given IP address. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolve_reverse(). + + @param in an IPv4 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); + +/** + Lookup a PTR record for a given IPv6 address. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolve_reverse_ipv6(). + + @param in an IPv6 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); + +/** + Set the value of a configuration option. + + The currently available configuration options are: + + ndots, timeout, max-timeouts, max-inflight, and attempts + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_set_option(). + + @param option the name of the configuration option to be modified + @param val the value to be set + @param flags Ignored. + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evdns_set_option(const char *option, const char *val, int flags); + +/** + Parse a resolv.conf file. + + The 'flags' parameter determines what information is parsed from the + resolv.conf file. See the man page for resolv.conf for the format of this + file. + + The following directives are not parsed from the file: sortlist, rotate, + no-check-names, inet6, debug. + + If this function encounters an error, the possible return values are: 1 = + failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of + memory, 5 = short read from file, 6 = no nameservers listed in the file + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolv_conf_parse(). + + @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| + DNS_OPTIONS_ALL + @param filename the path to the resolv.conf file + @return 0 if successful, or various positive error codes if an error + occurred (see above) + @see resolv.conf(3), evdns_config_windows_nameservers() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolv_conf_parse(int flags, const char *const filename); + +/** + Clear the list of search domains. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_search_clear(). + */ +EVENT2_EXPORT_SYMBOL +void evdns_search_clear(void); + +/** + Add a domain to the list of search domains + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_search_add(). + + @param domain the domain to be added to the search list + */ +EVENT2_EXPORT_SYMBOL +void evdns_search_add(const char *domain); + +/** + Set the 'ndots' parameter for searches. + + Sets the number of dots which, when found in a name, causes + the first query to be without any search domain. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_search_ndots_set(). + + @param ndots the new ndots parameter + */ +EVENT2_EXPORT_SYMBOL +void evdns_search_ndots_set(const int ndots); + +/** + As evdns_server_new_with_base. + + @deprecated This function is deprecated because it does not allow the + caller to specify which even_base it uses. The recommended + function is evdns_add_server_port_with_base(). + +*/ +EVENT2_EXPORT_SYMBOL +struct evdns_server_port * +evdns_add_server_port(evutil_socket_t socket, int flags, + evdns_request_callback_fn_type callback, void *user_data); + +#ifdef _WIN32 +EVENT2_EXPORT_SYMBOL +int evdns_config_windows_nameservers(void); +#define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/include/libevent/event2/dns_struct.h b/include/libevent/event2/dns_struct.h new file mode 100644 index 0000000..593a8a7 --- /dev/null +++ b/include/libevent/event2/dns_struct.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_DNS_STRUCT_H_INCLUDED_ +#define EVENT2_DNS_STRUCT_H_INCLUDED_ + +/** @file event2/dns_struct.h + + Data structures for dns. Using these structures may hurt forward + compatibility with later versions of Libevent: be careful! + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/* + * Structures used to implement a DNS server. + */ + +struct evdns_server_request { + int flags; + int nquestions; + struct evdns_server_question **questions; +}; +struct evdns_server_question { + int type; +#ifdef __cplusplus + int dns_question_class; +#else + /* You should refer to this field as "dns_question_class". The + * name "class" works in C for backward compatibility, and will be + * removed in a future version. (1.5 or later). */ + int class; +#define dns_question_class class +#endif + char name[1]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_DNS_STRUCT_H_INCLUDED_ */ + diff --git a/include/libevent/event2/event-config.h b/include/libevent/event2/event-config.h new file mode 100644 index 0000000..c76e42f --- /dev/null +++ b/include/libevent/event2/event-config.h @@ -0,0 +1,528 @@ +/* event-config.h + * + * This file was generated by cmake when the makefiles were generated. + * + * DO NOT EDIT THIS FILE. + * + * Do not rely on macros in this file existing in later versions. + */ +#ifndef EVENT2_EVENT_CONFIG_H_INCLUDED_ +#define EVENT2_EVENT_CONFIG_H_INCLUDED_ + +/* Numeric representation of the version */ +#define EVENT__NUMERIC_VERSION 0x02020001 +#define EVENT__PACKAGE_VERSION "2.2.0" + +#define EVENT__VERSION_MAJOR 2 +#define EVENT__VERSION_MINOR 2 +#define EVENT__VERSION_PATCH 0 + +/* Version number of package */ +#define EVENT__VERSION "2.2.0-alpha-dev" + +/* Name of package */ +#define EVENT__PACKAGE "libevent" + +/* Define to the address where bug reports for this package should be sent. */ +#define EVENT__PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define EVENT__PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define EVENT__PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define EVENT__PACKAGE_TARNAME "" + +/* Define if libevent should build without support for a debug mode */ +/* #undef EVENT__DISABLE_DEBUG_MODE */ + +/* Define if libevent should not allow replacing the mm functions */ +/* #undef EVENT__DISABLE_MM_REPLACEMENT */ + +/* Define if libevent should not be compiled with thread support */ +/* #undef EVENT__DISABLE_THREAD_SUPPORT */ + +/* Define to 1 if you have the `accept4' function. */ +#define EVENT__HAVE_ACCEPT4 1 + +/* Define to 1 if you have the `arc4random' function. */ +/* #undef EVENT__HAVE_ARC4RANDOM */ + +/* Define to 1 if you have the `arc4random_buf' function. */ +/* #undef EVENT__HAVE_ARC4RANDOM_BUF */ + +/* Define to 1 if you have the `arc4random_addrandom' function. */ +/* #undef EVENT__HAVE_ARC4RANDOM_ADDRANDOM */ + +/* Define if clock_gettime is available in libc */ +#define EVENT__DNS_USE_CPU_CLOCK_FOR_ID 1 + +/* Define is no secure id variant is available */ +/* #undef EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID */ +/* #undef EVENT__DNS_USE_FTIME_FOR_ID */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the `clock_gettime' function. */ +#define EVENT__HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `CTL_KERN'. */ +#define EVENT__HAVE_DECL_CTL_KERN 0 + +/* Define to 1 if you have the declaration of `KERN_ARND'. */ +#define EVENT__HAVE_DECL_KERN_ARND 0 + +/* Define to 1 if you have `getrandom' function. */ +#define EVENT__HAVE_GETRANDOM 1 + +/* Define if /dev/poll is available */ +/* #undef EVENT__HAVE_DEVPOLL */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_NETDB_H 1 + +/* Define to 1 if fd_mask type is defined */ +#define EVENT__HAVE_FD_MASK 1 + +/* Define to 1 if the header file defines TAILQ_FOREACH. */ +#define EVENT__HAVE_TAILQFOREACH 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_DLFCN_H 1 + +/* Define if your system supports the epoll system calls */ +#define EVENT__HAVE_EPOLL 1 + +/* Define to 1 if you have the `epoll_create1' function. */ +#define EVENT__HAVE_EPOLL_CREATE1 1 + +/* Define to 1 if you have the `epoll_pwait2' function. */ +#define EVENT__HAVE_EPOLL_PWAIT2 1 + +/* Define to 1 if you have the `epoll_ctl' function. */ +#define EVENT__HAVE_EPOLL_CTL 1 + +/* Define if your system supports the wepoll module */ +/* #undef EVENT__HAVE_WEPOLL */ + +/* Define to 1 if you have the `eventfd' function. */ +#define EVENT__HAVE_EVENTFD 1 + +/* Define if your system supports event ports */ +/* #undef EVENT__HAVE_EVENT_PORTS */ + +/* Define to 1 if you have the `fcntl' function. */ +#define EVENT__HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define EVENT__HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getegid' function. */ +#define EVENT__HAVE_GETEGID 1 + +/* Define to 1 if you have the `geteuid' function. */ +#define EVENT__HAVE_GETEUID 1 + +/* TODO: Check for different gethostname argument counts. CheckPrototypeDefinition.cmake can be used. */ +/* Define this if you have any gethostbyname_r() */ +#define EVENT__HAVE_GETHOSTBYNAME_R 1 + +/* Define this if gethostbyname_r takes 3 arguments */ +/* #undef EVENT__HAVE_GETHOSTBYNAME_R_3_ARG */ + +/* Define this if gethostbyname_r takes 5 arguments */ +/* #undef EVENT__HAVE_GETHOSTBYNAME_R_5_ARG */ + +/* Define this if gethostbyname_r takes 6 arguments */ +#define EVENT__HAVE_GETHOSTBYNAME_R_6_ARG 1 + +/* Define to 1 if you have the `getifaddrs' function. */ +#define EVENT__HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#define EVENT__HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `getprotobynumber' function. */ +#define EVENT__HAVE_GETPROTOBYNUMBER 1 + +/* Define to 1 if you have the `getservbyname' function. */ +#define EVENT__HAVE_GETSERVBYNAME 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define EVENT__HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the `inet_ntop' function. */ +#define EVENT__HAVE_INET_NTOP 1 + +/* Define to 1 if you have the `inet_pton' function. */ +#define EVENT__HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `issetugid' function. */ +/* #undef EVENT__HAVE_ISSETUGID */ + +/* Define to 1 if you have the `kqueue' function. */ +/* #undef EVENT__HAVE_KQUEUE */ + +/* Define if the system has zlib */ +#define EVENT__HAVE_LIBZ 1 + +/* Define to 1 if you have the `mach_absolute_time' function. */ +/* #undef EVENT__HAVE_MACH_ABSOLUTE_TIME */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_MACH_MACH_TIME_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mmap' function. */ +#define EVENT__HAVE_MMAP 1 + +/* Define to 1 if you have the `mmap64' function. */ +#define EVENT__HAVE_MMAP64 1 + +/* Define to 1 if you have the `nanosleep' function. */ +#define EVENT__HAVE_NANOSLEEP 1 + +/* Define to 1 if you have the `usleep' function. */ +#define EVENT__HAVE_USLEEP 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_NETINET_IN6_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_UN_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_AFUNIX_H */ + +/* Define if the system has openssl */ +#define EVENT__HAVE_OPENSSL 1 + +/* Define if the system has mbedtls */ +/* #undef EVENT__HAVE_MBEDTLS */ + +/* Define to 1 if you have the `pipe' function. */ +#define EVENT__HAVE_PIPE 1 + +/* Define to 1 if you have the `pipe2' function. */ +#define EVENT__HAVE_PIPE2 1 + +/* Define to 1 if you have the `poll' function. */ +#define EVENT__HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_POLL_H 1 + +/* Define to 1 if you have the `port_create' function. */ +/* #undef EVENT__HAVE_PORT_CREATE */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_PORT_H */ + +/* Define if we have pthreads on this system */ +#define EVENT__HAVE_PTHREADS 1 + +/* Define to 1 if you have the `pthread_mutexattr_setprotocol' function. */ +#define EVENT__HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL 1 + +/* Define to 1 if you have the `putenv' function. */ +#define EVENT__HAVE_PUTENV 1 + +/* Define to 1 if the system has the type `sa_family_t'. */ +#define EVENT__HAVE_SA_FAMILY_T 1 + +/* Define to 1 if you have the `select' function. */ +#define EVENT__HAVE_SELECT 1 + +/* Define to 1 if you have the `setenv' function. */ +#define EVENT__HAVE_SETENV 1 + +/* Define if F_SETFD is defined in */ +#define EVENT__HAVE_SETFD 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define EVENT__HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `sendfile' function. */ +#define EVENT__HAVE_SENDFILE 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define EVENT__HAVE_SIGACTION 1 + +/* Define to 1 if you have the `signal' function. */ +#define EVENT__HAVE_SIGNAL 1 + +/* Define to 1 if you have the `strsignal' function. */ +#define EVENT__HAVE_STRSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef EVENT__HAVE_STRLCPY */ + +/* Define to 1 if you have the `strsep' function. */ +#define EVENT__HAVE_STRSEP 1 + +/* Define to 1 if you have the `strtok_r' function. */ +#define EVENT__HAVE_STRTOK_R 1 + +/* Define to 1 if you have the `strtoll' function. */ +#define EVENT__HAVE_STRTOLL 1 + +/* Define to 1 if you have the `_gmtime64_s' function. */ +/* #undef EVENT__HAVE__GMTIME64_S */ + +/* Define to 1 if you have the `_gmtime64' function. */ +/* #undef EVENT__HAVE__GMTIME64 */ + +/* Define to 1 if the system has the type `struct addrinfo'. */ +#define EVENT__HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if the system has the type `struct in6_addr'. */ +#define EVENT__HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */ +#define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1 + +/* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */ +#define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1 + +/* Define to 1 if the system has the type `struct sockaddr_in6'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_IN6 1 + +/* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */ +/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN */ + +/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */ +/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + +/* Define to 1 if the system has the type `struct sockaddr_un'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_UN 1 + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1 + +/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */ +/* #undef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */ + +/* Define to 1 if the system has the type `struct linger'. */ +#define EVENT__HAVE_STRUCT_LINGER 1 + +/* Define to 1 if you have the `sysctl' function. */ +/* #undef EVENT__HAVE_SYSCTL */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_EPOLL_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_EVENTFD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_EVENT_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_QUEUE_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_SENDFILE_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_RANDOM_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_SYSCTL_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_TIMERFD_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_SIGNALFD_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_ERRNO_H 1 + +/* Define if TAILQ_FOREACH is defined in */ +#define EVENT__HAVE_TAILQFOREACH 1 + +/* Define if timeradd is defined in */ +#define EVENT__HAVE_TIMERADD 1 + +/* Define if timerclear is defined in */ +#define EVENT__HAVE_TIMERCLEAR 1 + +/* Define if timercmp is defined in */ +#define EVENT__HAVE_TIMERCMP 1 + + +/* Define to 1 if you have the `timerfd_create' function. */ +#define EVENT__HAVE_TIMERFD_CREATE 1 + +/* Define if timerisset is defined in */ +#define EVENT__HAVE_TIMERISSET 1 + +/* Define to 1 if the system has the type `uint8_t'. */ +#define EVENT__HAVE_UINT8_T 1 + +/* Define to 1 if the system has the type `uint16_t'. */ +#define EVENT__HAVE_UINT16_T 1 + +/* Define to 1 if the system has the type `uint32_t'. */ +#define EVENT__HAVE_UINT32_T 1 + +/* Define to 1 if the system has the type `uint64_t'. */ +#define EVENT__HAVE_UINT64_T 1 + +/* Define to 1 if the system has the type `uintptr_t'. */ +#define EVENT__HAVE_UINTPTR_T 1 + +/* Define to 1 if you have the `umask' function. */ +#define EVENT__HAVE_UMASK 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unsetenv' function. */ +#define EVENT__HAVE_UNSETENV 1 + +/* Define if kqueue works correctly with pipes */ +/* #undef EVENT__HAVE_WORKING_KQUEUE */ + +#ifdef __USE_UNUSED_DEFINITIONS__ +/* Define to necessary symbol if this constant uses a non-standard name on your system. */ +/* XXX: Hello, this isn't even used, nor is it defined anywhere... - Ellzey */ +#define EVENT__PTHREAD_CREATE_JOINABLE +#endif + +/* The size of `pthread_t', as computed by sizeof. */ +#define EVENT__SIZEOF_PTHREAD_T 8 + +/* The size of a `int', as computed by sizeof. */ +#define EVENT__SIZEOF_INT 4 + +/* The size of a `long', as computed by sizeof. */ +#define EVENT__SIZEOF_LONG 8 + +/* The size of a `long long', as computed by sizeof. */ +#define EVENT__SIZEOF_LONG_LONG 8 + +/* The size of `off_t', as computed by sizeof. */ +#define EVENT__SIZEOF_OFF_T 8 + +#define EVENT__SIZEOF_SSIZE_T 8 + + +/* The size of a `short', as computed by sizeof. */ +#define EVENT__SIZEOF_SHORT 2 + +/* The size of `size_t', as computed by sizeof. */ +#define EVENT__SIZEOF_SIZE_T 8 + +/* The size of `socklen_t', as computed by sizeof. */ +#define EVENT__SIZEOF_SOCKLEN_T 4 + +/* The size of 'void *', as computer by sizeof */ +#define EVENT__SIZEOF_VOID_P 8 + +/* The size of 'time_t', as computer by sizeof */ +#define EVENT__SIZEOF_TIME_T 8 + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* why not c++? + * + * and are we really expected to use EVENT__inline everywhere, + * shouldn't we just do: + * ifdef EVENT__inline + * define inline EVENT__inline + * + * - Ellzey + */ + +#define EVENT__inline inline +#endif + +#define EVENT__HAVE___func__ 1 +#define EVENT__HAVE___FUNCTION__ 1 + +/* Define to `unsigned' if does not define. */ +#define EVENT__size_t size_t + +/* Define to unsigned int if you dont have it */ +#define EVENT__socklen_t socklen_t + +/* Define to `int' if does not define. */ +#define EVENT__ssize_t ssize_t + +#endif /* \EVENT2_EVENT_CONFIG_H_INCLUDED_ */ diff --git a/include/libevent/event2/event.h b/include/libevent/event2/event.h new file mode 100644 index 0000000..4a9b5f3 --- /dev/null +++ b/include/libevent/event2/event.h @@ -0,0 +1,1704 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_EVENT_H_INCLUDED_ +#define EVENT2_EVENT_H_INCLUDED_ + +/** + @mainpage + + @section intro Introduction + + Libevent is an event notification library for developing scalable network + servers. The Libevent API provides a mechanism to execute a callback + function when a specific event occurs on a file descriptor or after a + timeout has been reached. Furthermore, Libevent also support callbacks due + to signals or regular timeouts. + + Libevent is meant to replace the event loop found in event driven network + servers. An application just needs to call event_base_dispatch() and then add or + remove events dynamically without having to change the event loop. + + + Currently, Libevent supports /dev/poll, kqueue(2), select(2), poll(2), + epoll(4), and evports. The internal event mechanism is completely + independent of the exposed event API, and a simple update of Libevent can + provide new functionality without having to redesign the applications. As a + result, Libevent allows for portable application development and provides + the most scalable event notification mechanism available on an operating + system. Libevent can also be used for multithreaded programs. Libevent + should compile on Linux, *BSD, Mac OS X, Solaris and, Windows. + + @section usage Standard usage + + Every program that uses Libevent must include the + header, and pass the -levent flag to the linker. (You can instead link + -levent_core if you only want the main event and buffered IO-based code, + and don't want to link any protocol code.) + + @section setup Library setup + + Before you call any other Libevent functions, you need to set up the + library. If you're going to use Libevent from multiple threads_ in a + multithreaded application, you need to initialize thread support -- + typically by using evthread_use_pthreads() or + evthread_use_windows_threads(). See for more + information. + + This is also the point where you can replace Libevent's memory + management functions with event_set_mem_functions, and enable debug mode + with event_enable_debug_mode(). + + @section base Creating an event base + + Next, you need to create an event_base structure, using event_base_new() + or event_base_new_with_config(). The event_base is responsible for + keeping track of which events are "pending" (that is to say, being + watched to see if they become active) and which events are "active". + Every event is associated with a single event_base. + + @section event Event notification + + For each file descriptor that you wish to monitor, you must create an + event structure with event_new(). (You may also declare an event + structure and call event_assign() to initialize the members of the + structure.) To enable notification, you add the structure to the list + of monitored events by calling event_add(). The event structure must + remain allocated as long as it is active, so it should generally be + allocated on the heap. + + @section loop Dispatching events. + + Finally, you call event_base_dispatch() to loop and dispatch events. + You can also use event_base_loop() for more fine-grained control. + + Currently, only one thread can be dispatching a given event_base at a + time. If you want to run events in multiple threads_ at once, you can + either have a single event_base whose events add work to a work queue, + or you can create multiple event_base objects. + + @section bufferevent I/O Buffers + + Libevent provides a buffered I/O abstraction on top of the regular event + callbacks. This abstraction is called a bufferevent. A bufferevent + provides input and output buffers that get filled and drained + automatically. The user of a buffered event no longer deals directly + with the I/O, but instead is reading from input and writing to output + buffers. + + Once initialized via bufferevent_socket_new(), the bufferevent structure + can be used repeatedly with bufferevent_enable() and + bufferevent_disable(). Instead of reading and writing directly to a + socket, you would call bufferevent_read() and bufferevent_write(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + See for more information. + + @section timers Timers + + Libevent can also be used to create timers that invoke a callback after a + certain amount of time has expired. The evtimer_new() macro returns + an event struct to use as a timer. To activate the timer, call + evtimer_add(). Timers can be deactivated by calling evtimer_del(). + (These macros are thin wrappers around event_new(), event_add(), + and event_del(); you can also use those instead.) + + @section evdns Asynchronous DNS resolution + + Libevent provides an asynchronous DNS resolver that should be used instead + of the standard DNS resolver functions. See the + functions for more detail. + + @section evhttp Event-driven HTTP servers + + Libevent provides a very simple event-driven HTTP server that can be + embedded in your program and used to service HTTP requests. + + To use this capability, you need to include the header in your + program. See that header for more information. + + @section evrpc A framework for RPC servers and clients + + Libevent provides a framework for creating RPC servers and clients. It + takes care of marshaling and unmarshaling all data structures. + + @section api API Reference + + To browse the complete documentation of the libevent API, click on any of + the following links. + + event2/event.h + The primary libevent header + + event2/thread.h + Functions for use by multithreaded programs + + event2/buffer.h and event2/bufferevent.h + Buffer management for network reading and writing + + event2/util.h + Utility functions for portable nonblocking network code + + event2/dns.h + Asynchronous DNS resolution + + event2/http.h + An embedded libevent-based HTTP server + + event2/rpc.h + A framework for creating RPC servers and clients + + event2/watch.h + "Prepare" and "check" watchers. + */ + +/** @file event2/event.h + + @brief Core functions for waiting for and receiving events, and using event bases. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +#include + +/* For int types. */ +#include + +/** + * Structure to hold information and state for a Libevent dispatch loop. + * + * The event_base lies at the center of Libevent; every application will + * have one. It keeps track of all pending and active events, and + * notifies your application of the active ones. + * + * This is an opaque structure; you can allocate one using + * event_base_new() or event_base_new_with_config(). + * + * @see event_base_new(), event_base_free(), event_base_loop(), + * event_base_new_with_config() + */ +struct event_base +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +/** + * Structure to represent a single event. + * + * An event can have some underlying condition it represents: a socket + * becoming readable or writeable (or both), or a signal becoming raised. + * (An event that represents no underlying condition is still useful: you + * can use one to implement a timer, or to communicate between threads_.) + * + * Generally, you can create events with event_new(), then make them + * pending with event_add(). As your event_base runs, it will run the + * callbacks of an events whose conditions are triggered. When you no + * longer want the event, free it with event_free(). + * + * In more depth: + * + * An event may be "pending" (one whose condition we are watching), + * "active" (one whose condition has triggered and whose callback is about + * to run), neither, or both. Events come into existence via + * event_assign() or event_new(), and are then neither active nor pending. + * + * To make an event pending, pass it to event_add(). When doing so, you + * can also set a timeout for the event. + * + * Events become active during an event_base_loop() call when either their + * condition has triggered, or when their timeout has elapsed. You can + * also activate an event manually using event_active(). The even_base + * loop will run the callbacks of active events; after it has done so, it + * marks them as no longer active. + * + * You can make an event non-pending by passing it to event_del(). This + * also makes the event non-active. + * + * Events can be "persistent" or "non-persistent". A non-persistent event + * becomes non-pending as soon as it is triggered: thus, it only runs at + * most once per call to event_add(). A persistent event remains pending + * even when it becomes active: you'll need to event_del() it manually in + * order to make it non-pending. When a persistent event with a timeout + * becomes active, its timeout is reset: this means you can use persistent + * events to implement periodic timeouts. + * + * This should be treated as an opaque structure; you should never read or + * write any of its fields directly. For backward compatibility with old + * code, it is defined in the event2/event_struct.h header; including this + * header may make your code incompatible with other versions of Libevent. + * + * @see event_new(), event_free(), event_assign(), event_get_assignment(), + * event_add(), event_del(), event_active(), event_pending(), + * event_get_fd(), event_get_base(), event_get_events(), + * event_get_callback(), event_get_callback_arg(), + * event_priority_set() + */ +struct event +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +/** + * Configuration for an event_base. + * + * There are many options that can be used to alter the behavior and + * implementation of an event_base. To avoid having to pass them all in a + * complex many-argument constructor, we provide an abstract data type + * where you set up configuration information before passing it to + * event_base_new_with_config(). + * + * @see event_config_new(), event_config_free(), event_base_new_with_config(), + * event_config_avoid_method(), event_config_require_features(), + * event_config_set_flag(), event_config_set_num_cpus_hint() + */ +struct event_config +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +/** + * Enable some relatively expensive debugging checks in Libevent that + * would normally be turned off. Generally, these checks cause code that + * would otherwise crash mysteriously to fail earlier with an assertion + * failure. Note that this method MUST be called before any events or + * event_bases have been created. + * + * Debug mode can currently catch the following errors: + * An event is re-assigned while it is added + * Any function is called on a non-assigned event + * + * Note that debugging mode uses memory to track every event that has been + * initialized (via event_assign, event_set, or event_new) but not yet + * released (via event_free or event_debug_unassign). If you want to use + * debug mode, and you find yourself running out of memory, you will need + * to use event_debug_unassign to explicitly stop tracking events that + * are no longer considered set-up. + * + * @see event_debug_unassign() + */ +EVENT2_EXPORT_SYMBOL +void event_enable_debug_mode(void); + +/** + * When debugging mode is enabled, informs Libevent that an event should no + * longer be considered as assigned. When debugging mode is not enabled, does + * nothing. + * + * This function must only be called on a non-added event. + * + * @see event_enable_debug_mode() + */ +EVENT2_EXPORT_SYMBOL +void event_debug_unassign(struct event *); + +/** + * Create and return a new event_base to use with the rest of Libevent. + * + * @return a new event_base on success, or NULL on failure. + * + * @see event_base_free(), event_base_new_with_config() + */ +EVENT2_EXPORT_SYMBOL +struct event_base *event_base_new(void); + +/** + Reinitialize the event base after a fork + + Some event mechanisms do not survive across fork. The event base needs + to be reinitialized with the event_reinit() function. + + @param base the event base that needs to be re-initialized + @return 0 if successful, or -1 if some events could not be re-added. + @see event_base_new() +*/ +EVENT2_EXPORT_SYMBOL +int event_reinit(struct event_base *base); + +/** + Event dispatching loop + + This loop will run the event base until either there are no more pending or + active, or until something calls event_base_loopbreak() or + event_base_loopexit(). + + @param base the event_base structure returned by event_base_new() or + event_base_new_with_config() + @return 0 if successful, -1 if an error occurred, or 1 if we exited because + no events were pending or active. + @see event_base_loop() + */ +EVENT2_EXPORT_SYMBOL +int event_base_dispatch(struct event_base *base); + +/** + Get the kernel event notification mechanism used by Libevent. + + @param eb the event_base structure returned by event_base_new() + @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) + */ +EVENT2_EXPORT_SYMBOL +const char *event_base_get_method(const struct event_base *eb); + +/** + Get the kernel signal handling mechanism used by Libevent. + + @param eb the event_base structure returned by event_base_new() + @return a string identifying the kernel signal handling mechanism, + which is "signal" for traditional UNIX signal handlers, + "kqueue_signal" for kqueue(2)-based method on *BSD and macOS, + and "signalfd_signal" for Linux-only signalfd(2)-based method. + */ +EVENT2_EXPORT_SYMBOL +const char *event_base_get_signal_method(const struct event_base *eb); + +/** + Gets all event notification mechanisms supported by Libevent. + + This functions returns the event mechanism in order preferred by + Libevent. Note that this list will include all backends that + Libevent has compiled-in support for, and will not necessarily check + your OS to see whether it has the required resources. + + @return an array with pointers to the names of support methods. + The end of the array is indicated by a NULL pointer. If an + error is encountered NULL is returned. +*/ +EVENT2_EXPORT_SYMBOL +const char **event_get_supported_methods(void); + +/** Query the current monotonic time from the timer for a struct + * event_base. + */ +EVENT2_EXPORT_SYMBOL +int event_gettime_monotonic(struct event_base *base, struct timeval *tp); + +/** + @name event type flag + + Flags to pass to event_base_get_num_events() to specify the kinds of events + we want to aggregate counts for +*/ +/**@{*/ +/** count the number of active events, which have been triggered.*/ +#define EVENT_BASE_COUNT_ACTIVE 1U +/** count the number of virtual events, which is used to represent an internal + * condition, other than a pending event, that keeps the loop from exiting. */ +#define EVENT_BASE_COUNT_VIRTUAL 2U +/** count the number of events which have been added to event base, including + * internal events. */ +#define EVENT_BASE_COUNT_ADDED 4U +/**@}*/ + +/** + Gets the number of events in event_base, as specified in the flags. + + Since event base has some internal events added to make some of its + functionalities work, EVENT_BASE_COUNT_ADDED may return more than the + number of events you added using event_add(). + + If you pass EVENT_BASE_COUNT_ACTIVE and EVENT_BASE_COUNT_ADDED together, an + active event will be counted twice. However, this might not be the case in + future libevent versions. The return value is an indication of the work + load, but the user shouldn't rely on the exact value as this may change in + the future. + + @param eb the event_base structure returned by event_base_new() + @param flags a bitwise combination of the kinds of events to aggregate + counts for + @return the number of events specified in the flags +*/ +EVENT2_EXPORT_SYMBOL +int event_base_get_num_events(struct event_base *eb, unsigned int flags); + +/** + Get the maximum number of events in a given event_base as specified in the + flags. + + @param eb the event_base structure returned by event_base_new() + @param flags a bitwise combination of the kinds of events to aggregate + counts for + @param clear option used to reset the maximum count. + @return the number of events specified in the flags + */ +EVENT2_EXPORT_SYMBOL +int event_base_get_max_events(struct event_base *eb, unsigned int flags, int clear); + +/** + Allocates a new event configuration object. + + The event configuration object can be used to change the behavior of + an event base. + + @return an event_config object that can be used to store configuration, or + NULL if an error is encountered. + @see event_base_new_with_config(), event_config_free(), event_config +*/ +EVENT2_EXPORT_SYMBOL +struct event_config *event_config_new(void); + +/** + Deallocates all memory associated with an event configuration object + + @param cfg the event configuration object to be freed. +*/ +EVENT2_EXPORT_SYMBOL +void event_config_free(struct event_config *cfg); + +/** + Enters an event method that should be avoided into the configuration. + + This can be used to avoid event mechanisms that do not support certain + file descriptor types, or for debugging to avoid certain event + mechanisms. An application can make use of multiple event bases to + accommodate incompatible file descriptor types. + + @param cfg the event configuration object + @param method the name of the event method to avoid + @return 0 on success, -1 on failure. +*/ +EVENT2_EXPORT_SYMBOL +int event_config_avoid_method(struct event_config *cfg, const char *method); + +/** + A flag used to describe which features an event_base (must) provide. + + Because of OS limitations, not every Libevent backend supports every + possible feature. You can use this type with + event_config_require_features() to tell Libevent to only proceed if your + event_base implements a given feature, and you can receive this type from + event_base_get_features() to see which features are available. +*/ +enum event_method_feature { + /** Require an event method that allows edge-triggered events with EV_ET. */ + EV_FEATURE_ET = 0x01, + /** Require an event method where having one event triggered among + * many is [approximately] an O(1) operation. This excludes (for + * example) select and poll, which are approximately O(N) for N + * equal to the total number of possible events. */ + EV_FEATURE_O1 = 0x02, + /** Require an event method that allows file descriptors as well as + * sockets. */ + EV_FEATURE_FDS = 0x04, + /** Require an event method that allows you to use EV_CLOSED to detect + * connection close without the necessity of reading all the pending data. + * + * Methods that do support EV_CLOSED may not be able to provide support on + * all kernel versions. + **/ + EV_FEATURE_EARLY_CLOSE = 0x08 +}; + +/** + A flag passed to event_config_set_flag(). + + These flags change the behavior of an allocated event_base. + + @see event_config_set_flag(), event_base_new_with_config(), + event_method_feature + */ +enum event_base_config_flag { + /** Do not allocate a lock for the event base, even if we have + locking set up. + + Setting this option will make it unsafe and nonfunctional to call + functions on the base concurrently from multiple threads_. + */ + EVENT_BASE_FLAG_NOLOCK = 0x01, + /** Do not check the EVENT_* environment variables when configuring + an event_base */ + EVENT_BASE_FLAG_IGNORE_ENV = 0x02, + /** Windows only: enable the IOCP dispatcher at startup + + If this flag is set then bufferevent_socket_new() and + evconn_listener_new() will use IOCP-backed implementations + instead of the usual select-based one on Windows. + + Note: it is experimental feature, and has some bugs. + */ + EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, + /** Instead of checking the current time every time the event loop is + ready to run timeout callbacks, check after each timeout callback. + */ + EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, + + /** If we are using the epoll backend, this flag says that it is + safe to use Libevent's internal change-list code to batch up + adds and deletes in order to try to do as few syscalls as + possible. Setting this flag can make your code run faster, but + it may trigger a Linux bug: it is not safe to use this flag + if you have any fds cloned by dup() or its variants. Doing so + will produce strange and hard-to-diagnose bugs. + + This flag can also be activated by setting the + EVENT_EPOLL_USE_CHANGELIST environment variable. + + This flag has no effect if you wind up using a backend other than + epoll. + */ + EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10, + + /** Ordinarily, Libevent implements its time and timeout code using + the fastest monotonic timer that we have. If this flag is set, + however, we use less efficient more precise timer, assuming one is + present. + */ + EVENT_BASE_FLAG_PRECISE_TIMER = 0x20, + + /** With EVENT_BASE_FLAG_PRECISE_TIMER, + epoll backend will use timerfd for more accurate timers, this will + allows to disable this. + + That said that this is something in between lack of + (CLOCK_MONOTONIC_COARSE) and enabled EVENT_BASE_FLAG_PRECISE_TIMER + (CLOCK_MONOTONIC + timerfd). + + This flag has no effect if you wind up using a backend other than + epoll and if you do not have EVENT_BASE_FLAG_PRECISE_TIMER enabled. + */ + EVENT_BASE_FLAG_EPOLL_DISALLOW_TIMERFD = 0x40, + + /** Do not use signalfd(2) to handle signals even if supported. + */ + EVENT_BASE_FLAG_DISALLOW_SIGNALFD = 0x80, +}; + +/** + Return a bitmask of the features implemented by an event base. This + will be a bitwise OR of one or more of the values of + event_method_feature + + @see event_method_feature + */ +EVENT2_EXPORT_SYMBOL +int event_base_get_features(const struct event_base *base); + +/** + Enters a required event method feature that the application demands. + + Note that not every feature or combination of features is supported + on every platform. Code that requests features should be prepared + to handle the case where event_base_new_with_config() returns NULL, as in: +
+     event_config_require_features(cfg, EV_FEATURE_ET);
+     base = event_base_new_with_config(cfg);
+     if (base == NULL) {
+       // We can't get edge-triggered behavior here.
+       event_config_require_features(cfg, 0);
+       base = event_base_new_with_config(cfg);
+     }
+   
+ + @param cfg the event configuration object + @param feature a bitfield of one or more event_method_feature values. + Replaces values from previous calls to this function. + @return 0 on success, -1 on failure. + @see event_method_feature, event_base_new_with_config() +*/ +EVENT2_EXPORT_SYMBOL +int event_config_require_features(struct event_config *cfg, int feature); + +/** + * Sets one or more flags to configure what parts of the eventual event_base + * will be initialized, and how they'll work. + * + * @see event_base_config_flags, event_base_new_with_config() + **/ +EVENT2_EXPORT_SYMBOL +int event_config_set_flag(struct event_config *cfg, int flag); + +/** + * Records a hint for the number of CPUs in the system. This is used for + * tuning thread pools, etc, for optimal performance. In Libevent 2.0, + * it is only on Windows, and only when IOCP is in use. + * + * @param cfg the event configuration object + * @param cpus the number of cpus + * @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus); + +/** + * Record an interval and/or a number of callbacks after which the event base + * should check for new events. By default, the event base will run as many + * events are as activated at the highest activated priority before checking + * for new events. If you configure it by setting max_interval, it will check + * the time after each callback, and not allow more than max_interval to + * elapse before checking for new events. If you configure it by setting + * max_callbacks to a value >= 0, it will run no more than max_callbacks + * callbacks before checking for new events. + * + * This option can decrease the latency of high-priority events, and + * avoid priority inversions where multiple low-priority events keep us from + * polling for high-priority events, but at the expense of slightly decreasing + * the throughput. Use it with caution! + * + * @param cfg The event_base configuration object. + * @param max_interval An interval after which Libevent should stop running + * callbacks and check for more events, or NULL if there should be + * no such interval. + * @param max_callbacks A number of callbacks after which Libevent should + * stop running callbacks and check for more events, or -1 if there + * should be no such limit. + * @param min_priority A priority below which max_interval and max_callbacks + * should not be enforced. If this is set to 0, they are enforced + * for events of every priority; if it's set to 1, they're enforced + * for events of priority 1 and above, and so on. + * @return 0 on success, -1 on failure. + **/ +EVENT2_EXPORT_SYMBOL +int event_config_set_max_dispatch_interval(struct event_config *cfg, + const struct timeval *max_interval, int max_callbacks, + int min_priority); + +/** + Initialize the event API. + + Use event_base_new_with_config() to initialize a new event base, taking + the specified configuration under consideration. The configuration object + can currently be used to avoid certain event notification mechanisms. + + @param cfg the event configuration object + @return an initialized event_base that can be used to registering events, + or NULL if no event base can be created with the requested event_config. + @see event_base_new(), event_base_free(), event_init(), event_assign() +*/ +EVENT2_EXPORT_SYMBOL +struct event_base *event_base_new_with_config(const struct event_config *cfg); + +/** + Deallocate all memory associated with an event_base, and free the base. + + Note that this function will not close any fds or free any memory passed + to event_new as the argument to callback. + + If there are any pending finalizer callbacks, this function will invoke + them. + + @param eb an event_base to be freed + */ +EVENT2_EXPORT_SYMBOL +void event_base_free(struct event_base *eb); + +/** + As event_base_free, but do not run finalizers. + */ +EVENT2_EXPORT_SYMBOL +void event_base_free_nofinalize(struct event_base *); + +/** @name Log severities + */ +/**@{*/ +#define EVENT_LOG_DEBUG 0 +#define EVENT_LOG_MSG 1 +#define EVENT_LOG_WARN 2 +#define EVENT_LOG_ERR 3 +/**@}*/ + +/* Obsolete names: these are deprecated, but older programs might use them. + * They violate the reserved-identifier namespace. */ +#define _EVENT_LOG_DEBUG EVENT_LOG_DEBUG +#define _EVENT_LOG_MSG EVENT_LOG_MSG +#define _EVENT_LOG_WARN EVENT_LOG_WARN +#define _EVENT_LOG_ERR EVENT_LOG_ERR + +/** + A callback function used to intercept Libevent's log messages. + + @see event_set_log_callback + */ +typedef void (*event_log_cb)(int severity, const char *msg); +/** + Redirect Libevent's log messages. + + @param cb a function taking two arguments: an integer severity between + EVENT_LOG_DEBUG and EVENT_LOG_ERR, and a string. If cb is NULL, + then the default log is used. + + NOTE: The function you provide *must not* call any other libevent + functionality. Doing so can produce undefined behavior. + */ +EVENT2_EXPORT_SYMBOL +void event_set_log_callback(event_log_cb cb); + +/** + A function to be called if Libevent encounters a fatal internal error. + + @see event_set_fatal_callback + */ +typedef void (*event_fatal_cb)(int err); + +/** + Override Libevent's behavior in the event of a fatal internal error. + + By default, Libevent will call exit(1) if a programming error makes it + impossible to continue correct operation. This function allows you to supply + another callback instead. Note that if the function is ever invoked, + something is wrong with your program, or with Libevent: any subsequent calls + to Libevent may result in undefined behavior. + + Libevent will (almost) always log an EVENT_LOG_ERR message before calling + this function; look at the last log message to see why Libevent has died. + */ +EVENT2_EXPORT_SYMBOL +void event_set_fatal_callback(event_fatal_cb cb); + +#define EVENT_DBG_ALL 0xffffffffu +#define EVENT_DBG_NONE 0 + +/** + Turn on debugging logs and have them sent to the default log handler. + + This is a global setting; if you are going to call it, you must call this + before any calls that create an event-base. You must call it before any + multithreaded use of Libevent. + + Debug logs are verbose. + + @param which Controls which debug messages are turned on. This option is + unused for now; for forward compatibility, you must pass in the constant + "EVENT_DBG_ALL" to turn debugging logs on, or "EVENT_DBG_NONE" to turn + debugging logs off. + */ +EVENT2_EXPORT_SYMBOL +void event_enable_debug_logging(ev_uint32_t which); + +/** + Associate a different event base with an event. + + The event to be associated must not be currently active or pending. + + @param eb the event base + @param ev the event + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int event_base_set(struct event_base *eb, struct event *ev); + +/** @name Loop flags + + These flags control the behavior of event_base_loop(). + */ +/**@{*/ +/** Block until we have an active event, then exit once all active events + * have had their callbacks run. */ +#define EVLOOP_ONCE 0x01 +/** Do not block: see which events are ready now, run the callbacks + * of the highest-priority ones, then exit. */ +#define EVLOOP_NONBLOCK 0x02 +/** Do not exit the loop because we have no pending events. Instead, keep + * running until event_base_loopexit() or event_base_loopbreak() makes us + * stop. + */ +#define EVLOOP_NO_EXIT_ON_EMPTY 0x04 +/**@}*/ + +/** + Wait for events to become active, and run their callbacks. + + This is a more flexible version of event_base_dispatch(). + + By default, this loop will run the event base until either there are no more + pending or active events, or until something calls event_base_loopbreak() or + event_base_loopexit(). You can override this behavior with the 'flags' + argument. + + @param eb the event_base structure returned by event_base_new() or + event_base_new_with_config() + @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK | + EVLOOP_NO_EXIT_ON_EMPTY + @return 0 if successful, -1 if an error occurred, or 1 if we exited because + no events were pending or active. + @see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE, + EVLOOP_NONBLOCK + */ +EVENT2_EXPORT_SYMBOL +int event_base_loop(struct event_base *eb, int flags); + +/** + Exit the event loop after the specified time + + The next event_base_loop() iteration after the given timer expires will + complete normally (handling all queued events) then exit without + blocking for events again. + + Subsequent invocations of event_base_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @param tv the amount of time after which the loop should terminate, + or NULL to exit after running all currently active events. + @return 0 if successful, or -1 if an error occurred + @see event_base_loopbreak() + */ +EVENT2_EXPORT_SYMBOL +int event_base_loopexit(struct event_base *eb, const struct timeval *tv); + +/** + Abort the active event_base_loop() immediately. + + event_base_loop() will abort the loop after the next event is completed; + event_base_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "break;" statement. + + Subsequent invocations of event_base_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @return 0 if successful, or -1 if an error occurred + @see event_base_loopexit() + */ +EVENT2_EXPORT_SYMBOL +int event_base_loopbreak(struct event_base *eb); + +/** + Tell the active event_base_loop() to scan for new events immediately. + + Calling this function makes the currently active event_base_loop() + start the loop over again (scanning for new events) after the current + event callback finishes. If the event loop is not running, this + function has no effect. + + event_base_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "continue;" statement. + + Subsequent invocations of event loop will proceed normally. + + @param eb the event_base structure returned by event_init() + @return 0 if successful, or -1 if an error occurred + @see event_base_loopbreak() + */ +EVENT2_EXPORT_SYMBOL +int event_base_loopcontinue(struct event_base *eb); + +/** + Checks if the event loop was told to exit by event_base_loopexit(). + + This function will return true for an event_base at every point after + event_loopexit() is called, until the event loop is next entered. + + @param eb the event_base structure returned by event_init() + @return true if event_base_loopexit() was called on this event base, + or 0 otherwise + @see event_base_loopexit() + @see event_base_got_break() + */ +EVENT2_EXPORT_SYMBOL +int event_base_got_exit(struct event_base *eb); + +/** + Checks if the event loop was told to abort immediately by event_base_loopbreak(). + + This function will return true for an event_base at every point after + event_base_loopbreak() is called, until the event loop is next entered. + + @param eb the event_base structure returned by event_init() + @return true if event_base_loopbreak() was called on this event base, + or 0 otherwise + @see event_base_loopbreak() + @see event_base_got_exit() + */ +EVENT2_EXPORT_SYMBOL +int event_base_got_break(struct event_base *eb); + +/** + * @name event flags + * + * Flags to pass to event_new(), event_assign(), event_pending(), and + * anything else with an argument of the form "short events" + */ +/**@{*/ +/** Indicates that a timeout has occurred. It's not necessary to pass + * this flag to event_for new()/event_assign() to get a timeout. */ +#define EV_TIMEOUT 0x01 +/** Wait for a socket or FD to become readable */ +#define EV_READ 0x02 +/** Wait for a socket or FD to become writeable */ +#define EV_WRITE 0x04 +/** Wait for a POSIX signal to be raised*/ +#define EV_SIGNAL 0x08 +/** + * Persistent event: won't get removed automatically when activated. + * + * When a persistent event with a timeout becomes activated, its timeout + * is reset to 0. + */ +#define EV_PERSIST 0x10 +/** Select edge-triggered behavior, if supported by the backend. */ +#define EV_ET 0x20 +/** + * If this option is provided, then event_del() will not block in one thread + * while waiting for the event callback to complete in another thread. + * + * To use this option safely, you may need to use event_finalize() or + * event_free_finalize() in order to safely tear down an event in a + * multithreaded application. See those functions for more information. + **/ +#define EV_FINALIZE 0x40 +/** + * Detects connection close events. You can use this to detect when a + * connection has been closed, without having to read all the pending data + * from a connection. + * + * Not all backends support EV_CLOSED. To detect or require it, use the + * feature flag EV_FEATURE_EARLY_CLOSE. + **/ +#define EV_CLOSED 0x80 +/**@}*/ + +/** + @name evtimer_* macros + + Aliases for working with one-shot timer events + If you need EV_PERSIST timer use event_*() functions. + */ +/**@{*/ +#define evtimer_assign(ev, b, cb, arg) \ + event_assign((ev), (b), -1, 0, (cb), (arg)) +#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg)) +#define evtimer_add(ev, tv) event_add((ev), (tv)) +#define evtimer_del(ev) event_del(ev) +#define evtimer_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv)) +#define evtimer_initialized(ev) event_initialized(ev) +/**@}*/ + +/** + @name evsignal_* macros + + Aliases for working with signal events + */ +/**@{*/ +#define evsignal_add(ev, tv) event_add((ev), (tv)) +#define evsignal_assign(ev, b, x, cb, arg) \ + event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg)) +#define evsignal_new(b, x, cb, arg) \ + event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) +#define evsignal_del(ev) event_del(ev) +#define evsignal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv)) +#define evsignal_initialized(ev) event_initialized(ev) +/**@}*/ + +/** + @name evuser_* macros + + Aliases for working with user-triggered events + If you need EV_PERSIST event use event_*() functions. + */ +/**@{*/ +#define evuser_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg)) +#define evuser_del(ev) event_del(ev) +#define evuser_pending(ev, tv) event_pending((ev), 0, (tv)) +#define evuser_initialized(ev) event_initialized(ev) +#define evuser_trigger(ev) event_active((ev), 0, 0) +/**@}*/ + +/** + A callback function for an event. + + It receives three arguments: + + @param fd An fd or signal + @param events One or more EV_* flags + @param arg A user-supplied argument. + + @see event_new() + */ +typedef void (*event_callback_fn)(evutil_socket_t, short, void *); + +/** + Return a value used to specify that the event itself must be used as the callback argument. + + The function event_new() takes a callback argument which is passed + to the event's callback function. To specify that the argument to be + passed to the callback function is the event that event_new() returns, + pass in the return value of event_self_cbarg() as the callback argument + for event_new(). + + For example: +
+      struct event *ev = event_new(base, sock, events, callback, %event_self_cbarg());
+  
+ + For consistency with event_new(), it is possible to pass the return value + of this function as the callback argument for event_assign() – this + achieves the same result as passing the event in directly. + + @return a value to be passed as the callback argument to event_new() or + event_assign(). + @see event_new(), event_assign() + */ +EVENT2_EXPORT_SYMBOL +void *event_self_cbarg(void); + +/** + Allocate and assign a new event structure, ready to be added. + + The function event_new() returns a new event that can be used in + future calls to event_add() and event_del(). The fd and events + arguments determine which conditions will trigger the event; the + callback and callback_arg arguments tell Libevent what to do when the + event becomes active. + + If events contains one of EV_READ, EV_WRITE, or EV_READ|EV_WRITE, then + fd is a file descriptor or socket that should get monitored for + readiness to read, readiness to write, or readiness for either operation + (respectively). If events contains EV_SIGNAL, then fd is a signal + number to wait for. If events contains none of those flags, then the + event can be triggered only by a timeout or by manual activation with + event_active(): In this case, fd must be -1. + + The EV_PERSIST flag can also be passed in the events argument: it makes + event_add() persistent until event_del() is called. + + The EV_ET flag is compatible with EV_READ and EV_WRITE, and supported + only by certain backends. It tells Libevent to use edge-triggered + events. + + The EV_TIMEOUT flag has no effect here. + + It is okay to have multiple events all listening on the same fds; but + they must either all be edge-triggered, or not be edge-triggered at all. + + When the event becomes active, the event loop will run the provided + callback function, with three arguments. The first will be the provided + fd value. The second will be a bitfield of the events that triggered: + EV_READ, EV_WRITE, or EV_SIGNAL. Here the EV_TIMEOUT flag indicates + that a timeout occurred, and EV_ET indicates that an edge-triggered + event occurred. The third event will be the callback_arg pointer that + you provide. + + @param base the event base to which the event should be attached. + @param fd the file descriptor or signal to be monitored, or -1. + @param events desired events to monitor: bitfield of EV_READ, EV_WRITE, + EV_SIGNAL, EV_PERSIST, EV_ET. + @param callback callback function to be invoked when the event occurs + @param callback_arg an argument to be passed to the callback function + + @return a newly allocated struct event that must later be freed with + event_free() or NULL if an error occurred. + @see event_free(), event_add(), event_del(), event_assign() + */ +EVENT2_EXPORT_SYMBOL +struct event *event_new(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg); + + +/** + Prepare a new, already-allocated event structure to be added. + + The function event_assign() prepares the event structure ev to be used + in future calls to event_add() and event_del(). Unlike event_new(), it + doesn't allocate memory itself: it requires that you have already + allocated a struct event, probably on the heap. Doing this will + typically make your code depend on the size of the event structure, and + thereby create incompatibility with future versions of Libevent. + + The easiest way to avoid this problem is just to use event_new() and + event_free() instead. + + A slightly harder way to future-proof your code is to use + event_get_struct_event_size() to determine the required size of an event + at runtime. + + Note that it is NOT safe to call this function on an event that is + active or pending. Doing so WILL corrupt internal data structures in + Libevent, and lead to strange, hard-to-diagnose bugs. You _can_ use + event_assign to change an existing event, but only if it is not active + or pending! + + The arguments for this function, and the behavior of the events that it + makes, are as for event_new(). + + @param ev an event struct to be modified + @param base the event base to which ev should be attached. + @param fd the file descriptor to be monitored + @param events desired events to monitor; can be EV_READ and/or EV_WRITE + @param callback callback function to be invoked when the event occurs + @param callback_arg an argument to be passed to the callback function + + @return 0 if success, or -1 on invalid arguments. + + @see event_new(), event_add(), event_del(), event_base_once(), + event_get_struct_event_size() + */ +EVENT2_EXPORT_SYMBOL +int event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg); + +/** + Deallocate a struct event * returned by event_new(). + + If the event is pending or active, this function makes it non-pending + and non-active first. + */ +EVENT2_EXPORT_SYMBOL +void event_free(struct event *); + +/** + * Callback type for event_finalize and event_free_finalize(). + **/ +typedef void (*event_finalize_callback_fn)(struct event *, void *); +/** + @name Finalization functions + + These functions are used to safely tear down an event in a multithreaded + application. If you construct your events with EV_FINALIZE to avoid + deadlocks, you will need a way to remove an event in the certainty that + it will definitely not be running its callback when you deallocate it + and its callback argument. + + To do this, call one of event_finalize() or event_free_finalize with + 0 for its first argument, the event to tear down as its second argument, + and a callback function as its third argument. The callback will be + invoked as part of the event loop, with the event's priority. + + After you call a finalizer function, event_add() and event_active() will + no longer work on the event, and event_del() will produce a no-op. You + must not try to change the event's fields with event_assign() or + event_set() while the finalize callback is in progress. Once the + callback has been invoked, you should treat the event structure as + containing uninitialized memory. + + The event_free_finalize() function frees the event after it's finalized; + event_finalize() does not. + + A finalizer callback must not make events pending or active. It must not + add events, activate events, or attempt to "resuscitate" the event being + finalized in any way. + + @return 0 on success, -1 on failure. + */ +/**@{*/ +EVENT2_EXPORT_SYMBOL +int event_finalize(unsigned, struct event *, event_finalize_callback_fn); +EVENT2_EXPORT_SYMBOL +int event_free_finalize(unsigned, struct event *, event_finalize_callback_fn); +/**@}*/ + +/** + Schedule a one-time event + + The function event_base_once() is similar to event_new(). However, it + schedules a callback to be called exactly once, and does not require the + caller to prepare an event structure. + + Note that in Libevent 2.0 and earlier, if the event is never triggered, the + internal memory used to hold it will never be freed. In Libevent 2.1, + the internal memory will get freed by event_base_free() if the event + is never triggered. The 'arg' value, however, will not get freed in either + case--you'll need to free that on your own if you want it to go away. + + @param base an event_base + @param fd a file descriptor to monitor, or -1 for no fd. + @param events event(s) to monitor; can be any of EV_READ | + EV_WRITE, or EV_TIMEOUT + @param callback callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + @param timeout the maximum amount of time to wait for the event. NULL + makes an EV_READ/EV_WRITE event make forever; NULL makes an + EV_TIMEOUT event success immediately. + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int event_base_once(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *arg, const struct timeval *timeout); + +/** + Add an event to the set of pending events. + + The function event_add() schedules the execution of the event 'ev' when the + condition specified by event_assign() or event_new() occurs, or when the time + specified in timeout has elapsed. If a timeout is NULL, no timeout + occurs and the function will only be + called if a matching event occurs. The event in the + ev argument must be already initialized by event_assign() or event_new() + and may not be used + in calls to event_assign() until it is no longer pending. + + If the event in the ev argument already has a scheduled timeout, calling + event_add() replaces the old timeout with the new one if tv is non-NULL. + + @param ev an event struct initialized via event_assign() or event_new() + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_del(), event_assign(), event_new() + */ +EVENT2_EXPORT_SYMBOL +int event_add(struct event *ev, const struct timeval *timeout); + +/** + Remove a timer from a pending event without removing the event itself. + + If the event has a scheduled timeout, this function unschedules it but + leaves the event otherwise pending. + + @param ev an event struct initialized via event_assign() or event_new() + @return 0 on success, or -1 if an error occurred. +*/ +EVENT2_EXPORT_SYMBOL +int event_remove_timer(struct event *ev); + +/** + Remove an event from the set of monitored events. + + The function event_del() will cancel the event in the argument ev. If the + event has already executed or has never been added the call will have no + effect. + + @param ev an event struct to be removed from the working set + @return 0 if successful, or -1 if an error occurred + @see event_add() + */ +EVENT2_EXPORT_SYMBOL +int event_del(struct event *ev); + +/** + As event_del(), but never blocks while the event's callback is running + in another thread, even if the event was constructed without the + EV_FINALIZE flag. + */ +EVENT2_EXPORT_SYMBOL +int event_del_noblock(struct event *ev); +/** + As event_del(), but always blocks while the event's callback is running + in another thread, even if the event was constructed with the + EV_FINALIZE flag. + */ +EVENT2_EXPORT_SYMBOL +int event_del_block(struct event *ev); + +/** + Make an event active. + + You can use this function on a pending or a non-pending event to make it + active, so that its callback will be run by event_base_dispatch() or + event_base_loop(). + + One common use in multithreaded programs is to wake the thread running + event_base_loop() from another thread. + + @param ev an event to make active. + @param res a set of flags to pass to the event's callback. + @param ncalls an obsolete argument: this is ignored. + **/ +EVENT2_EXPORT_SYMBOL +void event_active(struct event *ev, int res, short ncalls); + +/** + Checks if a specific event is pending or scheduled. + + @param ev an event struct previously passed to event_add() + @param events the requested event type; any of EV_TIMEOUT|EV_READ| + EV_WRITE|EV_SIGNAL + @param tv if this field is not NULL, and the event has a timeout, + this field is set to hold the time at which the timeout will + expire. + + @return true if the event is pending on any of the events in 'what', (that + is to say, it has been added), or 0 if the event is not added. + */ +EVENT2_EXPORT_SYMBOL +int event_pending(const struct event *ev, short events, struct timeval *tv); + +/** + If called from within the callback for an event, returns that event. + + The behavior of this function is not defined when called from outside the + callback function for an event. + */ +EVENT2_EXPORT_SYMBOL +struct event *event_base_get_running_event(struct event_base *base); + +/** + Test if an event structure might be initialized. + + The event_initialized() function can be used to check if an event has been + initialized. + + Warning: This function is only useful for distinguishing a zeroed-out + piece of memory from an initialized event, it can easily be confused by + uninitialized memory. Thus, it should ONLY be used to distinguish an + initialized event from zero. + + @param ev an event structure to be tested + @return 1 if the structure might be initialized, or 0 if it has not been + initialized + */ +EVENT2_EXPORT_SYMBOL +int event_initialized(const struct event *ev); + +/** + Get the signal number assigned to a signal event +*/ +#define event_get_signal(ev) ((int)event_get_fd(ev)) + +/** + Get the socket or signal assigned to an event, or -1 if the event has + no socket. +*/ +EVENT2_EXPORT_SYMBOL +evutil_socket_t event_get_fd(const struct event *ev); + +/** + Get the event_base associated with an event. +*/ +EVENT2_EXPORT_SYMBOL +struct event_base *event_get_base(const struct event *ev); + +/** + Return the events (EV_READ, EV_WRITE, etc) assigned to an event. +*/ +EVENT2_EXPORT_SYMBOL +short event_get_events(const struct event *ev); + +/** + Return the callback assigned to an event. +*/ +EVENT2_EXPORT_SYMBOL +event_callback_fn event_get_callback(const struct event *ev); + +/** + Return the callback argument assigned to an event. +*/ +EVENT2_EXPORT_SYMBOL +void *event_get_callback_arg(const struct event *ev); + +/** + Return the priority of an event. + @see event_priority_init(), event_get_priority() +*/ +EVENT2_EXPORT_SYMBOL +int event_get_priority(const struct event *ev); + +/** + Extract _all_ of arguments given to construct a given event. The + event_base is copied into *base_out, the fd is copied into *fd_out, and so + on. + + If any of the "_out" arguments is NULL, it will be ignored. + */ +EVENT2_EXPORT_SYMBOL +void event_get_assignment(const struct event *event, + struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, + event_callback_fn *callback_out, void **arg_out); + +/** + Return the size of struct event that the Libevent library was compiled + with. + + This will be NO GREATER than sizeof(struct event) if you're running with + the same version of Libevent that your application was built with, but + otherwise might not. + + Note that it might be SMALLER than sizeof(struct event) if some future + version of Libevent adds extra padding to the end of struct event. + We might do this to help ensure ABI-compatibility between different + versions of Libevent. + */ +EVENT2_EXPORT_SYMBOL +size_t event_get_struct_event_size(void); + +/** + Get the Libevent version. + + Note that this will give you the version of the library that you're + currently linked against, not the version of the headers that you've + compiled against. + + @return a string containing the version number of Libevent +*/ +EVENT2_EXPORT_SYMBOL +const char *event_get_version(void); + +/** + Return a numeric representation of Libevent's version. + + Note that this will give you the version of the library that you're + currently linked against, not the version of the headers you've used to + compile. + + The format uses one byte each for the major, minor, and patchlevel parts of + the version number. The low-order byte is unused. For example, version + 2.0.1-alpha has a numeric representation of 0x02000100 +*/ +EVENT2_EXPORT_SYMBOL +ev_uint32_t event_get_version_number(void); + +/** As event_get_version, but gives the version of Libevent's headers. */ +#define LIBEVENT_VERSION EVENT__VERSION +/** As event_get_version_number, but gives the version number of Libevent's + * headers. */ +#define LIBEVENT_VERSION_NUMBER EVENT__NUMERIC_VERSION + +/** Largest number of priorities that Libevent can support. */ +#define EVENT_MAX_PRIORITIES 256 +/** + Set the number of different event priorities + + By default Libevent schedules all active events with the same priority. + However, some time it is desirable to process some events with a higher + priority than others. For that reason, Libevent supports strict priority + queues. Active events with a lower priority are always processed before + events with a higher priority. + + The number of different priorities can be set initially with the + event_base_priority_init() function. This function should be called + before the first call to event_base_dispatch(). The + event_priority_set() function can be used to assign a priority to an + event. By default, Libevent assigns the middle priority to all events + unless their priority is explicitly set. + + Note that urgent-priority events can starve less-urgent events: after + running all urgent-priority callbacks, Libevent checks for more urgent + events again, before running less-urgent events. Less-urgent events + will not have their callbacks run until there are no events more urgent + than them that want to be active. + + @param eb the event_base structure returned by event_base_new() + @param npriorities the maximum number of priorities + @return 0 if successful, or -1 if an error occurred + @see event_priority_set() + */ +EVENT2_EXPORT_SYMBOL +int event_base_priority_init(struct event_base *eb, int npriorities); + +/** + Get the number of different event priorities. + + @param eb the event_base structure returned by event_base_new() + @return Number of different event priorities + @see event_base_priority_init() +*/ +EVENT2_EXPORT_SYMBOL +int event_base_get_npriorities(struct event_base *eb); + +/** + Assign a priority to an event. + + @param ev an event struct + @param priority the new priority to be assigned + @return 0 if successful, or -1 if an error occurred + @see event_priority_init(), event_get_priority() + */ +EVENT2_EXPORT_SYMBOL +int event_priority_set(struct event *ev, int priority); + +/** + Prepare an event_base to use a large number of timeouts with the same + duration. + + Libevent's default scheduling algorithm is optimized for having a large + number of timeouts with their durations more or less randomly + distributed. But if you have a large number of timeouts that all have + the same duration (for example, if you have a large number of + connections that all have a 10-second timeout), then you can improve + Libevent's performance by telling Libevent about it. + + To do this, call this function with the common duration. It will return a + pointer to a different, opaque timeout value. (Don't depend on its actual + contents!) When you use this timeout value in event_add(), Libevent will + schedule the event more efficiently. + + (This optimization probably will not be worthwhile until you have thousands + or tens of thousands of events with the same timeout.) + */ +EVENT2_EXPORT_SYMBOL +const struct timeval *event_base_init_common_timeout(struct event_base *base, + const struct timeval *duration); + +#if !defined(EVENT__DISABLE_MM_REPLACEMENT) || defined(EVENT_IN_DOXYGEN_) +/** + Override the functions that Libevent uses for memory management. + + Usually, Libevent uses the standard libc functions malloc, realloc, and + free to allocate memory. Passing replacements for those functions to + event_set_mem_functions() overrides this behavior. + + Note that all memory returned from Libevent will be allocated by the + replacement functions rather than by malloc() and realloc(). Thus, if you + have replaced those functions, it will not be appropriate to free() memory + that you get from Libevent. Instead, you must use the free_fn replacement + that you provided. + + Note also that if you are going to call this function, you should do so + before any call to any Libevent function that does allocation. + Otherwise, those functions will allocate their memory using malloc(), but + then later free it using your provided free_fn. + + @param malloc_fn A replacement for malloc. + @param realloc_fn A replacement for realloc + @param free_fn A replacement for free. + **/ +EVENT2_EXPORT_SYMBOL +void event_set_mem_functions( + void *(*malloc_fn)(size_t sz), + void *(*realloc_fn)(void *ptr, size_t sz), + void (*free_fn)(void *ptr)); +/** This definition is present if Libevent was built with support for + event_set_mem_functions() */ +#define EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED +#endif + +/** + Writes a human-readable description of all inserted and/or active + events to a provided stdio stream. + + This is intended for debugging; its format is not guaranteed to be the same + between libevent versions. + + @param base An event_base on which to scan the events. + @param output A stdio file to write on. + */ +EVENT2_EXPORT_SYMBOL +void event_base_dump_events(struct event_base *base, FILE *output); + + +/** + Activates all pending events for the given fd and event mask. + + This function activates pending events only. Events which have not been + added will not become active. + + @param base the event_base on which to activate the events. + @param fd An fd to active events on. + @param events One or more of EV_{READ,WRITE,TIMEOUT}. + */ +EVENT2_EXPORT_SYMBOL +void event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events); + +/** + Activates all pending signals with a given signal number + + This function activates pending events only. Events which have not been + added will not become active. + + @param base the event_base on which to activate the events. + @param sig The signal to active events on. + */ +EVENT2_EXPORT_SYMBOL +void event_base_active_by_signal(struct event_base *base, int sig); + +/** + * Callback for iterating events in an event base via event_base_foreach_event + */ +typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *); + +/** + Iterate over all added or active events events in an event loop, and invoke + a given callback on each one. + + The callback must not call any function that modifies the event base, that + modifies any event in the event base, or that adds or removes any event to + the event base. Doing so is unsupported and will lead to undefined + behavior -- likely, to crashes. + + event_base_foreach_event() holds a lock on the event_base() for the whole + time it's running: slow callbacks are not advisable. + + Note that Libevent adds some events of its own to make pieces of its + functionality work. You must not assume that the only events you'll + encounter will be the ones you added yourself. + + The callback function must return 0 to continue iteration, or some other + integer to stop iterating. + + @param base An event_base on which to scan the events. + @param fn A callback function to receive the events. + @param arg An argument passed to the callback function. + @return 0 if we iterated over every event, or the value returned by the + callback function if the loop exited early. +*/ +EVENT2_EXPORT_SYMBOL +int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb fn, void *arg); + + +/** Sets 'tv' to the current time (as returned by gettimeofday()), + looking at the cached value in 'base' if possible, and calling + gettimeofday() or clock_gettime() as appropriate if there is no + cached time. + + Generally, this value will only be cached while actually + processing event callbacks, and may be very inaccurate if your + callbacks take a long time to execute. + + Returns 0 on success, negative on failure. + */ +EVENT2_EXPORT_SYMBOL +int event_base_gettimeofday_cached(struct event_base *base, + struct timeval *tv); + +/** Update cached_tv in the 'base' to the current time + * + * You can use this function is useful for selectively increasing + * the accuracy of the cached time value in 'base' during callbacks + * that take a long time to execute. + * + * This function has no effect if the base is currently not in its + * event loop, or if timeval caching is disabled via + * EVENT_BASE_FLAG_NO_CACHE_TIME. + * + * @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int event_base_update_cache_time(struct event_base *base); + +/** Release up all globally-allocated resources allocated by Libevent. + + This function does not free developer-controlled resources like + event_bases, events, bufferevents, listeners, and so on. It only releases + resources like global locks that there is no other way to free. + + It is not actually necessary to call this function before exit: every + resource that it frees would be released anyway on exit. It mainly exists + so that resource-leak debugging tools don't see Libevent as holding + resources at exit. + + You should only call this function when no other Libevent functions will + be invoked -- e.g., when cleanly exiting a program. + */ +EVENT2_EXPORT_SYMBOL +void libevent_global_shutdown(void); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_H_INCLUDED_ */ diff --git a/include/libevent/event2/event_compat.h b/include/libevent/event2/event_compat.h new file mode 100644 index 0000000..fecdb3b --- /dev/null +++ b/include/libevent/event2/event_compat.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_EVENT_COMPAT_H_INCLUDED_ +#define EVENT2_EVENT_COMPAT_H_INCLUDED_ + +/** @file event2/event_compat.h + + @brief Potentially non-threadsafe versions of the functions in event.h: provided + only for backwards compatibility. + + In the oldest versions of Libevent, event_base was not a first-class + structure. Instead, there was a single event base that every function + manipulated. Later, when separate event bases were added, the old functions + that didn't take an event_base argument needed to work by manipulating the + "current" event base. This could lead to thread-safety issues, and obscure, + hard-to-diagnose bugs. + + @deprecated All functions in this file are by definition deprecated. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** + Initialize the event API. + + The event API needs to be initialized with event_init() before it can be + used. Sets the global current base that gets used for events that have no + base associated with them. + + @deprecated This function is deprecated because it replaces the "current" + event_base, and is totally unsafe for multithreaded use. The replacement + is event_base_new(). + + @see event_base_set(), event_base_new() + */ +EVENT2_EXPORT_SYMBOL +struct event_base *event_init(void); + +/** + Loop to process events. + + Like event_base_dispatch(), but uses the "current" base. + + @deprecated This function is deprecated because it is easily confused by + multiple calls to event_init(), and because it is not safe for + multithreaded use. The replacement is event_base_dispatch(). + + @see event_base_dispatch(), event_init() + */ +EVENT2_EXPORT_SYMBOL +int event_dispatch(void); + +/** + Handle events. + + This function behaves like event_base_loop(), but uses the "current" base + + @deprecated This function is deprecated because it uses the event base from + the last call to event_init, and is therefore not safe for multithreaded + use. The replacement is event_base_loop(). + + @see event_base_loop(), event_init() +*/ +EVENT2_EXPORT_SYMBOL +int event_loop(int); + + +/** + Exit the event loop after the specified time. + + This function behaves like event_base_loopexit(), except that it uses the + "current" base. + + @deprecated This function is deprecated because it uses the event base from + the last call to event_init, and is therefore not safe for multithreaded + use. The replacement is event_base_loopexit(). + + @see event_init, event_base_loopexit() + */ +EVENT2_EXPORT_SYMBOL +int event_loopexit(const struct timeval *); + + +/** + Abort the active event_loop() immediately. + + This function behaves like event_base_loopbreakt(), except that it uses the + "current" base. + + @deprecated This function is deprecated because it uses the event base from + the last call to event_init, and is therefore not safe for multithreaded + use. The replacement is event_base_loopbreak(). + + @see event_base_loopbreak(), event_init() + */ +EVENT2_EXPORT_SYMBOL +int event_loopbreak(void); + +/** + Schedule a one-time event to occur. + + @deprecated This function is obsolete, and has been replaced by + event_base_once(). Its use is deprecated because it relies on the + "current" base configured by event_init(). + + @see event_base_once() + */ +EVENT2_EXPORT_SYMBOL +int event_once(evutil_socket_t , short, + void (*)(evutil_socket_t, short, void *), void *, const struct timeval *); + + +/** + Get the kernel event notification mechanism used by Libevent. + + @deprecated This function is obsolete, and has been replaced by + event_base_get_method(). Its use is deprecated because it relies on the + "current" base configured by event_init(). + + @see event_base_get_method() + */ +EVENT2_EXPORT_SYMBOL +const char *event_get_method(void); + + +/** + Set the number of different event priorities. + + @deprecated This function is deprecated because it is easily confused by + multiple calls to event_init(), and because it is not safe for + multithreaded use. The replacement is event_base_priority_init(). + + @see event_base_priority_init() + */ +EVENT2_EXPORT_SYMBOL +int event_priority_init(int); + +/** + Prepare an event structure to be added. + + @deprecated event_set() is not recommended for new code, because it requires + a subsequent call to event_base_set() to be safe under most circumstances. + Use event_assign() or event_new() instead. + */ +EVENT2_EXPORT_SYMBOL +void event_set(struct event *, evutil_socket_t, short, void (*)(evutil_socket_t, short, void *), void *); + +#define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) +#define evsignal_set(ev, x, cb, arg) \ + event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) + + +/** + @name timeout_* macros + + @deprecated These macros are deprecated because their naming is inconsistent + with the rest of Libevent. Use the evtimer_* macros instead. + @{ + */ +#define timeout_add(ev, tv) event_add((ev), (tv)) +#define timeout_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) +#define timeout_del(ev) event_del(ev) +#define timeout_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv)) +#define timeout_initialized(ev) event_initialized(ev) +/**@}*/ + +/** + @name signal_* macros + + @deprecated These macros are deprecated because their naming is inconsistent + with the rest of Libevent. Use the evsignal_* macros instead. + @{ + */ +#define signal_add(ev, tv) event_add((ev), (tv)) +#define signal_set(ev, x, cb, arg) \ + event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) +#define signal_del(ev) event_del(ev) +#define signal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv)) +#define signal_initialized(ev) event_initialized(ev) +/**@}*/ + +#ifndef EVENT_FD +/* These macros are obsolete; use event_get_fd and event_get_signal instead. */ +#define EVENT_FD(ev) ((int)event_get_fd(ev)) +#define EVENT_SIGNAL(ev) event_get_signal(ev) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/include/libevent/event2/event_struct.h b/include/libevent/event2/event_struct.h new file mode 100644 index 0000000..34672e8 --- /dev/null +++ b/include/libevent/event2/event_struct.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_EVENT_STRUCT_H_INCLUDED_ +#define EVENT2_EVENT_STRUCT_H_INCLUDED_ + +/** @file event2/event_struct.h + + Structures used by event.h. Using these structures directly WILL harm + forward compatibility: be careful. + + No field declared in this file should be used directly in user code. Except + for historical reasons, these fields would not be exposed at all. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/* For evkeyvalq */ +#include + +#define EVLIST_TIMEOUT 0x01 +#define EVLIST_INSERTED 0x02 +#define EVLIST_SIGNAL 0x04 +#define EVLIST_ACTIVE 0x08 +#define EVLIST_INTERNAL 0x10 +#define EVLIST_ACTIVE_LATER 0x20 +#define EVLIST_FINALIZING 0x40 +#define EVLIST_INIT 0x80 + +#define EVLIST_ALL 0xff + +/* Fix so that people don't have to run with */ +#ifndef TAILQ_ENTRY +#define EVENT_DEFINED_TQENTRY_ +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ + +#ifndef TAILQ_HEAD +#define EVENT_DEFINED_TQHEAD_ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; \ + struct type **tqh_last; \ +} +#endif + +/* Fix so that people don't have to run with */ +#ifndef LIST_ENTRY +#define EVENT_DEFINED_LISTENTRY_ +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} +#endif /* !LIST_ENTRY */ + +#ifndef LIST_HEAD +#define EVENT_DEFINED_LISTHEAD_ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ + } +#endif /* !LIST_HEAD */ + +struct event; + +struct event_callback { + TAILQ_ENTRY(event_callback) evcb_active_next; + short evcb_flags; + ev_uint8_t evcb_pri; /* smaller numbers are higher priority */ + ev_uint8_t evcb_closure; + /* allows us to adopt for different types of events */ + union { + void (*evcb_callback)(evutil_socket_t, short, void *); + void (*evcb_selfcb)(struct event_callback *, void *); + void (*evcb_evfinalize)(struct event *, void *); + void (*evcb_cbfinalize)(struct event_callback *, void *); + } evcb_cb_union; + void *evcb_arg; +}; + +struct event_base; +struct event { + struct event_callback ev_evcallback; + + /* for managing timeouts */ + union { + TAILQ_ENTRY(event) ev_next_with_common_timeout; + size_t min_heap_idx; + } ev_timeout_pos; + evutil_socket_t ev_fd; + + short ev_events; + short ev_res; /* result passed to event callback */ + + struct event_base *ev_base; + + union { + /* used for io events */ + struct { + LIST_ENTRY (event) ev_io_next; + struct timeval ev_timeout; + } ev_io; + + /* used by signal events */ + struct { + LIST_ENTRY (event) ev_signal_next; + short ev_ncalls; + /* Allows deletes in callback */ + short *ev_pncalls; + } ev_signal; + } ev_; + + + struct timeval ev_timeout; +}; + +TAILQ_HEAD (event_list, event); + +#ifdef EVENT_DEFINED_TQENTRY_ +#undef TAILQ_ENTRY +#endif + +#ifdef EVENT_DEFINED_TQHEAD_ +#undef TAILQ_HEAD +#endif + +LIST_HEAD (event_dlist, event); + +#ifdef EVENT_DEFINED_LISTENTRY_ +#undef LIST_ENTRY +#endif + +#ifdef EVENT_DEFINED_LISTHEAD_ +#undef LIST_HEAD +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_STRUCT_H_INCLUDED_ */ diff --git a/include/libevent/event2/http.h b/include/libevent/event2/http.h new file mode 100644 index 0000000..50c0a27 --- /dev/null +++ b/include/libevent/event2/http.h @@ -0,0 +1,1482 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_HTTP_H_INCLUDED_ +#define EVENT2_HTTP_H_INCLUDED_ + +/* For int types. */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* In case we haven't included the right headers yet. */ +struct evbuffer; +struct event_base; +struct bufferevent; +struct evhttp_connection; + +/** @file event2/http.h + * + * @brief Basic support for HTTP serving. + * + * As Libevent is a library for dealing with event notification and most + * interesting applications are networked today, I have often found the + * need to write HTTP code. The following prototypes and definitions provide + * an application with a minimal interface for making HTTP requests and for + * creating a very simple HTTP server. + */ + +/* Response codes */ +#define HTTP_CONTINUE 100 /**< client should proceed to send */ +#define HTTP_SWITCH_PROTOCOLS 101 /**< switching to another protocol */ +#define HTTP_PROCESSING 102 /**< processing the request, but no response is available yet */ +#define HTTP_EARLYHINTS 103 /**< return some response headers */ +#define HTTP_OK 200 /**< request completed ok */ +#define HTTP_CREATED 201 /**< new resource is created */ +#define HTTP_ACCEPTED 202 /**< accepted for processing */ +#define HTTP_NONAUTHORITATIVE 203 /**< returning a modified version of the origin's response */ +#define HTTP_NOCONTENT 204 /**< request does not have content */ +#define HTTP_MOVEPERM 301 /**< the uri moved permanently */ +#define HTTP_MOVETEMP 302 /**< the uri moved temporarily */ +#define HTTP_NOTMODIFIED 304 /**< page was not modified from last */ +#define HTTP_BADREQUEST 400 /**< invalid http request was made */ +#define HTTP_UNAUTHORIZED 401 /**< authentication is required */ +#define HTTP_PAYMENTREQUIRED 402 /**< user exceeded limit on requests */ +#define HTTP_FORBIDDEN 403 /**< user not having the necessary permissions */ +#define HTTP_NOTFOUND 404 /**< could not find content for uri */ +#define HTTP_BADMETHOD 405 /**< method not allowed for this uri */ +#define HTTP_ENTITYTOOLARGE 413 /**< request is larger than the server is able to process */ +#define HTTP_EXPECTATIONFAILED 417 /**< we can't handle this expectation */ +#define HTTP_INTERNAL 500 /**< internal error */ +#define HTTP_NOTIMPLEMENTED 501 /**< not implemented */ +#define HTTP_BADGATEWAY 502 /**< received an invalid response from the upstream */ +#define HTTP_SERVUNAVAIL 503 /**< the server is not available */ + +struct evhttp; +struct evhttp_request; +struct evkeyvalq; +struct evhttp_bound_socket; +struct evconnlistener; +struct evdns_base; +struct evhttp_ext_method; + +/** + * Create a new HTTP server. + * + * @param base (optional) the event base to receive the HTTP events + * @return a pointer to a newly initialized evhttp server structure or NULL + * on error + * @see evhttp_free() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp *evhttp_new(struct event_base *base); + +/** + * Binds an HTTP server on the specified address and port. + * + * Can be called multiple times to bind the same http server + * to multiple different ports. + * + * @param http a pointer to an evhttp object + * @param address a string containing the IP address to listen(2) on + * @param port the port number to listen on + * @return 0 on success, -1 on failure. + * @see evhttp_accept_socket() + */ +EVENT2_EXPORT_SYMBOL +int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port); + +/** + * Like evhttp_bind_socket(), but returns a handle for referencing the socket. + * + * The returned pointer is not valid after \a http is freed. + * + * @param http a pointer to an evhttp object + * @param address a string containing the IP address to listen(2) on + * @param port the port number to listen on + * @return Handle for the socket on success, NULL on failure. + * @see evhttp_bind_socket(), evhttp_del_accept_socket() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_bound_socket *evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port); + +/** + * Makes an HTTP server accept connections on the specified socket. + * + * This may be useful to create a socket and then fork multiple instances + * of an http server, or when a socket has been communicated via file + * descriptor passing in situations where an http servers does not have + * permissions to bind to a low-numbered port. + * + * Can be called multiple times to have the http server listen to + * multiple different sockets. + * + * @param http a pointer to an evhttp object + * @param fd a socket fd that is ready for accepting connections + * @return 0 on success, -1 on failure. + * @see evhttp_bind_socket() + */ +EVENT2_EXPORT_SYMBOL +int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd); + +/** + * Like evhttp_accept_socket(), but returns a handle for referencing the socket. + * + * The returned pointer is not valid after \a http is freed. + * + * @param http a pointer to an evhttp object + * @param fd a socket fd that is ready for accepting connections + * @return Handle for the socket on success, NULL on failure. + * @see evhttp_accept_socket(), evhttp_del_accept_socket() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd); + +/** + * The most low-level evhttp_bind/accept method: takes an evconnlistener, and + * returns an evhttp_bound_socket. The listener will be freed when the bound + * socket is freed. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener); + +/** + * Return the listener used to implement a bound socket. + */ +EVENT2_EXPORT_SYMBOL +struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound); + +/* + * Like evhttp_set_bevcb. + * If cb returns a non-NULL bufferevent, * the callback supplied through + * evhttp_set_bevcb isn't used. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_bound_set_bevcb(struct evhttp_bound_socket *bound, struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg); + +typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *); +/** + * Applies the function specified in the first argument to all + * evhttp_bound_sockets associated with "http". The user must not + * attempt to free or remove any connections, sockets or listeners + * in the callback "function". + * + * @param http pointer to an evhttp object + * @param function function to apply to every bound socket + * @param argument pointer value passed to function for every socket iterated + */ +EVENT2_EXPORT_SYMBOL +void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreach_fn *function, void *argument); + +/** + * Makes an HTTP server stop accepting connections on the specified socket + * + * This may be useful when a socket has been sent via file descriptor passing + * and is no longer needed by the current process. + * + * If you created this bound socket with evhttp_bind_socket_with_handle or + * evhttp_accept_socket_with_handle, this function closes the fd you provided. + * If you created this bound socket with evhttp_bind_listener, this function + * frees the listener you provided. + * + * \a bound_socket is an invalid pointer after this call returns. + * + * @param http a pointer to an evhttp object + * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle + * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound_socket); + +/** + * Get the raw file descriptor referenced by an evhttp_bound_socket. + * + * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle + * @return the file descriptor used by the bound socket + * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle() + */ +EVENT2_EXPORT_SYMBOL +evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound_socket); + +/** + * Free the previously created HTTP server. + * + * Works only if no requests are currently being served. + * + * @param http the evhttp server object to be freed + * @see evhttp_start() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_free(struct evhttp* http); + +/** XXX Document. */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size); +/** XXX Document. */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size); + +/** + * Set the maximum number of simultaneous connections for this server. + * A value of zero or less disables the limit. + * + * @param http the http server on which to set the max connection limit + * @param max_connections the maximum number of simultaneous connections or 0 + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_max_connections(struct evhttp* http, int max_connections); + +/** + * Get the current number of connections. + * + * @return The current number of connections for this server. + */ +EVENT2_EXPORT_SYMBOL +int evhttp_get_connection_count(struct evhttp* http); + +/** + Set the value to use for the Content-Type header when none was provided. If + the content type string is NULL, the Content-Type header will not be + automatically added. + + @param http the http server on which to set the default content type + @param content_type the value for the Content-Type header +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_set_default_content_type(struct evhttp *http, + const char *content_type); + +/** + Sets the what HTTP methods are supported in requests accepted by this + server, and passed to user callbacks. + + If not supported they will generate a "405 Method not allowed" response. + + By default this includes the following methods: GET, POST, HEAD, PUT, DELETE + + @param http the http server on which to set the methods + @param methods bit mask constructed from evhttp_cmd_type values +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_set_allowed_methods(struct evhttp* http, ev_uint32_t methods); + +typedef int (*evhttp_ext_method_cb)(struct evhttp_ext_method *); +/** + Sets the callback function which allows HTTP extended methods + to be supported by this server. + + The callback should : + - if method field is NULL : set method field according to type field + - else : set type and flags fields according to method string + - return 0 for success (known method / type) + - return -1 for error (unknown method / type) + + evhttp_set_allowed_methods still needs to be called. + + @param http the http server on which to add support to the methods + @param cmp the extended method callback + @see evhttp_ext_method +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_set_ext_method_cmp(struct evhttp *http, evhttp_ext_method_cb cmp); + +/** + Set a callback for a specified URI + + @param http the http sever on which to set the callback + @param path the path for which to invoke the callback + @param cb the callback function that gets invoked on requesting path + @param cb_arg an additional context argument for the callback + @return 0 on success, -1 if the callback existed already, -2 on failure +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_set_cb(struct evhttp *http, const char *path, + void (*cb)(struct evhttp_request *, void *), void *cb_arg); + +/** Removes the callback for a specified URI */ +EVENT2_EXPORT_SYMBOL +int evhttp_del_cb(struct evhttp *, const char *); + +/** + Set a callback for all requests that are not caught by specific callbacks + + Invokes the specified callback for all requests that do not match any of + the previously specified request paths. This is catchall for requests not + specifically configured with evhttp_set_cb(). + + @param http the evhttp server object for which to set the callback + @param cb the callback to invoke for any unmatched requests + @param arg an context argument for the callback +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_set_gencb(struct evhttp *http, + void (*cb)(struct evhttp_request *, void *), void *arg); + +/** + Set a callback used to create new bufferevents for connections + to a given evhttp object. + cb is not called if a non-NULL bufferevent was supplied by + evhttp_bound_set_bevcb. + + You can use this to override the default bufferevent type -- for example, + to make this evhttp object use SSL bufferevents rather than unencrypted + ones. + + New bufferevents must be allocated with no fd set on them. + + @param http the evhttp server object for which to set the callback + @param cb the callback to invoke for incoming connections + @param arg an context argument for the callback + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_bevcb(struct evhttp *http, + struct bufferevent *(*cb)(struct event_base *, void *), void *arg); + + +/** + Set a callback which allows the user to note or throttle incoming requests. + + The requests are not populated with HTTP level information. They + are just associated to a connection. + + If the callback returns -1, the associated connection is terminated + and the request is closed. + + @param http the evhttp server object for which to set the callback + @param cb the callback to invoke for incoming connections + @param arg an context argument for the callback + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_newreqcb(struct evhttp *http, + int (*cb)(struct evhttp_request*, void *), void *arg); + +/** + Set a callback to output for any error pages sent for requests of a given + evhttp object. + + You can use this to override the default error pages sent, allowing such + things as multi-lingual support or customization to match other pages. + + The callback should use the supplied buffer to output the text for an + error page. If the callback returns a negative value or doesn't output + anything to the buffer, the default error page will be sent instead. The + buffer will be automatically be sent when the callback returns, so the + callback shouldn't do so itself. + + Microsoft Internet Explorer may display its own error pages if ones sent by + an HTTP server are smaller than certain sizes, depending on the status code. + To reliably suppress this feature an error page should be at least 512 + bytes in size. + + @param http the evhttp server object for which to set the callback + @param cb the callback to invoke to format error pages + @param arg an context argument for the callback + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_errorcb(struct evhttp *http, + int (*cb)(struct evhttp_request *req, struct evbuffer *buffer, int error, const char *reason, void *cbarg), + void *cbarg); + +/** + Adds a virtual host to the http server. + + A virtual host is a newly initialized evhttp object that has request + callbacks set on it via evhttp_set_cb() or evhttp_set_gencb(). It + most not have any listing sockets associated with it. + + If the virtual host has not been removed by the time that evhttp_free() + is called on the main http server, it will be automatically freed, too. + + It is possible to have hierarchical vhosts. For example: A vhost + with the pattern *.example.com may have other vhosts with patterns + foo.example.com and bar.example.com associated with it. + + @param http the evhttp object to which to add a virtual host + @param pattern the glob pattern against which the hostname is matched. + The match is case insensitive and follows otherwise regular shell + matching. + @param vhost the virtual host to add the regular http server. + @return 0 on success, -1 on failure + @see evhttp_remove_virtual_host() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_add_virtual_host(struct evhttp* http, const char *pattern, + struct evhttp* vhost); + +/** + Removes a virtual host from the http server. + + @param http the evhttp object from which to remove the virtual host + @param vhost the virtual host to remove from the regular http server. + @return 0 on success, -1 on failure + @see evhttp_add_virtual_host() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost); + +/** + Add a server alias to an http object. The http object can be a virtual + host or the main server. + + @param http the evhttp object + @param alias the alias to add + @see evhttp_add_remove_alias() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_add_server_alias(struct evhttp *http, const char *alias); + +/** + Remove a server alias from an http object. + + @param http the evhttp object + @param alias the alias to remove + @see evhttp_add_server_alias() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_remove_server_alias(struct evhttp *http, const char *alias); + +/** + * Set the timeout for an HTTP request. + * + * @param http an evhttp object + * @param timeout the timeout, in seconds + * @see evhttp_set_timeout_tv() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_timeout(struct evhttp *http, int timeout); + +/** + * Set read and write timeout for an HTTP request. + * + * @param http an evhttp object + * @param tv the timeout, or NULL + * + * For more precise control: + * @see evhttp_set_read_timeout_tv() + * @see evhttp_set_write_timeout_tv() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv); + +/** + * Set read timeout for an HTTP request. + * + * @param http an evhttp object + * @param tv the timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_read_timeout_tv(struct evhttp *http, const struct timeval* tv); + +/** + * Set write timeout for an HTTP request. + * + * @param http an evhttp object + * @param tv the timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_write_timeout_tv(struct evhttp *http, const struct timeval* tv); + +/* Read all the clients body, and only after this respond with an error if the + * clients body exceed max_body_size */ +#define EVHTTP_SERVER_LINGERING_CLOSE 0x0001 +/** + * Set connection flags for HTTP server. + * + * @see EVHTTP_SERVER_* + * @return 0 on success, otherwise non zero (for example if flag doesn't + * supported). + */ +EVENT2_EXPORT_SYMBOL +int evhttp_set_flags(struct evhttp *http, int flags); + +/* Request/Response functionality */ + +/** + * Send an HTML error message to the client. + * + * @param req a request object + * @param error the HTTP error code + * @param reason a brief explanation of the error. If this is NULL, we'll + * just use the standard meaning of the error code. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_send_error(struct evhttp_request *req, int error, + const char *reason); + +/** + * Send an HTML reply to the client. + * + * The body of the reply consists of the data in databuf. After calling + * evhttp_send_reply() databuf will be empty, but the buffer is still + * owned by the caller and needs to be deallocated by the caller if + * necessary. + * + * @param req a request object + * @param code the HTTP response code to send + * @param reason a brief message to send with the response code + * @param databuf the body of the response + */ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply(struct evhttp_request *req, int code, + const char *reason, struct evbuffer *databuf); + +/* Low-level response interface, for streaming/chunked replies */ + +/** + Initiate a reply that uses Transfer-Encoding chunked. + + This allows the caller to stream the reply back to the client and is + useful when either not all of the reply data is immediately available + or when sending very large replies. + + The caller needs to supply data chunks with evhttp_send_reply_chunk() + and complete the reply by calling evhttp_send_reply_end(). + + @param req a request object + @param code the HTTP response code to send + @param reason a brief message to send with the response code +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_start(struct evhttp_request *req, int code, + const char *reason); + +/** + Send another data chunk as part of an ongoing chunked reply. + + The reply chunk consists of the data in databuf. After calling + evhttp_send_reply_chunk() databuf will be empty, but the buffer is + still owned by the caller and needs to be deallocated by the caller + if necessary. + + @param req a request object + @param databuf the data chunk to send as part of the reply. +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_chunk(struct evhttp_request *req, + struct evbuffer *databuf); + +/** + Send another data chunk as part of an ongoing chunked reply. + + The reply chunk consists of the data in databuf. After calling + evhttp_send_reply_chunk() databuf will be empty, but the buffer is + still owned by the caller and needs to be deallocated by the caller + if necessary. + + @param req a request object + @param databuf the data chunk to send as part of the reply. + @param cb callback funcion + @param arg call back's argument. +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf, + void (*cb)(struct evhttp_connection *, void *), void *arg); + +/** + Complete a chunked reply, freeing the request as appropriate. + + @param req a request object +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_end(struct evhttp_request *req); + +/* + * Interfaces for making requests + */ + +/** The different request types supported by evhttp. These are as specified + * in RFC2616, except for: + * - PATCH which is specified by RFC5789 + * - PROPFIND, PROPPATCH, MKCOL, LOCK, UNLOCK, COPY, MOVE + * which are specified by RFC4918 + * + * By default, only some of these methods are accepted and passed to user + * callbacks; use evhttp_set_allowed_methods() to change which methods + * are allowed. + */ +enum evhttp_cmd_type { + EVHTTP_REQ_GET = 1 << 0, + EVHTTP_REQ_POST = 1 << 1, + EVHTTP_REQ_HEAD = 1 << 2, + EVHTTP_REQ_PUT = 1 << 3, + EVHTTP_REQ_DELETE = 1 << 4, + EVHTTP_REQ_OPTIONS = 1 << 5, + EVHTTP_REQ_TRACE = 1 << 6, + EVHTTP_REQ_CONNECT = 1 << 7, + EVHTTP_REQ_PATCH = 1 << 8, + EVHTTP_REQ_PROPFIND= 1 << 9, + EVHTTP_REQ_PROPPATCH=1 << 10, + EVHTTP_REQ_MKCOL = 1 << 11, + EVHTTP_REQ_LOCK = 1 << 12, + EVHTTP_REQ_UNLOCK = 1 << 13, + EVHTTP_REQ_COPY = 1 << 14, + EVHTTP_REQ_MOVE = 1 << 15, +}; + +#define EVHTTP_REQ_MAX EVHTTP_REQ_MOVE + +/** + * @brief stucture that is passed to (and modified by) the + * extended method callback function + * + * @see evhttp_set_ext_method_cmp + * @see evhttp_connection_set_ext_method_cmp + */ +struct evhttp_ext_method { + const char *method; + ev_uint32_t type; /* @see enum evhttp_cmd_type */ + ev_uint16_t flags; /* Available flag : EVHTTP_METHOD_HAS_BODY */ +}; + +#define EVHTTP_METHOD_HAS_BODY 0x0001 + +/** a request object can represent either a request or a reply */ +enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE }; + +/** + * Create and return a connection object that can be used to for making HTTP + * requests. The connection object tries to resolve address and establish the + * connection when it is given an http request object. + * + * Connection also has default timeouts for the following events: + * - connect HTTP_CONNECT_TIMEOUT, which is 45 seconds + * - read HTTP_READ_TIMEOUT which is 50 seconds + * - write HTTP_WRITE_TIMEOUT, which is 50 seconds + * + * @param base the event_base to use for handling the connection + * @param dnsbase the dns_base to use for resolving host names; if not + * specified host name resolution will block. + * @param bev a bufferevent to use for connecting to the server; if NULL, a + * socket-based bufferevent will be created. This bufferevent will be freed + * when the connection closes. It must have no fd set on it. + * @param address the address to which to connect + * @param port the port to connect to + * @return an evhttp_connection object that can be used for making requests or + * NULL on error + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_connection_base_bufferevent_new( + struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, ev_uint16_t port); + +/** + * Create and return a connection object that can be used to for making HTTP + * requests over an unix domain socket. + * + * @param base the event_base to use for handling the connection + * @param bev a bufferevent to use for connecting to the server; if NULL, a + * socket-based bufferevent will be created. This bufferevent will be freed + * when the connection closes. It must have no fd set on it. + * @param path path of unix domain socket + * @return an evhttp_connection object that can be used for making requests + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_connection_base_bufferevent_unix_new( + struct event_base *base, struct bufferevent* bev, const char *path); + +/** + * Return the bufferevent that an evhttp_connection is using. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon); + +/** + * Return the HTTP server associated with this connection, or NULL. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp *evhttp_connection_get_server(struct evhttp_connection *evcon); + +/** + * Creates a new request object that needs to be filled in with the request + * parameters. The callback is executed when the request completed or an + * error occurred. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_request *evhttp_request_new( + void (*cb)(struct evhttp_request *, void *), void *arg); + +/** + * Enable delivery of chunks to requestor. + * @param cb will be called after every read of data with the same argument + * as the completion callback. Will never be called on an empty + * response. May drain the input buffer; it will be drained + * automatically on return. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_chunked_cb(struct evhttp_request *, + void (*cb)(struct evhttp_request *, void *)); + +/** + * Register callback for additional parsing of request headers. + * @param cb will be called after receiving and parsing the full header. + * It allows analyzing the header and possibly closing the connection + * by returning a value < 0. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_header_cb(struct evhttp_request *, + int (*cb)(struct evhttp_request *, void *)); + +/** + * The different error types supported by evhttp + * + * @see evhttp_request_set_error_cb() + */ +enum evhttp_request_error { + /** + * Timeout reached, also @see evhttp_connection_set_timeout() + */ + EVREQ_HTTP_TIMEOUT, + /** + * EOF reached + */ + EVREQ_HTTP_EOF, + /** + * Error while reading header, or invalid header + */ + EVREQ_HTTP_INVALID_HEADER, + /** + * Error encountered while reading or writing + */ + EVREQ_HTTP_BUFFER_ERROR, + /** + * The evhttp_cancel_request() called on this request. + */ + EVREQ_HTTP_REQUEST_CANCEL, + /** + * Body is greater then evhttp_connection_set_max_body_size() + */ + EVREQ_HTTP_DATA_TOO_LONG +}; +/** + * Set a callback for errors + * @see evhttp_request_error for error types. + * + * On error, both the error callback and the regular callback will be called, + * error callback is called before the regular callback. + **/ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_error_cb(struct evhttp_request *, + void (*)(enum evhttp_request_error, void *)); + +/** + * Set a callback to be called on request completion of evhttp_send_* function. + * + * The callback function will be called on the completion of the request after + * the output data has been written and before the evhttp_request object + * is destroyed. This can be useful for tracking resources associated with a + * request (ex: timing metrics). + * + * @param req a request object + * @param cb callback function that will be called on request completion + * @param cb_arg an additional context argument for the callback + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_on_complete_cb(struct evhttp_request *req, + void (*cb)(struct evhttp_request *, void *), void *cb_arg); + +/** Frees the request object and removes associated events. */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_free(struct evhttp_request *req); + +/** + * Create and return a connection object that can be used to for making HTTP + * requests. The connection object tries to resolve address and establish the + * connection when it is given an http request object. + * + * @param base the event_base to use for handling the connection + * @param dnsbase the dns_base to use for resolving host names; if not + * specified host name resolution will block. + * @param address the address to which to connect + * @param port the port to connect to + * @return an evhttp_connection object that can be used for making requests or + * NULL on error + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_connection_base_new( + struct event_base *base, struct evdns_base *dnsbase, + const char *address, ev_uint16_t port); + +/** + * Set family hint for DNS requests. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_family(struct evhttp_connection *evcon, + int family); + +/* reuse connection address on retry */ +#define EVHTTP_CON_REUSE_CONNECTED_ADDR 0x0008 +/* Try to read error, since server may already send and close + * connection, but if at that time we have some data to send then we + * can send get EPIPE and fail, while we can read that HTTP error. */ +#define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010 +/* @see EVHTTP_SERVER_LINGERING_CLOSE */ +#define EVHTTP_CON_LINGERING_CLOSE 0x0020 +/* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */ +#define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000 +/** + * Set connection flags. + * + * @see EVHTTP_CON_* + * @return 0 on success, otherwise non zero (for example if flag doesn't + * supported). + */ +EVENT2_EXPORT_SYMBOL +int evhttp_connection_set_flags(struct evhttp_connection *evcon, + int flags); + +/** Takes ownership of the request object + * + * Can be used in a request callback to keep onto the request until + * evhttp_request_free() is explicitly called by the user. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_own(struct evhttp_request *req); + +/** Returns 1 if the request is owned by the user */ +EVENT2_EXPORT_SYMBOL +int evhttp_request_is_owned(struct evhttp_request *req); + +/** + * Sets extended method cmp callback for this http connection. + * + * @see evhttp_set_ext_method_cmp + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_ext_method_cmp(struct evhttp_connection *evcon, + evhttp_ext_method_cb cmp); + +/** + * Returns the connection object associated with the request or NULL + * + * The user needs to either free the request explicitly or call + * evhttp_send_reply_end(). + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_request_get_connection(struct evhttp_request *req); + +/** + * Returns the underlying event_base for this connection + */ +EVENT2_EXPORT_SYMBOL +struct event_base *evhttp_connection_get_base(struct evhttp_connection *req); + +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, + ev_ssize_t new_max_headers_size); + +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, + ev_ssize_t new_max_body_size); + +/** Frees an http connection */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_free(struct evhttp_connection *evcon); + +/** Disowns a given connection object + * + * Can be used to tell libevent to free the connection object after + * the last request has completed or failed. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_free_on_completion(struct evhttp_connection *evcon); + +/** Sets the IP address from which http connections are made + * + * Note this resets internal bufferevent fd, so any options that had been + * installed will be flushed. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_local_address(struct evhttp_connection *evcon, + const char *address); + +/** sets the local port from which http connections are made */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_local_port(struct evhttp_connection *evcon, + ev_uint16_t port); + +/** + * Sets the timeout for this connection. + * + * @see evhttp_connection_set_timeout_tv() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_timeout(struct evhttp_connection *evcon, + int timeout); + +/** + * Sets the timeout for this connection for the following events: + * - read, if tv==NULL then it uses default timeout (HTTP_READ_TIMEOUT) + * - write, if tv==NULL then it uses default timeout (HTTP_WRITE_TIMEOUT) + * + * But it does not adjust timeout for the "connect" (for historical reasons). + * + * @param tv the timeout, or NULL + * + * For more precise control: + * @see evhttp_connection_set_connect_timeout_tv() + * @see evhttp_connection_set_read_timeout_tv() + * @see evhttp_connection_set_write_timeout_tv() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon, + const struct timeval *tv); + +/** + * Sets the connect timeout for this connection + * + * @param tv the timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_connect_timeout_tv(struct evhttp_connection *evcon, + const struct timeval *tv); + +/** + * Sets the read timeout for this connection + * + * @param tv the timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_read_timeout_tv(struct evhttp_connection *evcon, + const struct timeval *tv); + +/** + * Sets the write timeout for this connection + * + * @param tv the timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_write_timeout_tv(struct evhttp_connection *evcon, + const struct timeval *tv); + +/** + * Sets the delay before retrying requests on this connection. + * + * This is only used if evhttp_connection_set_retries is used to make the + * number of retries at least one. Each retry after the first is twice as long + * as the one before it. + * + * Default delay is HTTP_INITIAL_RETRY_TIMEOUT, which is 2 seconds. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon, + const struct timeval *tv); + +/** Sets the retry limit for this connection - -1 repeats indefinitely */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_retries(struct evhttp_connection *evcon, + int retry_max); + +/** Set a callback for connection close. */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_closecb(struct evhttp_connection *evcon, + void (*)(struct evhttp_connection *, void *), void *); + +/** Get the remote address and port associated with this connection. */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_get_peer(struct evhttp_connection *evcon, + const char **address, ev_uint16_t *port); + +/** Get the remote address associated with this connection. + * extracted from getpeername() OR from nameserver. + * + * @return NULL if getpeername() return non success, + * or connection is not connected, + * otherwise it return pointer to struct sockaddr_storage */ +EVENT2_EXPORT_SYMBOL +const struct sockaddr* +evhttp_connection_get_addr(struct evhttp_connection *evcon); + +/** + Make an HTTP request over the specified connection. + + The connection gets ownership of the request. On failure, the + request object is no longer valid as it has been freed. + + @param evcon the evhttp_connection object over which to send the request + @param req the previously created and configured request object + @param type the request type EVHTTP_REQ_GET, EVHTTP_REQ_POST, etc. + @param uri the URI associated with the request + @return 0 on success, -1 on failure + @see evhttp_cancel_request() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_make_request(struct evhttp_connection *evcon, + struct evhttp_request *req, + enum evhttp_cmd_type type, const char *uri); + +/** + Cancels a pending HTTP request. + + Cancels an ongoing HTTP request. The callback associated with this request + is not executed and the request object is freed. If the request is + currently being processed, e.g. it is ongoing, the corresponding + evhttp_connection object is going to get reset. + + A request cannot be canceled if its callback has executed already. A request + may be canceled reentrantly from its chunked callback. + + @param req the evhttp_request to cancel; req becomes invalid after this call. +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_cancel_request(struct evhttp_request *req); + +/** + * A structure to hold a parsed URI or Relative-Ref conforming to RFC3986. + */ +struct evhttp_uri; + +/** Returns the request URI */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_request_get_uri(const struct evhttp_request *req); +/** Returns the request URI (parsed) */ +EVENT2_EXPORT_SYMBOL +const struct evhttp_uri *evhttp_request_get_evhttp_uri(const struct evhttp_request *req); +/** Returns the request command */ +EVENT2_EXPORT_SYMBOL +enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req); + +EVENT2_EXPORT_SYMBOL +int evhttp_request_get_response_code(const struct evhttp_request *req); +EVENT2_EXPORT_SYMBOL +const char * evhttp_request_get_response_code_line(const struct evhttp_request *req); + +/** Returns the input headers */ +EVENT2_EXPORT_SYMBOL +struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req); +/** Returns the output headers */ +EVENT2_EXPORT_SYMBOL +struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req); +/** Returns the input buffer */ +EVENT2_EXPORT_SYMBOL +struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req); +/** Returns the output buffer */ +EVENT2_EXPORT_SYMBOL +struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req); +/** Returns the host associated with the request. If a client sends an absolute + URI, the host part of that is preferred. Otherwise, the input headers are + searched for a Host: header. NULL is returned if no absolute URI or Host: + header is provided. */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_request_get_host(struct evhttp_request *req); + +/* Interfaces for dealing with HTTP headers */ + +/** + Finds the value belonging to a header. + + @param headers the evkeyvalq object in which to find the header + @param key the name of the header to find + @returns a pointer to the value for the header or NULL if the header + could not be found. + @see evhttp_add_header(), evhttp_remove_header() +*/ +EVENT2_EXPORT_SYMBOL +const char *evhttp_find_header(const struct evkeyvalq *headers, + const char *key); + +/** + Removes a header from a list of existing headers. + + @param headers the evkeyvalq object from which to remove a header + @param key the name of the header to remove + @returns 0 if the header was removed, -1 otherwise. + @see evhttp_find_header(), evhttp_add_header() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_remove_header(struct evkeyvalq *headers, const char *key); + +/** + Adds a header to a list of existing headers. + + @param headers the evkeyvalq object to which to add a header + @param key the name of the header + @param value the value belonging to the header + @returns 0 on success, -1 otherwise. + @see evhttp_find_header(), evhttp_clear_headers() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value); + +/** + Removes all headers from the header list. + + @param headers the evkeyvalq object from which to remove all headers +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_clear_headers(struct evkeyvalq *headers); + +/* Miscellaneous utility functions */ + + +/** + Helper function to encode a string for inclusion in a URI. All + characters are replaced by their hex-escaped (%22) equivalents, + except for characters explicitly unreserved by RFC3986 -- that is, + ASCII alphanumeric characters, hyphen, dot, underscore, and tilde. + + The returned string must be freed by the caller. + + @param str an unencoded string + @return a newly allocated URI-encoded string or NULL on failure + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_encode_uri(const char *str); + +/** + As evhttp_encode_uri, but if 'size' is nonnegative, treat the string + as being 'size' bytes long. This allows you to encode strings that + may contain 0-valued bytes. + + The returned string must be freed by the caller. + + @param str an unencoded string + @param size the length of the string to encode, or -1 if the string + is NUL-terminated + @param space_to_plus if true, space characters in 'str' are encoded + as +, not %20. + @return a newly allocate URI-encoded string, or NULL on failure. + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_uriencode(const char *str, ev_ssize_t size, int space_to_plus); + +/** + Helper function to sort of decode a URI-encoded string. Unlike + evhttp_uridecode, it decodes all plus characters that appear + _after_ the first question mark character, but no plusses that occur + before. This is not a good way to decode URIs in whole or in part. + + The returned string must be freed by the caller + + @deprecated This function is deprecated; you probably want to use + evhttp_uridecode instead. + + @param uri an encoded URI + @return a newly allocated unencoded URI or NULL on failure + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_decode_uri(const char *uri); + +/** + Helper function to decode a URI-escaped string or HTTP parameter. + + If 'decode_plus' is 1, then we decode the string as an HTTP parameter + value, and convert all plus ('+') characters to spaces. If + 'decode_plus' is 0, we leave all plus characters unchanged. + + The returned string must be freed by the caller. + + @param uri a URI-encode encoded URI + @param decode_plus determines whether we convert '+' to space. + @param size_out if size_out is not NULL, *size_out is set to the size of the + returned string + @return a newly allocated unencoded URI or NULL on failure + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_uridecode(const char *uri, int decode_plus, + size_t *size_out); + +/** + Helper function to parse out arguments in a query. + + Parsing a URI like + + http://foo.com/?q=test&s=some+thing + + will result in two entries in the key value queue. + + The first entry is: key="q", value="test" + The second entry is: key="s", value="some thing" + + @deprecated This function is deprecated as of Libevent 2.0.9. Use + evhttp_uri_parse and evhttp_parse_query_str instead. + + @param uri the request URI + @param headers the head of the evkeyval queue + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evhttp_parse_query(const char *uri, struct evkeyvalq *headers); + +/** @see evhttp_parse_query_str_flags() */ +EVENT2_EXPORT_SYMBOL +int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers); + +/** Tolerate queries that are not standard conformant. + * + * Here are some examples: + * + * - test=123&test2 + * with with this flag test2 will be present in the output headers + * + * - test=123&&test2=1 + * will parse the query with this flag + * + * - test=123&=456&test2=1 + * will parse the queyr with this flag, however there won't be empty key + * present + */ +#define EVHTTP_URI_QUERY_NONCONFORMANT 0x01 +/** Prefer last value over the first from query args + * + * Example: test=123&test=456 + * Without: test=123 + * With : test=456 + */ +#define EVHTTP_URI_QUERY_LAST_VAL 0x02 + +/** + Helper function to parse out arguments from the query portion of an + HTTP URI. + + Parsing a query string like + + q=test&s=some+thing + + will result in two entries in the key value queue. + + The first entry is: key="q", value="test" + The second entry is: key="s", value="some thing" + + @param uri the query portion of the URI + @param headers the head of the evkeyval queue + @param flags one or more of EVHTTP_URI_QUERY_* + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evhttp_parse_query_str_flags(const char *uri, struct evkeyvalq *headers, unsigned flags); + +/** + * Escape HTML character entities in a string. + * + * Replaces <, >, ", ' and & with <, >, ", + * ' and & correspondingly. + * + * The returned string needs to be freed by the caller. + * + * @param html an unescaped HTML string + * @return an escaped HTML string or NULL on error + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_htmlescape(const char *html); + +/** + * Return a new empty evhttp_uri with no fields set. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_uri *evhttp_uri_new(void); + +/** + * Changes the flags set on a given URI. See EVHTTP_URI_* for + * a list of flags. + **/ +EVENT2_EXPORT_SYMBOL +void evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags); + +/** Return the scheme of an evhttp_uri, or NULL if there is no scheme has + * been set and the evhttp_uri contains a Relative-Ref. */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_scheme(const struct evhttp_uri *uri); +/** + * Return the userinfo part of an evhttp_uri, or NULL if it has no userinfo + * set. + */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_userinfo(const struct evhttp_uri *uri); +/** + * Return the host part of an evhttp_uri, or NULL if it has no host set. + * The host may either be a regular hostname (conforming to the RFC 3986 + * "regname" production), or an IPv4 address, or the empty string, or a + * bracketed IPv6 address, or a bracketed 'IP-Future' address. + * + * Note that having a NULL host means that the URI has no authority + * section, but having an empty-string host means that the URI has an + * authority section with no host part. For example, + * "mailto:user@example.com" has a host of NULL, but "file:///etc/motd" + * has a host of "". + */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_host(const struct evhttp_uri *uri); +/** Return the unix socket part of an evhttp_uri, or NULL if there is no unix + * socket set */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_unixsocket(const struct evhttp_uri *uri); +/** Return the port part of an evhttp_uri, or -1 if there is no port set. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_get_port(const struct evhttp_uri *uri); +/** Return the path part of an evhttp_uri, or NULL if it has no path set */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_path(const struct evhttp_uri *uri); +/** Return the query part of an evhttp_uri (excluding the leading "?"), or + * NULL if it has no query set */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_query(const struct evhttp_uri *uri); +/** Return the fragment part of an evhttp_uri (excluding the leading "#"), + * or NULL if it has no fragment set */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_fragment(const struct evhttp_uri *uri); + +/** Set the scheme of an evhttp_uri, or clear the scheme if scheme==NULL. + * Returns 0 on success, -1 if scheme is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme); +/** Set the userinfo of an evhttp_uri, or clear the userinfo if userinfo==NULL. + * Returns 0 on success, -1 if userinfo is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo); +/** Set the host of an evhttp_uri, or clear the host if host==NULL. + * Returns 0 on success, -1 if host is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_host(struct evhttp_uri *uri, const char *host); +/** Set the unix socket of an evhttp_uri, or clear the unix socket if unixsocket==NULL. + * Returns 0 on success, -1 if unixsocket is not well-formed */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_unixsocket(struct evhttp_uri *uri, const char *unixsocket); + +/** Set the port of an evhttp_uri, or clear the port if port==-1. + * Returns 0 on success, -1 if port is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_port(struct evhttp_uri *uri, int port); +/** Set the path of an evhttp_uri, or clear the path if path==NULL. + * Returns 0 on success, -1 if path is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_path(struct evhttp_uri *uri, const char *path); +/** Set the query of an evhttp_uri, or clear the query if query==NULL. + * The query should not include a leading "?". + * Returns 0 on success, -1 if query is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_query(struct evhttp_uri *uri, const char *query); +/** Set the fragment of an evhttp_uri, or clear the fragment if fragment==NULL. + * The fragment should not include a leading "#". + * Returns 0 on success, -1 if fragment is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment); + +/** + * Helper function to parse a URI-Reference as specified by RFC3986. + * + * This function matches the URI-Reference production from RFC3986, + * which includes both URIs like + * + * scheme://[[userinfo]@]foo.com[:port]]/[path][?query][#fragment] + * + * and relative-refs like + * + * [path][?query][#fragment] + * + * Any optional elements portions not present in the original URI are + * left set to NULL in the resulting evhttp_uri. If no port is + * specified, the port is set to -1. + * + * Note that no decoding is performed on percent-escaped characters in + * the string; if you want to parse them, use evhttp_uridecode or + * evhttp_parse_query_str as appropriate. + * + * Note also that most URI schemes will have additional constraints that + * this function does not know about, and cannot check. For example, + * mailto://www.example.com/cgi-bin/fortune.pl is not a reasonable + * mailto url, http://www.example.com:99999/ is not a reasonable HTTP + * URL, and ftp:username@example.com is not a reasonable FTP URL. + * Nevertheless, all of these URLs conform to RFC3986, and this function + * accepts all of them as valid. + * + * @param source_uri the request URI + * @param flags Zero or more EVHTTP_URI_* flags to affect the behavior + * of the parser. + * @return uri container to hold parsed data, or NULL if there is error + * @see evhttp_uri_free() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri, + unsigned flags); + +/** Tolerate URIs that do not conform to RFC3986. + * + * Unfortunately, some HTTP clients generate URIs that, according to RFC3986, + * are not conformant URIs. If you need to support these URIs, you can + * do so by passing this flag to evhttp_uri_parse_with_flags. + * + * Currently, these changes are: + *
    + *
  • Nonconformant URIs are allowed to contain otherwise unreasonable + * characters in their path, query, and fragment components. + *
+ */ +#define EVHTTP_URI_NONCONFORMANT 0x01 + +/** + * Strip brackets from the IPv6 address and only for evhttp_uri_get_host(), + * evhttp_uri_join() returns the host with brackets. + * + * Thus you can use host part of the evhttp_uri for getaddrinfo(). + * + * @see also _EVHTTP_URI_HOST_HAS_BRACKETS + */ +#define EVHTTP_URI_HOST_STRIP_BRACKETS 0x04 + +/** + * Parse unix domain socket URIs, for example: + * + * http://unix:/run/control.sock:/controller + */ +#define EVHTTP_URI_UNIX_SOCKET 0x08 + +/** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */ +EVENT2_EXPORT_SYMBOL +struct evhttp_uri *evhttp_uri_parse(const char *source_uri); + +/** + * Free all memory allocated for a parsed uri. Only use this for URIs + * generated by evhttp_uri_parse. + * + * @param uri container with parsed data + * @see evhttp_uri_parse() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_uri_free(struct evhttp_uri *uri); + +/** + * Join together the uri parts from parsed data to form a URI-Reference. + * + * Note that no escaping of reserved characters is done on the members + * of the evhttp_uri, so the generated string might not be a valid URI + * unless the members of evhttp_uri are themselves valid. + * + * @param uri container with parsed data + * @param buf destination buffer + * @param limit destination buffer size + * @return an joined uri as string or NULL on error + * @see evhttp_uri_parse() + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_HTTP_H_INCLUDED_ */ diff --git a/include/libevent/event2/http_compat.h b/include/libevent/event2/http_compat.h new file mode 100644 index 0000000..979a3a4 --- /dev/null +++ b/include/libevent/event2/http_compat.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_HTTP_COMPAT_H_INCLUDED_ +#define EVENT2_HTTP_COMPAT_H_INCLUDED_ + +/** @file event2/http_compat.h + + @brief Potentially non-threadsafe versions of the functions in http.h: provided + only for backwards compatibility. + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** + * Start an HTTP server on the specified address and port + * + * @deprecated It does not allow an event base to be specified + * + * @param address the address to which the HTTP server should be bound + * @param port the port number on which the HTTP server should listen + * @return a pointer to a newly initialized evhttp server structure + * or NULL on error + */ +EVENT2_EXPORT_SYMBOL +struct evhttp *evhttp_start(const char *address, ev_uint16_t port); + +/** + * A connection object that can be used to for making HTTP requests. The + * connection object tries to establish the connection when it is given an + * http request object. + * + * @deprecated It does not allow an event base to be specified + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_connection_new( + const char *address, ev_uint16_t port); + +/** + * Associates an event base with the connection - can only be called + * on a freshly created connection object that has not been used yet. + * + * @deprecated XXXX Why? + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_base(struct evhttp_connection *evcon, + struct event_base *base); + + +/** Returns the request URI */ +#define evhttp_request_uri evhttp_request_get_uri + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/include/libevent/event2/http_struct.h b/include/libevent/event2/http_struct.h new file mode 100644 index 0000000..b828180 --- /dev/null +++ b/include/libevent/event2/http_struct.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_HTTP_STRUCT_H_INCLUDED_ +#define EVENT2_HTTP_STRUCT_H_INCLUDED_ + +/** @file event2/http_struct.h + + Data structures for http. Using these structures may hurt forward + compatibility with later versions of Libevent: be careful! + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** + * the request structure that a server receives. + * WARNING: expect this structure to change. I will try to provide + * reasonable accessors. + */ +struct evhttp_request { +#if defined(TAILQ_ENTRY) + TAILQ_ENTRY(evhttp_request) next; +#else +struct { + struct evhttp_request *tqe_next; + struct evhttp_request **tqe_prev; +} next; +#endif + + /* the connection object that this request belongs to */ + struct evhttp_connection *evcon; + int flags; +/** The request obj owns the evhttp connection and needs to free it */ +#define EVHTTP_REQ_OWN_CONNECTION 0x0001 +/** Request was made via a proxy */ +#define EVHTTP_PROXY_REQUEST 0x0002 +/** The request object is owned by the user; the user must free it */ +#define EVHTTP_USER_OWNED 0x0004 +/** The request will be used again upstack; freeing must be deferred */ +#define EVHTTP_REQ_DEFER_FREE 0x0008 +/** The request should be freed upstack */ +#define EVHTTP_REQ_NEEDS_FREE 0x0010 + + struct evkeyvalq *input_headers; + struct evkeyvalq *output_headers; + + /* address of the remote host and the port connection came from */ + char *remote_host; + ev_uint16_t remote_port; + + /* cache of the hostname for evhttp_request_get_host */ + char *host_cache; + + enum evhttp_request_kind kind; + enum evhttp_cmd_type type; + + size_t headers_size; + size_t body_size; + + char *uri; /* uri after HTTP request was parsed */ + struct evhttp_uri *uri_elems; /* uri elements */ + + char major; /* HTTP Major number */ + char minor; /* HTTP Minor number */ + + int response_code; /* HTTP Response code */ + char *response_code_line; /* Readable response */ + + struct evbuffer *input_buffer; /* read data */ + ev_int64_t ntoread; + unsigned chunked:1, /* a chunked request */ + userdone:1; /* the user has sent all data */ + + struct evbuffer *output_buffer; /* outgoing post or data */ + + /* Callback */ + void (*cb)(struct evhttp_request *, void *); + void *cb_arg; + + /* + * Chunked data callback - call for each completed chunk if + * specified. If not specified, all the data is delivered via + * the regular callback. + */ + void (*chunk_cb)(struct evhttp_request *, void *); + + /* + * Callback added for forked-daapd so they can collect ICY + * (shoutcast) metadata from the http header. If return + * int is negative the connection will be closed. + */ + int (*header_cb)(struct evhttp_request *, void *); + + /* + * Error callback - called when error is occurred. + * @see evhttp_request_error for error types. + * + * @see evhttp_request_set_error_cb() + */ + void (*error_cb)(enum evhttp_request_error, void *); + + /* + * Send complete callback - called when the request is actually + * sent and completed. + */ + void (*on_complete_cb)(struct evhttp_request *, void *); + void *on_complete_cb_arg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_HTTP_STRUCT_H_INCLUDED_ */ + diff --git a/include/libevent/event2/keyvalq_struct.h b/include/libevent/event2/keyvalq_struct.h new file mode 100644 index 0000000..bffa54b --- /dev/null +++ b/include/libevent/event2/keyvalq_struct.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_KEYVALQ_STRUCT_H_INCLUDED_ +#define EVENT2_KEYVALQ_STRUCT_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Fix so that people don't have to run with */ +/* XXXX This code is duplicated with event_struct.h */ +#ifndef TAILQ_ENTRY +#define EVENT_DEFINED_TQENTRY_ +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ + +#ifndef TAILQ_HEAD +#define EVENT_DEFINED_TQHEAD_ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; \ + struct type **tqh_last; \ +} +#endif + +/* + * Key-Value pairs. Can be used for HTTP headers but also for + * query argument parsing. + */ +struct evkeyval { + TAILQ_ENTRY(evkeyval) next; + + char *key; + char *value; +}; + +TAILQ_HEAD (evkeyvalq, evkeyval); + +/* XXXX This code is duplicated with event_struct.h */ +#ifdef EVENT_DEFINED_TQENTRY_ +#undef TAILQ_ENTRY +#endif + +#ifdef EVENT_DEFINED_TQHEAD_ +#undef TAILQ_HEAD +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libevent/event2/listener.h b/include/libevent/event2/listener.h new file mode 100644 index 0000000..d7f638b --- /dev/null +++ b/include/libevent/event2/listener.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_LISTENER_H_INCLUDED_ +#define EVENT2_LISTENER_H_INCLUDED_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct sockaddr; +struct evconnlistener; + +/**@file event2/listener.h + + @brief A callback that we invoke when a listener has a new connection. + + @param listener The evconnlistener + @param fd The new file descriptor + @param addr The source address of the connection + @param socklen The length of addr + @param user_arg the pointer passed to evconnlistener_new() + */ +typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *); + +/** + A callback that we invoke when a listener encounters a non-retriable error. + + @param listener The evconnlistener + @param user_arg the pointer passed to evconnlistener_new() + */ +typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *); + +/** Flag: Indicates that we should not make incoming sockets nonblocking + * before passing them to the callback. */ +#define LEV_OPT_LEAVE_SOCKETS_BLOCKING (1u<<0) +/** Flag: Indicates that freeing the listener should close the underlying + * socket. */ +#define LEV_OPT_CLOSE_ON_FREE (1u<<1) +/** Flag: Indicates that we should set the close-on-exec flag, if possible */ +#define LEV_OPT_CLOSE_ON_EXEC (1u<<2) +/** Flag: Indicates that we should disable the timeout (if any) between when + * this socket is closed and when we can listen again on the same port. */ +#define LEV_OPT_REUSEABLE (1u<<3) +/** Flag: Indicates that the listener should be locked so it's safe to use + * from multiple threadcs at once. */ +#define LEV_OPT_THREADSAFE (1u<<4) +/** Flag: Indicates that the listener should be created in disabled + * state. Use evconnlistener_enable() to enable it later. */ +#define LEV_OPT_DISABLED (1u<<5) +/** Flag: Indicates that the listener should defer accept() until data is + * available, if possible. Ignored on platforms that do not support this. + * + * This option can help performance for protocols where the client transmits + * immediately after connecting. Do not use this option if your protocol + * _doesn't_ start out with the client transmitting data, since in that case + * this option will sometimes cause the kernel to never tell you about the + * connection. + * + * This option is only supported by evconnlistener_new_bind(): it can't + * work with evconnlistener_new_fd(), since the listener needs to be told + * to use the option before it is actually bound. + */ +#define LEV_OPT_DEFERRED_ACCEPT (1u<<6) +/** Flag: Indicates that we ask to allow multiple servers (processes or + * threads_) to bind to the same port if they each set the option. + * + * SO_REUSEPORT is what most people would expect SO_REUSEADDR to be, however + * SO_REUSEPORT does not imply SO_REUSEADDR. + * + * This is only available on Linux and kernel 3.9+ + */ +#define LEV_OPT_REUSEABLE_PORT (1u<<7) +/** Flag: Indicates that the listener wants to work only in IPv6 socket. + * + * According to RFC3493 and most Linux distributions, default value is to + * work in IPv4-mapped mode. If there is a requirement to bind same port + * on same ip addresses but different handlers for both IPv4 and IPv6, + * it is required to set IPV6_V6ONLY socket option to be sure that the + * code works as expected without affected by bindv6only sysctl setting in + * system. + * + * This socket option also supported by Windows. + */ +#define LEV_OPT_BIND_IPV6ONLY (1u<<8) + +/** + Allocate a new evconnlistener object to listen for incoming TCP connections + on a given file descriptor. + + @param base The event base to associate the listener with. + @param cb A callback to be invoked when a new connection arrives. If the + callback is NULL, the listener will be treated as disabled until the + callback is set. + @param ptr A user-supplied pointer to give to the callback. + @param flags Any number of LEV_OPT_* flags + @param backlog Passed to the listen() call to determine the length of the + acceptable connection backlog. Set to -1 for a reasonable default. + Set to 0 if the socket is already listening. + @param fd The file descriptor to listen on. It must be a nonblocking + file descriptor, and it should already be bound to an appropriate + port and address. +*/ +EVENT2_EXPORT_SYMBOL +struct evconnlistener *evconnlistener_new(struct event_base *base, + evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, + evutil_socket_t fd); +/** + Allocate a new evconnlistener object to listen for incoming TCP connections + on a given address. + + @param base The event base to associate the listener with. + @param cb A callback to be invoked when a new connection arrives. If the + callback is NULL, the listener will be treated as disabled until the + callback is set. + @param ptr A user-supplied pointer to give to the callback. + @param flags Any number of LEV_OPT_* flags + @param backlog Passed to the listen() call to determine the length of the + acceptable connection backlog. Set to -1 for a reasonable default. + @param sa The address to listen for connections on. + @param socklen The length of the address. + */ +EVENT2_EXPORT_SYMBOL +struct evconnlistener *evconnlistener_new_bind(struct event_base *base, + evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, + const struct sockaddr *sa, int socklen); +/** + Disable and deallocate an evconnlistener. + */ +EVENT2_EXPORT_SYMBOL +void evconnlistener_free(struct evconnlistener *lev); +/** + Re-enable an evconnlistener that has been disabled. + */ +EVENT2_EXPORT_SYMBOL +int evconnlistener_enable(struct evconnlistener *lev); +/** + Stop listening for connections on an evconnlistener. + */ +EVENT2_EXPORT_SYMBOL +int evconnlistener_disable(struct evconnlistener *lev); + +/** Return an evconnlistener's associated event_base. */ +EVENT2_EXPORT_SYMBOL +struct event_base *evconnlistener_get_base(struct evconnlistener *lev); + +/** Return the socket that an evconnlistner is listening on. */ +EVENT2_EXPORT_SYMBOL +evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev); + +/** Change the callback on the listener to cb and its user_data to arg. + */ +EVENT2_EXPORT_SYMBOL +void evconnlistener_set_cb(struct evconnlistener *lev, + evconnlistener_cb cb, void *arg); + +/** Set an evconnlistener's error callback. */ +EVENT2_EXPORT_SYMBOL +void evconnlistener_set_error_cb(struct evconnlistener *lev, + evconnlistener_errorcb errorcb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libevent/event2/rpc.h b/include/libevent/event2/rpc.h new file mode 100644 index 0000000..9e8830c --- /dev/null +++ b/include/libevent/event2/rpc.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_RPC_H_INCLUDED_ +#define EVENT2_RPC_H_INCLUDED_ + +/* For int types. */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file event2/rpc.h + * + * @brief This header files provides basic support for an RPC server and client. + * + * To support RPCs in a server, every supported RPC command needs to be + * defined and registered. + * + * EVRPC_HEADER(SendCommand, Request, Reply); + * + * SendCommand is the name of the RPC command. + * Request is the name of a structure generated by event_rpcgen.py. + * It contains all parameters relating to the SendCommand RPC. The + * server needs to fill in the Reply structure. + * Reply is the name of a structure generated by event_rpcgen.py. It + * contains the answer to the RPC. + * + * To register an RPC with an HTTP server, you need to first create an RPC + * base with: + * + * struct evrpc_base *base = evrpc_init(http); + * + * A specific RPC can then be registered with + * + * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg); + * + * when the server receives an appropriately formatted RPC, the user callback + * is invoked. The callback needs to fill in the reply structure. + * + * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg); + * + * To send the reply, call EVRPC_REQUEST_DONE(rpc); + * + * See the regression test for an example. + */ + +/** + Determines if the member has been set in the message + + @param msg the message to inspect + @param member the member variable to test for presences + @return 1 if it's present or 0 otherwise. +*/ +#define EVTAG_HAS(msg, member) \ + ((msg)->member##_set == 1) + +#ifndef EVENT2_RPC_COMPAT_H_INCLUDED_ + +/** + Assigns a value to the member in the message. + + @param msg the message to which to assign a value + @param member the name of the member variable + @param value the value to assign +*/ +#define EVTAG_ASSIGN(msg, member, value) \ + (*(msg)->base->member##_assign)((msg), (value)) +/** + Assigns a value to the member in the message. + + @param msg the message to which to assign a value + @param member the name of the member variable + @param value the value to assign + @param len the length of the value +*/ +#define EVTAG_ASSIGN_WITH_LEN(msg, member, value, len) \ + (*(msg)->base->member##_assign)((msg), (value), (len)) +/** + Returns the value for a member. + + @param msg the message from which to get the value + @param member the name of the member variable + @param pvalue a pointer to the variable to hold the value + @return 0 on success, -1 otherwise. +*/ +#define EVTAG_GET(msg, member, pvalue) \ + (*(msg)->base->member##_get)((msg), (pvalue)) +/** + Returns the value for a member. + + @param msg the message from which to get the value + @param member the name of the member variable + @param pvalue a pointer to the variable to hold the value + @param plen a pointer to the length of the value + @return 0 on success, -1 otherwise. +*/ +#define EVTAG_GET_WITH_LEN(msg, member, pvalue, plen) \ + (*(msg)->base->member##_get)((msg), (pvalue), (plen)) + +#endif /* EVENT2_RPC_COMPAT_H_INCLUDED_ */ + +/** + Adds a value to an array. +*/ +#define EVTAG_ARRAY_ADD_VALUE(msg, member, value) \ + (*(msg)->base->member##_add)((msg), (value)) +/** + Allocates a new entry in the array and returns it. +*/ +#define EVTAG_ARRAY_ADD(msg, member) \ + (*(msg)->base->member##_add)(msg) +/** + Gets a variable at the specified offset from the array. +*/ +#define EVTAG_ARRAY_GET(msg, member, offset, pvalue) \ + (*(msg)->base->member##_get)((msg), (offset), (pvalue)) +/** + Returns the number of entries in the array. +*/ +#define EVTAG_ARRAY_LEN(msg, member) ((msg)->member##_length) + + +struct evbuffer; +struct event_base; +struct evrpc_req_generic; +struct evrpc_request_wrapper; +struct evrpc; + +/** The type of a specific RPC Message + * + * @param rpcname the name of the RPC message + */ +#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname + +struct evhttp_request; +struct evrpc_status; +struct evrpc_hook_meta; + +/** Creates the definitions and prototypes for an RPC + * + * You need to use EVRPC_HEADER to create structures and function prototypes + * needed by the server and client implementation. The structures have to be + * defined in an .rpc file and converted to source code via event_rpcgen.py + * + * @param rpcname the name of the RPC + * @param reqstruct the name of the RPC request structure + * @param rplystruct the name of the RPC reply structure + * @see EVRPC_GENERATE() + */ +#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \ +EVRPC_STRUCT(rpcname) { \ + struct evrpc_hook_meta *hook_meta; \ + struct reqstruct* request; \ + struct rplystruct* reply; \ + struct evrpc* rpc; \ + struct evhttp_request* http_req; \ + struct evbuffer* rpc_data; \ +}; \ +EVENT2_EXPORT_SYMBOL \ +int evrpc_send_request_##rpcname(struct evrpc_pool *, \ + struct reqstruct *, struct rplystruct *, \ + void (*)(struct evrpc_status *, \ + struct reqstruct *, struct rplystruct *, void *cbarg), \ + void *); + +struct evrpc_pool; + +/** use EVRPC_GENERATE instead */ +EVENT2_EXPORT_SYMBOL +struct evrpc_request_wrapper *evrpc_make_request_ctx( + struct evrpc_pool *pool, void *request, void *reply, + const char *rpcname, + void (*req_marshal)(struct evbuffer*, void *), + void (*rpl_clear)(void *), + int (*rpl_unmarshal)(void *, struct evbuffer *), + void (*cb)(struct evrpc_status *, void *, void *, void *), + void *cbarg); + +/** Creates a context structure that contains rpc specific information. + * + * EVRPC_MAKE_CTX is used to populate a RPC specific context that + * contains information about marshaling the RPC data types. + * + * @param rpcname the name of the RPC + * @param reqstruct the name of the RPC request structure + * @param rplystruct the name of the RPC reply structure + * @param pool the evrpc_pool over which to make the request + * @param request a pointer to the RPC request structure object + * @param reply a pointer to the RPC reply structure object + * @param cb the callback function to call when the RPC has completed + * @param cbarg the argument to supply to the callback + */ +#define EVRPC_MAKE_CTX(rpcname, reqstruct, rplystruct, \ + pool, request, reply, cb, cbarg) \ + evrpc_make_request_ctx(pool, request, reply, \ + #rpcname, \ + (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \ + (void (*)(void *))rplystruct##_clear, \ + (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal, \ + (void (*)(struct evrpc_status *, void *, void *, void *))cb, \ + cbarg) + +/** Generates the code for receiving and sending an RPC message + * + * EVRPC_GENERATE is used to create the code corresponding to sending + * and receiving a particular RPC message + * + * @param rpcname the name of the RPC + * @param reqstruct the name of the RPC request structure + * @param rplystruct the name of the RPC reply structure + * @see EVRPC_HEADER() + */ +#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \ + int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \ + struct reqstruct *request, struct rplystruct *reply, \ + void (*cb)(struct evrpc_status *, \ + struct reqstruct *, struct rplystruct *, void *cbarg), \ + void *cbarg) { \ + return evrpc_send_request_generic(pool, request, reply, \ + (void (*)(struct evrpc_status *, void *, void *, void *))cb, \ + cbarg, \ + #rpcname, \ + (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \ + (void (*)(void *))rplystruct##_clear, \ + (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal); \ +} + +/** Provides access to the HTTP request object underlying an RPC + * + * Access to the underlying http object; can be used to look at headers or + * for getting the remote ip address + * + * @param rpc_req the rpc request structure provided to the server callback + * @return an struct evhttp_request object that can be inspected for + * HTTP headers or sender information. + */ +#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req + +/** completes the server response to an rpc request */ +EVENT2_EXPORT_SYMBOL +void evrpc_request_done(struct evrpc_req_generic *req); + +/** accessors for request and reply */ +EVENT2_EXPORT_SYMBOL +void *evrpc_get_request(struct evrpc_req_generic *req); +EVENT2_EXPORT_SYMBOL +void *evrpc_get_reply(struct evrpc_req_generic *req); + +/** Creates the reply to an RPC request + * + * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected + * to have been filled in. The request and reply pointers become invalid + * after this call has finished. + * + * @param rpc_req the rpc request structure provided to the server callback + */ +#define EVRPC_REQUEST_DONE(rpc_req) do { \ + struct evrpc_req_generic *req_ = (struct evrpc_req_generic *)(rpc_req); \ + evrpc_request_done(req_); \ +} while (0) + + +struct evrpc_base; +struct evhttp; + +/* functions to start up the rpc system */ + +/** Creates a new rpc base from which RPC requests can be received + * + * @param server a pointer to an existing HTTP server + * @return a newly allocated evrpc_base struct or NULL if an error occurred + * @see evrpc_free() + */ +EVENT2_EXPORT_SYMBOL +struct evrpc_base *evrpc_init(struct evhttp *server); + +/** + * Frees the evrpc base + * + * For now, you are responsible for making sure that no rpcs are ongoing. + * + * @param base the evrpc_base object to be freed + * @see evrpc_init + */ +EVENT2_EXPORT_SYMBOL +void evrpc_free(struct evrpc_base *base); + +/** register RPCs with the HTTP Server + * + * registers a new RPC with the HTTP server, each RPC needs to have + * a unique name under which it can be identified. + * + * @param base the evrpc_base structure in which the RPC should be + * registered. + * @param name the name of the RPC + * @param request the name of the RPC request structure + * @param reply the name of the RPC reply structure + * @param callback the callback that should be invoked when the RPC + * is received. The callback has the following prototype + * void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg) + * @param cbarg an additional parameter that can be passed to the callback. + * The parameter can be used to carry around state. + */ +#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \ + evrpc_register_generic(base, #name, \ + (void (*)(struct evrpc_req_generic *, void *))callback, cbarg, \ + (void *(*)(void *))request##_new_with_arg, NULL, \ + (void (*)(void *))request##_free, \ + (int (*)(void *, struct evbuffer *))request##_unmarshal, \ + (void *(*)(void *))reply##_new_with_arg, NULL, \ + (void (*)(void *))reply##_free, \ + (int (*)(void *))reply##_complete, \ + (void (*)(struct evbuffer *, void *))reply##_marshal) + +/** + Low level function for registering an RPC with a server. + + Use EVRPC_REGISTER() instead. + + @see EVRPC_REGISTER() +*/ +EVENT2_EXPORT_SYMBOL +int evrpc_register_rpc(struct evrpc_base *, struct evrpc *, + void (*)(struct evrpc_req_generic*, void *), void *); + +/** + * Unregisters an already registered RPC + * + * @param base the evrpc_base object from which to unregister an RPC + * @param name the name of the rpc to unregister + * @return -1 on error or 0 when successful. + * @see EVRPC_REGISTER() + */ +#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc((base), #name) + +EVENT2_EXPORT_SYMBOL +int evrpc_unregister_rpc(struct evrpc_base *base, const char *name); + +/* + * Client-side RPC support + */ + +struct evhttp_connection; +struct evrpc_status; + +/** launches an RPC and sends it to the server + * + * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server. + * + * @param name the name of the RPC + * @param pool the evrpc_pool that contains the connection objects over which + * the request should be sent. + * @param request a pointer to the RPC request structure - it contains the + * data to be sent to the server. + * @param reply a pointer to the RPC reply structure. It is going to be filled + * if the request was answered successfully + * @param cb the callback to invoke when the RPC request has been answered + * @param cbarg an additional argument to be passed to the client + * @return 0 on success, -1 on failure + */ +#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \ + evrpc_send_request_##name((pool), (request), (reply), (cb), (cbarg)) + +/** + Makes an RPC request based on the provided context. + + This is a low-level function and should not be used directly + unless a custom context object is provided. Use EVRPC_MAKE_REQUEST() + instead. + + @param ctx a context from EVRPC_MAKE_CTX() + @returns 0 on success, -1 otherwise. + @see EVRPC_MAKE_REQUEST(), EVRPC_MAKE_CTX() +*/ +EVENT2_EXPORT_SYMBOL +int evrpc_make_request(struct evrpc_request_wrapper *ctx); + +/** creates an rpc connection pool + * + * a pool has a number of connections associated with it. + * rpc requests are always made via a pool. + * + * @param base a pointer to an struct event_based object; can be left NULL + * in singled-threaded applications + * @return a newly allocated struct evrpc_pool object or NULL if an error + * occurred + * @see evrpc_pool_free() + */ +EVENT2_EXPORT_SYMBOL +struct evrpc_pool *evrpc_pool_new(struct event_base *base); +/** frees an rpc connection pool + * + * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new() + * @see evrpc_pool_new() + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_free(struct evrpc_pool *pool); + +/** + * Adds a connection over which rpc can be dispatched to the pool. + * + * The connection object must have been newly created. + * + * @param pool the pool to which to add the connection + * @param evcon the connection to add to the pool. + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_add_connection(struct evrpc_pool *pool, + struct evhttp_connection *evcon); + +/** + * Removes a connection from the pool. + * + * The connection object must have been newly created. + * + * @param pool the pool from which to remove the connection + * @param evcon the connection to remove from the pool. + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_remove_connection(struct evrpc_pool *pool, + struct evhttp_connection *evcon); + +/** + * Sets the timeout in secs after which a request has to complete. The + * RPC is completely aborted if it does not complete by then. Setting + * the timeout to 0 means that it never timeouts and can be used to + * implement callback type RPCs. + * + * Any connection already in the pool will be updated with the new + * timeout. Connections added to the pool after set_timeout has be + * called receive the pool timeout only if no timeout has been set + * for the connection itself. + * + * @param pool a pointer to a struct evrpc_pool object + * @param timeout_in_secs the number of seconds after which a request should + * timeout and a failure be returned to the callback. + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs); + +/** + * Hooks for changing the input and output of RPCs; this can be used to + * implement compression, authentication, encryption, ... + */ + +enum EVRPC_HOOK_TYPE { + EVRPC_INPUT, /**< apply the function to an input hook */ + EVRPC_OUTPUT /**< apply the function to an output hook */ +}; + +#ifndef _WIN32 +/** Deprecated alias for EVRPC_INPUT. Not available on windows, where it + * conflicts with platform headers. */ +#define INPUT EVRPC_INPUT +/** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it + * conflicts with platform headers. */ +#define OUTPUT EVRPC_OUTPUT +#endif + +/** + * Return value from hook processing functions + */ + +enum EVRPC_HOOK_RESULT { + EVRPC_TERMINATE = -1, /**< indicates the rpc should be terminated */ + EVRPC_CONTINUE = 0, /**< continue processing the rpc */ + EVRPC_PAUSE = 1 /**< pause processing request until resumed */ +}; + +/** adds a processing hook to either an rpc base or rpc pool + * + * If a hook returns TERMINATE, the processing is aborted. On CONTINUE, + * the request is immediately processed after the hook returns. If the + * hook returns PAUSE, request processing stops until evrpc_resume_request() + * has been called. + * + * The add functions return handles that can be used for removing hooks. + * + * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool + * @param hook_type either INPUT or OUTPUT + * @param cb the callback to call when the hook is activated + * @param cb_arg an additional argument for the callback + * @return a handle to the hook so it can be removed later + * @see evrpc_remove_hook() + */ +EVENT2_EXPORT_SYMBOL +void *evrpc_add_hook(void *vbase, + enum EVRPC_HOOK_TYPE hook_type, + int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *), + void *cb_arg); + +/** removes a previously added hook + * + * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool + * @param hook_type either INPUT or OUTPUT + * @param handle a handle returned by evrpc_add_hook() + * @return 1 on success or 0 on failure + * @see evrpc_add_hook() + */ +EVENT2_EXPORT_SYMBOL +int evrpc_remove_hook(void *vbase, + enum EVRPC_HOOK_TYPE hook_type, + void *handle); + +/** resume a paused request + * + * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool + * @param ctx the context pointer provided to the original hook call + */ +EVENT2_EXPORT_SYMBOL +int evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res); + +/** adds meta data to request + * + * evrpc_hook_add_meta() allows hooks to add meta data to a request. for + * a client request, the meta data can be inserted by an outgoing request hook + * and retrieved by the incoming request hook. + * + * @param ctx the context provided to the hook call + * @param key a NUL-terminated c-string + * @param data the data to be associated with the key + * @param data_size the size of the data + */ +EVENT2_EXPORT_SYMBOL +void evrpc_hook_add_meta(void *ctx, const char *key, + const void *data, size_t data_size); + +/** retrieves meta data previously associated + * + * evrpc_hook_find_meta() can be used to retrieve meta data associated to a + * request by a previous hook. + * @param ctx the context provided to the hook call + * @param key a NUL-terminated c-string + * @param data pointer to a data pointer that will contain the retrieved data + * @param data_size pointer to the size of the data + * @return 0 on success or -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evrpc_hook_find_meta(void *ctx, const char *key, + void **data, size_t *data_size); + +/** + * returns the connection object associated with the request + * + * @param ctx the context provided to the hook call + * @return a pointer to the evhttp_connection object or NULL if an error + * occurred + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evrpc_hook_get_connection(void *ctx); + +/** + Function for sending a generic RPC request. + + Do not call this function directly, use EVRPC_MAKE_REQUEST() instead. + + @see EVRPC_MAKE_REQUEST() + */ +EVENT2_EXPORT_SYMBOL +int evrpc_send_request_generic(struct evrpc_pool *pool, + void *request, void *reply, + void (*cb)(struct evrpc_status *, void *, void *, void *), + void *cb_arg, + const char *rpcname, + void (*req_marshal)(struct evbuffer *, void *), + void (*rpl_clear)(void *), + int (*rpl_unmarshal)(void *, struct evbuffer *)); + +/** + Function for registering a generic RPC with the RPC base. + + Do not call this function directly, use EVRPC_REGISTER() instead. + + @see EVRPC_REGISTER() + */ +EVENT2_EXPORT_SYMBOL +int evrpc_register_generic(struct evrpc_base *base, const char *name, + void (*callback)(struct evrpc_req_generic *, void *), void *cbarg, + void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *), + int (*req_unmarshal)(void *, struct evbuffer *), + void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *), + int (*rpl_complete)(void *), + void (*rpl_marshal)(struct evbuffer *, void *)); + +/** accessors for obscure and undocumented functionality */ +EVENT2_EXPORT_SYMBOL +struct evrpc_pool* evrpc_request_get_pool(struct evrpc_request_wrapper *ctx); +EVENT2_EXPORT_SYMBOL +void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx, + struct evrpc_pool *pool); +EVENT2_EXPORT_SYMBOL +void evrpc_request_set_cb(struct evrpc_request_wrapper *ctx, + void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg), + void *cb_arg); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_RPC_H_INCLUDED_ */ diff --git a/include/libevent/event2/rpc_compat.h b/include/libevent/event2/rpc_compat.h new file mode 100644 index 0000000..b3d3de3 --- /dev/null +++ b/include/libevent/event2/rpc_compat.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_RPC_COMPAT_H_INCLUDED_ +#define EVENT2_RPC_COMPAT_H_INCLUDED_ + +/** @file event2/rpc_compat.h + + @brief Deprecated versions of the functions in rpc.h: provided only for + backwards compatibility. + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** backwards compatible accessors that work only with gcc */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) + +#undef EVTAG_ASSIGN +#undef EVTAG_GET +#undef EVTAG_ADD + +#define EVTAG_ASSIGN(msg, member, args...) \ + (*(msg)->base->member##_assign)(msg, ## args) +#define EVTAG_GET(msg, member, args...) \ + (*(msg)->base->member##_get)(msg, ## args) +#define EVTAG_ADD(msg, member, args...) \ + (*(msg)->base->member##_add)(msg, ## args) +#endif +#define EVTAG_LEN(msg, member) ((msg)->member##_length) + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/include/libevent/event2/rpc_struct.h b/include/libevent/event2/rpc_struct.h new file mode 100644 index 0000000..f3cb460 --- /dev/null +++ b/include/libevent/event2/rpc_struct.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_RPC_STRUCT_H_INCLUDED_ +#define EVENT2_RPC_STRUCT_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file event2/rpc_struct.h + + Structures used by rpc.h. Using these structures directly may harm + forward compatibility: be careful! + + */ + +/* Fix so that people don't have to run with */ +#ifndef TAILQ_ENTRY +#define EVENT_DEFINED_TQENTRY_ +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ + +/** + * provides information about the completed RPC request. + */ +struct evrpc_status { +#define EVRPC_STATUS_ERR_NONE 0 +#define EVRPC_STATUS_ERR_TIMEOUT 1 +#define EVRPC_STATUS_ERR_BADPAYLOAD 2 +#define EVRPC_STATUS_ERR_UNSTARTED 3 +#define EVRPC_STATUS_ERR_HOOKABORTED 4 + int error; + + /* for looking at headers or other information */ + struct evhttp_request *http_req; +}; + +/* the structure below needs to be synchronized with evrpc_req_generic */ + +/* Encapsulates a request */ +struct evrpc { + TAILQ_ENTRY(evrpc) next; + + /* the URI at which the request handler lives */ + const char* uri; + + /* creates a new request structure */ + void *(*request_new)(void *); + void *request_new_arg; + + /* frees the request structure */ + void (*request_free)(void *); + + /* unmarshals the buffer into the proper request structure */ + int (*request_unmarshal)(void *, struct evbuffer *); + + /* creates a new reply structure */ + void *(*reply_new)(void *); + void *reply_new_arg; + + /* frees the reply structure */ + void (*reply_free)(void *); + + /* verifies that the reply is valid */ + int (*reply_complete)(void *); + + /* marshals the reply into a buffer */ + void (*reply_marshal)(struct evbuffer*, void *); + + /* the callback invoked for each received rpc */ + void (*cb)(struct evrpc_req_generic *, void *); + void *cb_arg; + + /* reference for further configuration */ + struct evrpc_base *base; +}; + +#ifdef EVENT_DEFINED_TQENTRY_ +#undef TAILQ_ENTRY +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_RPC_STRUCT_H_INCLUDED_ */ diff --git a/include/libevent/event2/tag.h b/include/libevent/event2/tag.h new file mode 100644 index 0000000..e765ea8 --- /dev/null +++ b/include/libevent/event2/tag.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_TAG_H_INCLUDED_ +#define EVENT2_TAG_H_INCLUDED_ + +/** @file event2/tag.h + + @brief Helper functions for reading and writing tagged data onto buffers. + + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +struct evbuffer; + +/* + * Marshaling tagged data - We assume that all tags are inserted in their + * numeric order - so that unknown tags will always be higher than the + * known ones - and we can just ignore the end of an event buffer. + */ + +EVENT2_EXPORT_SYMBOL +void evtag_init(void); + +/** + Unmarshals the header and returns the length of the payload + + @param evbuf the buffer from which to unmarshal data + @param ptag a pointer in which the tag id is being stored + @returns -1 on failure or the number of bytes in the remaining payload. +*/ +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, + ev_uint32_t len); +EVENT2_EXPORT_SYMBOL +void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag, + struct evbuffer *data); + +/** + Encode an integer and store it in an evbuffer. + + We encode integers by nybbles; the first nibble contains the number + of significant nibbles - 1; this allows us to encode up to 64-bit + integers. This function is byte-order independent. + + @param evbuf evbuffer to store the encoded number + @param number a 32-bit integer + */ +EVENT2_EXPORT_SYMBOL +void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number); +EVENT2_EXPORT_SYMBOL +void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint32_t integer); +EVENT2_EXPORT_SYMBOL +void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint64_t integer); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, + const char *string); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, + struct timeval *tv); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, + struct evbuffer *dst); +EVENT2_EXPORT_SYMBOL +int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); +EVENT2_EXPORT_SYMBOL +int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); +EVENT2_EXPORT_SYMBOL +int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); +EVENT2_EXPORT_SYMBOL +int evtag_consume(struct evbuffer *evbuf); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint32_t *pinteger); +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint64_t *pinteger); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, + void *data, size_t len); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, + char **pstring); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, + struct timeval *ptv); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_TAG_H_INCLUDED_ */ diff --git a/include/libevent/event2/tag_compat.h b/include/libevent/event2/tag_compat.h new file mode 100644 index 0000000..51a09e4 --- /dev/null +++ b/include/libevent/event2/tag_compat.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_TAG_COMPAT_H_INCLUDED_ +#define EVENT2_TAG_COMPAT_H_INCLUDED_ + +/** @file event2/tag_compat.h + + @brief Obsolete/deprecated functions from tag.h; provided only for backwards + compatibility. + */ + +/** + @name Misnamed functions + + @deprecated These macros are deprecated because their names don't follow + Libevent's naming conventions. Use evtag_encode_int and + evtag_encode_int64 instead. + + @{ +*/ +#define encode_int(evbuf, number) evtag_encode_int((evbuf), (number)) +#define encode_int64(evbuf, number) evtag_encode_int64((evbuf), (number)) +/**@}*/ + +#endif /* EVENT2_TAG_H_INCLUDED_ */ diff --git a/include/libevent/event2/thread.h b/include/libevent/event2/thread.h new file mode 100644 index 0000000..481a02f --- /dev/null +++ b/include/libevent/event2/thread.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_THREAD_H_INCLUDED_ +#define EVENT2_THREAD_H_INCLUDED_ + +/** @file event2/thread.h + + @brief Functions for multi-threaded applications using Libevent. + + When using a multi-threaded application in which multiple threads + add and delete events from a single event base, Libevent needs to + lock its data structures. + + Like the memory-management function hooks, all of the threading functions + _must_ be set up before an event_base is created if you want the base to + use them. + + Most programs will either be using Windows threads or Posix threads. You + can configure Libevent to use one of these evthread_use_windows_threads() or + evthread_use_pthreads() respectively. If you're using another threading + library, you'll need to configure threading functions manually using + evthread_set_lock_callbacks() and evthread_set_condition_callbacks(). + + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + @name Flags passed to lock functions + + @{ +*/ +/** A flag passed to a locking callback when the lock was allocated as a + * read-write lock, and we want to acquire or release the lock for writing. */ +#define EVTHREAD_WRITE 0x04 +/** A flag passed to a locking callback when the lock was allocated as a + * read-write lock, and we want to acquire or release the lock for reading. */ +#define EVTHREAD_READ 0x08 +/** A flag passed to a locking callback when we don't want to block waiting + * for the lock; if we can't get the lock immediately, we will instead + * return nonzero from the locking callback. */ +#define EVTHREAD_TRY 0x10 +/**@}*/ + +#if !defined(EVENT__DISABLE_THREAD_SUPPORT) || defined(EVENT_IN_DOXYGEN_) + +#define EVTHREAD_LOCK_API_VERSION 1 + +/** + @name Types of locks + + @{*/ +/** A recursive lock is one that can be acquired multiple times at once by the + * same thread. No other process can allocate the lock until the thread that + * has been holding it has unlocked it as many times as it locked it. */ +#define EVTHREAD_LOCKTYPE_RECURSIVE 1 +/* A read-write lock is one that allows multiple simultaneous readers, but + * where any one writer excludes all other writers and readers. */ +#define EVTHREAD_LOCKTYPE_READWRITE 2 +/**@}*/ + +/** This structure describes the interface a threading library uses for + * locking. It's used to tell evthread_set_lock_callbacks() how to use + * locking on this platform. + */ +struct evthread_lock_callbacks { + /** The current version of the locking API. Set this to + * EVTHREAD_LOCK_API_VERSION */ + int lock_api_version; + /** Which kinds of locks does this version of the locking API + * support? A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and + * EVTHREAD_LOCKTYPE_READWRITE. + * + * (Note that RECURSIVE locks are currently mandatory, and + * READWRITE locks are not currently used.) + **/ + unsigned supported_locktypes; + /** Function to allocate and initialize new lock of type 'locktype'. + * Returns NULL on failure. */ + void *(*alloc)(unsigned locktype); + /** Funtion to release all storage held in 'lock', which was created + * with type 'locktype'. */ + void (*free)(void *lock, unsigned locktype); + /** Acquire an already-allocated lock at 'lock' with mode 'mode'. + * Returns 0 on success, and nonzero on failure. */ + int (*lock)(unsigned mode, void *lock); + /** Release a lock at 'lock' using mode 'mode'. Returns 0 on success, + * and nonzero on failure. */ + int (*unlock)(unsigned mode, void *lock); +}; + +/** Sets a group of functions that Libevent should use for locking. + * For full information on the required callback API, see the + * documentation for the individual members of evthread_lock_callbacks. + * + * Note that if you're using Windows or the Pthreads threading library, you + * probably shouldn't call this function; instead, use + * evthread_use_windows_threads() or evthread_use_posix_threads() if you can. + */ +EVENT2_EXPORT_SYMBOL +int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *); + +#define EVTHREAD_CONDITION_API_VERSION 1 + +struct timeval; + +/** This structure describes the interface a threading library uses for + * condition variables. It's used to tell evthread_set_condition_callbacks + * how to use locking on this platform. + */ +struct evthread_condition_callbacks { + /** The current version of the conditions API. Set this to + * EVTHREAD_CONDITION_API_VERSION */ + int condition_api_version; + /** Function to allocate and initialize a new condition variable. + * Returns the condition variable on success, and NULL on failure. + * The 'condtype' argument will be 0 with this API version. + */ + void *(*alloc_condition)(unsigned condtype); + /** Function to free a condition variable. */ + void (*free_condition)(void *cond); + /** Function to signal a condition variable. If 'broadcast' is 1, all + * threads waiting on 'cond' should be woken; otherwise, only on one + * thread is worken. Should return 0 on success, -1 on failure. + * This function will only be called while holding the associated + * lock for the condition. + */ + int (*signal_condition)(void *cond, int broadcast); + /** Function to wait for a condition variable. The lock 'lock' + * will be held when this function is called; should be released + * while waiting for the condition to be come signalled, and + * should be held again when this function returns. + * If timeout is provided, it is interval of seconds to wait for + * the event to become signalled; if it is NULL, the function + * should wait indefinitely. + * + * The function should return -1 on error; 0 if the condition + * was signalled, or 1 on a timeout. */ + int (*wait_condition)(void *cond, void *lock, + const struct timeval *timeout); +}; + +/** Sets a group of functions that Libevent should use for condition variables. + * For full information on the required callback API, see the + * documentation for the individual members of evthread_condition_callbacks. + * + * Note that if you're using Windows or the Pthreads threading library, you + * probably shouldn't call this function; instead, use + * evthread_use_windows_threads() or evthread_use_pthreads() if you can. + */ +EVENT2_EXPORT_SYMBOL +int evthread_set_condition_callbacks( + const struct evthread_condition_callbacks *); + +/** + Sets the function for determining the thread id. + + @param id_fn the identify function Libevent should invoke to + determine the identity of a thread. +*/ +EVENT2_EXPORT_SYMBOL +void evthread_set_id_callback( + unsigned long (*id_fn)(void)); + +#if (defined(_WIN32) && !defined(EVENT__DISABLE_THREAD_SUPPORT)) || defined(EVENT_IN_DOXYGEN_) +/** Sets up Libevent for use with Windows builtin locking and thread ID + functions. Unavailable if Libevent is not built for Windows. + + @return 0 on success, -1 on failure. */ +EVENT2_EXPORT_SYMBOL +int evthread_use_windows_threads(void); +/** + Defined if Libevent was built with support for evthread_use_windows_threads() +*/ +#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 1 +#endif + +#if defined(EVENT__HAVE_PTHREADS) || defined(EVENT_IN_DOXYGEN_) +/** Sets up Libevent for use with Pthreads locking and thread ID functions. + Unavailable if Libevent is not build for use with pthreads. Requires + libraries to link against Libevent_pthreads as well as Libevent. + + @return 0 on success, -1 on failure. */ +EVENT2_EXPORT_SYMBOL +int evthread_use_pthreads(void); + +/* Enables posix mutex priority inheritance + * (if pthread_mutexattr_setprotocol() is supported). */ +#define EVTHREAD_PTHREAD_PRIO_INHERIT 0x01 + +/** + * Sets up Libevent for use with Pthreads locking and thread ID functions. + * Use evthread_use_pthreads_with_flags() to use Pthreads locking, taking the + * specified flags under consideration. + * + * @param flags the flags to apply when setting up Pthreads locking. @see EVTHREAD_PTHREAD_* + * @return 0 on success, -1 on failure. + **/ +EVENT2_EXPORT_SYMBOL +int evthread_use_pthreads_with_flags(int flags); + +/** Defined if Libevent was built with support for evthread_use_pthreads() */ +#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1 + +#endif + +/** Enable debugging wrappers around the current lock callbacks. If Libevent + * makes one of several common locking errors, exit with an assertion failure. + * + * If you're going to call this function, you must do so before any locks are + * allocated. + **/ +EVENT2_EXPORT_SYMBOL +void evthread_enable_lock_debugging(void); + +/* Old (misspelled) version: This is deprecated; use + * evthread_enable_log_debugging instead. */ +EVENT2_EXPORT_SYMBOL +void evthread_enable_lock_debuging(void); + +#endif /* EVENT__DISABLE_THREAD_SUPPORT */ + +struct event_base; +/** Make sure it's safe to tell an event base to wake up from another thread + or a signal handler. + + You shouldn't need to call this by hand; configuring the base with thread + support should be necessary and sufficient. + + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evthread_make_base_notifiable(struct event_base *base); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_THREAD_H_INCLUDED_ */ diff --git a/include/libevent/event2/util.h b/include/libevent/event2/util.h new file mode 100644 index 0000000..60ff4cc --- /dev/null +++ b/include/libevent/event2/util.h @@ -0,0 +1,888 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_UTIL_H_INCLUDED_ +#define EVENT2_UTIL_H_INCLUDED_ + +/** @file event2/util.h + + @brief Common convenience functions for cross-platform portability and + related socket manipulations. + + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif +#ifdef EVENT__HAVE_STDINT_H +#include +#elif defined(EVENT__HAVE_INTTYPES_H) +#include +#endif +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_STDDEF_H +#include +#endif +#ifdef _MSC_VER +#include +#endif +#include +#ifdef EVENT__HAVE_NETDB_H +#include +#endif + +#ifdef _WIN32 +#include +#ifdef EVENT__HAVE_GETADDRINFO +/* for EAI_* definitions. */ +#include +#endif +#else +#ifdef EVENT__HAVE_ERRNO_H +#include +#endif +#include +#endif + +#include + +/* Some openbsd autoconf versions get the name of this macro wrong. */ +#if defined(EVENT__SIZEOF_VOID__) && !defined(EVENT__SIZEOF_VOID_P) +#define EVENT__SIZEOF_VOID_P EVENT__SIZEOF_VOID__ +#endif + +/** + * @name Standard integer types. + * + * Integer type definitions for types that are supposed to be defined in the + * C99-specified stdint.h. Shamefully, some platforms do not include + * stdint.h, so we need to replace it. (If you are on a platform like this, + * your C headers are now over 10 years out of date. You should bug them to + * do something about this.) + * + * We define: + * + *
+ *
ev_uint64_t, ev_uint32_t, ev_uint16_t, ev_uint8_t
+ *
unsigned integer types of exactly 64, 32, 16, and 8 bits + * respectively.
+ *
ev_int64_t, ev_int32_t, ev_int16_t, ev_int8_t
+ *
signed integer types of exactly 64, 32, 16, and 8 bits + * respectively.
+ *
ev_uintptr_t, ev_intptr_t
+ *
unsigned/signed integers large enough + * to hold a pointer without loss of bits.
+ *
ev_ssize_t
+ *
A signed type of the same size as size_t
+ *
ev_off_t
+ *
A signed type typically used to represent offsets within a + * (potentially large) file
+ * + * @{ + */ +#ifdef EVENT__HAVE_UINT64_T +#define ev_uint64_t uint64_t +#define ev_int64_t int64_t +#elif defined(_WIN32) +#define ev_uint64_t unsigned __int64 +#define ev_int64_t signed __int64 +#elif EVENT__SIZEOF_LONG_LONG == 8 +#define ev_uint64_t unsigned long long +#define ev_int64_t long long +#elif EVENT__SIZEOF_LONG == 8 +#define ev_uint64_t unsigned long +#define ev_int64_t long +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint64_t ... +#define ev_int64_t ... +#else +#error "No way to define ev_uint64_t" +#endif + +#ifdef EVENT__HAVE_UINT32_T +#define ev_uint32_t uint32_t +#define ev_int32_t int32_t +#elif defined(_WIN32) +#define ev_uint32_t unsigned int +#define ev_int32_t signed int +#elif EVENT__SIZEOF_LONG == 4 +#define ev_uint32_t unsigned long +#define ev_int32_t signed long +#elif EVENT__SIZEOF_INT == 4 +#define ev_uint32_t unsigned int +#define ev_int32_t signed int +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint32_t ... +#define ev_int32_t ... +#else +#error "No way to define ev_uint32_t" +#endif + +#ifdef EVENT__HAVE_UINT16_T +#define ev_uint16_t uint16_t +#define ev_int16_t int16_t +#elif defined(_WIN32) +#define ev_uint16_t unsigned short +#define ev_int16_t signed short +#elif EVENT__SIZEOF_INT == 2 +#define ev_uint16_t unsigned int +#define ev_int16_t signed int +#elif EVENT__SIZEOF_SHORT == 2 +#define ev_uint16_t unsigned short +#define ev_int16_t signed short +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint16_t ... +#define ev_int16_t ... +#else +#error "No way to define ev_uint16_t" +#endif + +#ifdef EVENT__HAVE_UINT8_T +#define ev_uint8_t uint8_t +#define ev_int8_t int8_t +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint8_t ... +#define ev_int8_t ... +#else +#define ev_uint8_t unsigned char +#define ev_int8_t signed char +#endif + +#ifdef EVENT__HAVE_UINTPTR_T +#define ev_uintptr_t uintptr_t +#define ev_intptr_t intptr_t +#elif EVENT__SIZEOF_VOID_P <= 4 +#define ev_uintptr_t ev_uint32_t +#define ev_intptr_t ev_int32_t +#elif EVENT__SIZEOF_VOID_P <= 8 +#define ev_uintptr_t ev_uint64_t +#define ev_intptr_t ev_int64_t +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uintptr_t ... +#define ev_intptr_t ... +#else +#error "No way to define ev_uintptr_t" +#endif + +#ifdef EVENT__ssize_t +#define ev_ssize_t EVENT__ssize_t +#else +#define ev_ssize_t ssize_t +#endif + +/* Note that we define ev_off_t based on the compile-time size of off_t that + * we used to build Libevent, and not based on the current size of off_t. + * (For example, we don't define ev_off_t to off_t.). We do this because + * some systems let you build your software with different off_t sizes + * at runtime, and so putting in any dependency on off_t would risk API + * mismatch. + */ +#ifdef _WIN32 +#define ev_off_t ev_int64_t +#elif EVENT__SIZEOF_OFF_T == 8 +#define ev_off_t ev_int64_t +#elif EVENT__SIZEOF_OFF_T == 4 +#define ev_off_t ev_int32_t +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_off_t ... +#else +#define ev_off_t off_t +#endif +/**@}*/ + +/* Limits for integer types. + + We're making two assumptions here: + - The compiler does constant folding properly. + - The platform does signed arithmetic in two's complement. +*/ + +/** + @name Limits for integer types + + These macros hold the largest or smallest values possible for the + ev_[u]int*_t types. + + @{ +*/ +#ifndef EVENT__HAVE_STDINT_H +#define EV_UINT64_MAX ((((ev_uint64_t)0xffffffffUL) << 32) | 0xffffffffUL) +#define EV_INT64_MAX ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL) +#define EV_INT64_MIN ((-EV_INT64_MAX) - 1) +#define EV_UINT32_MAX ((ev_uint32_t)0xffffffffUL) +#define EV_INT32_MAX ((ev_int32_t) 0x7fffffffL) +#define EV_INT32_MIN ((-EV_INT32_MAX) - 1) +#define EV_UINT16_MAX ((ev_uint16_t)0xffffUL) +#define EV_INT16_MAX ((ev_int16_t) 0x7fffL) +#define EV_INT16_MIN ((-EV_INT16_MAX) - 1) +#define EV_UINT8_MAX 255 +#define EV_INT8_MAX 127 +#define EV_INT8_MIN ((-EV_INT8_MAX) - 1) +#else +#define EV_UINT64_MAX UINT64_MAX +#define EV_INT64_MAX INT64_MAX +#define EV_INT64_MIN INT64_MIN +#define EV_UINT32_MAX UINT32_MAX +#define EV_INT32_MAX INT32_MAX +#define EV_INT32_MIN INT32_MIN +#define EV_UINT16_MAX UINT16_MAX +#define EV_INT16_MIN INT16_MIN +#define EV_INT16_MAX INT16_MAX +#define EV_UINT8_MAX UINT8_MAX +#define EV_INT8_MAX INT8_MAX +#define EV_INT8_MIN INT8_MIN +/** @} */ +#endif + + +/** + @name Limits for SIZE_T and SSIZE_T + + @{ +*/ +#if EVENT__SIZEOF_SIZE_T == 8 +#define EV_SIZE_MAX EV_UINT64_MAX +#define EV_SSIZE_MAX EV_INT64_MAX +#elif EVENT__SIZEOF_SIZE_T == 4 +#define EV_SIZE_MAX EV_UINT32_MAX +#define EV_SSIZE_MAX EV_INT32_MAX +#elif defined(EVENT_IN_DOXYGEN_) +#define EV_SIZE_MAX ... +#define EV_SSIZE_MAX ... +#else +#error "No way to define SIZE_MAX" +#endif + +#define EV_SSIZE_MIN ((-EV_SSIZE_MAX) - 1) +/**@}*/ + +#ifdef _WIN32 +#define ev_socklen_t int +#elif defined(EVENT__socklen_t) +#define ev_socklen_t EVENT__socklen_t +#else +#define ev_socklen_t socklen_t +#endif + +#ifdef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY +#if !defined(EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY) \ + && !defined(ss_family) +#define ss_family __ss_family +#endif +#endif + +/** + * A type wide enough to hold the output of "socket()" or "accept()". On + * Windows, this is an intptr_t; elsewhere, it is an int. */ +#ifdef _WIN32 +#define evutil_socket_t intptr_t +#else +#define evutil_socket_t int +#endif + +/** + * Structure to hold information about a monotonic timer + * + * Use this with evutil_configure_monotonic_time() and + * evutil_gettime_monotonic(). + * + * This is an opaque structure; you can allocate one using + * evutil_monotonic_timer_new(). + * + * @see evutil_monotonic_timer_new(), evutil_monotonic_timer_free(), + * evutil_configure_monotonic_time(), evutil_gettime_monotonic() + */ +struct evutil_monotonic_timer +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +#define EV_MONOT_PRECISE 1 +#define EV_MONOT_FALLBACK 2 + +/** Format a date string using RFC 1123 format (used in HTTP). + * If `tm` is NULL, current system's time will be used. + * The number of characters written will be returned. + * One should check if the return value is smaller than `datelen` to check if + * the result is truncated or not. + */ +EVENT2_EXPORT_SYMBOL int +evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm); + +/** Allocate a new struct evutil_monotonic_timer for use with the + * evutil_configure_monotonic_time() and evutil_gettime_monotonic() + * functions. You must configure the timer with + * evutil_configure_monotonic_time() before using it. + */ +EVENT2_EXPORT_SYMBOL +struct evutil_monotonic_timer * evutil_monotonic_timer_new(void); + +/** Free a struct evutil_monotonic_timer that was allocated using + * evutil_monotonic_timer_new(). + */ +EVENT2_EXPORT_SYMBOL +void evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer); + +/** Set up a struct evutil_monotonic_timer; flags can include + * EV_MONOT_PRECISE and EV_MONOT_FALLBACK. + */ +EVENT2_EXPORT_SYMBOL +int evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer, + int flags); + +/** Query the current monotonic time from a struct evutil_monotonic_timer + * previously configured with evutil_configure_monotonic_time(). Monotonic + * time is guaranteed never to run in reverse, but is not necessarily epoch- + * based, or relative to any other definite point. Use it to make reliable + * measurements of elapsed time between events even when the system time + * may be changed. + * + * It is not safe to use this funtion on the same timer from multiple + * threads_. + */ +EVENT2_EXPORT_SYMBOL +int evutil_gettime_monotonic(struct evutil_monotonic_timer *timer, + struct timeval *tp); + +/** Create two new sockets that are connected to each other. + + On Unix, this simply calls socketpair(). On Windows, it uses the + loopback network interface on 127.0.0.1, and only + AF_INET,SOCK_STREAM are supported. + + (This may fail on some Windows hosts where firewall software has cleverly + decided to keep 127.0.0.1 from talking to itself.) + + Parameters and return values are as for socketpair() +*/ +EVENT2_EXPORT_SYMBOL +int evutil_socketpair(int d, int type, int protocol, evutil_socket_t sv[2]); +/** Do platform-specific operations as needed to make a socket nonblocking. + + @param sock The socket to make nonblocking + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_socket_nonblocking(evutil_socket_t sock); + +/** Do platform-specific operations to make a listener socket reusable. + + Specifically, we want to make sure that another program will be able + to bind this address right after we've closed the listener. + + This differs from Windows's interpretation of "reusable", which + allows multiple listeners to bind the same address at the same time. + + @param sock The socket to make reusable + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_listen_socket_reuseable(evutil_socket_t sock); + +/** Do platform-specific operations to make a listener port reusable. + + Specifically, we want to make sure that multiple programs which also + set the same socket option will be able to bind, listen at the same time. + + This is a feature available only to Linux 3.9+ + + @param sock The socket to make reusable + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_listen_socket_reuseable_port(evutil_socket_t sock); + +/** Set ipv6 only bind socket option to make listener work only in ipv6 sockets. + + According to RFC3493 and most Linux distributions, default value for the + sockets is to work in IPv4-mapped mode. In IPv4-mapped mode, it is not possible + to bind same port from different IPv4 and IPv6 handlers. + + @param sock The socket to make in ipv6only working mode + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_listen_socket_ipv6only(evutil_socket_t sock); + +/** Do platform-specific operations as needed to close a socket upon a + successful execution of one of the exec*() functions. + + @param sock The socket to be closed + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_socket_closeonexec(evutil_socket_t sock); + +/** Do the platform-specific call needed to close a socket returned from + socket() or accept(). + + @param sock The socket to be closed + @return 0 on success (whether the operation is supported or not), + -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_closesocket(evutil_socket_t sock); +#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s) + +/** Do platform-specific operations, if possible, to make a tcp listener + * socket defer accept()s until there is data to read. + * + * Not all platforms support this. You don't want to do this for every + * listener socket: only the ones that implement a protocol where the + * client transmits before the server needs to respond. + * + * @param sock The listening socket to to make deferred + * @return 0 on success (whether the operation is supported or not), + * -1 on failure +*/ +EVENT2_EXPORT_SYMBOL +int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock); + +#ifdef _WIN32 +/** Return the most recent socket error. Not idempotent on all platforms. */ +#define EVUTIL_SOCKET_ERROR() WSAGetLastError() +/** Replace the most recent socket error with errcode */ +#define EVUTIL_SET_SOCKET_ERROR(errcode) \ + do { WSASetLastError(errcode); } while (0) +/** Return the most recent socket error to occur on sock. */ +EVENT2_EXPORT_SYMBOL +int evutil_socket_geterror(evutil_socket_t sock); +/** Convert a socket error to a string. */ +EVENT2_EXPORT_SYMBOL +const char *evutil_socket_error_to_string(int errcode); +#define EVUTIL_INVALID_SOCKET INVALID_SOCKET +#elif defined(EVENT_IN_DOXYGEN_) +/** + @name Socket error functions + + These functions are needed for making programs compatible between + Windows and Unix-like platforms. + + You see, Winsock handles socket errors differently from the rest of + the world. Elsewhere, a socket error is like any other error and is + stored in errno. But winsock functions require you to retrieve the + error with a special function, and don't let you use strerror for + the error codes. And handling EWOULDBLOCK is ... different. + + @{ +*/ +/** Return the most recent socket error. Not idempotent on all platforms. */ +#define EVUTIL_SOCKET_ERROR() ... +/** Replace the most recent socket error with errcode */ +#define EVUTIL_SET_SOCKET_ERROR(errcode) ... +/** Return the most recent socket error to occur on sock. */ +#define evutil_socket_geterror(sock) ... +/** Convert a socket error to a string. */ +#define evutil_socket_error_to_string(errcode) ... +#define EVUTIL_INVALID_SOCKET -1 +/**@}*/ +#else /** !EVENT_IN_DOXYGEN_ && !_WIN32 */ +#define EVUTIL_SOCKET_ERROR() (errno) +#define EVUTIL_SET_SOCKET_ERROR(errcode) \ + do { errno = (errcode); } while (0) +#define evutil_socket_geterror(sock) (errno) +#define evutil_socket_error_to_string(errcode) (strerror(errcode)) +#define EVUTIL_INVALID_SOCKET -1 +#endif /** !_WIN32 */ + + +/** + * @name Manipulation macros for struct timeval. + * + * We define replacements + * for timeradd, timersub, timerclear, timercmp, and timerisset. + * + * @{ + */ +#ifdef EVENT__HAVE_TIMERADD +#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp)) +#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp)) +#else +#define evutil_timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define evutil_timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /* !EVENT__HAVE_TIMERADD */ + +#ifdef EVENT__HAVE_TIMERCLEAR +#define evutil_timerclear(tvp) timerclear(tvp) +#else +#define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif +/**@}*/ + +/** Return true iff the tvp is related to uvp according to the relational + * operator cmp. Recognized values for cmp are ==, <=, <, >=, and >. */ +#define evutil_timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) + +#ifdef EVENT__HAVE_TIMERISSET +#define evutil_timerisset(tvp) timerisset(tvp) +#else +#define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#endif + +/** Replacement for offsetof on platforms that don't define it. */ +#ifdef offsetof +#define evutil_offsetof(type, field) offsetof(type, field) +#else +#define evutil_offsetof(type, field) ((off_t)(&((type *)0)->field)) +#endif + +/* big-int related functions */ +/** Parse a 64-bit value from a string. Arguments are as for strtol. */ +EVENT2_EXPORT_SYMBOL +ev_int64_t evutil_strtoll(const char *s, char **endptr, int base); + +/** Replacement for gettimeofday on platforms that lack it. */ +#ifdef EVENT__HAVE_GETTIMEOFDAY +#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz)) +#else +struct timezone; +EVENT2_EXPORT_SYMBOL +int evutil_gettimeofday(struct timeval *tv, struct timezone *tz); +#endif + +/** Replacement for snprintf to get consistent behavior on platforms for + which the return value of snprintf does not conform to C99. + */ +EVENT2_EXPORT_SYMBOL +int evutil_snprintf(char *buf, size_t buflen, const char *format, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) +#endif +; +/** Replacement for vsnprintf to get consistent behavior on platforms for + which the return value of snprintf does not conform to C99. + */ +EVENT2_EXPORT_SYMBOL +int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap) +#ifdef __GNUC__ + __attribute__((format(printf, 3, 0))) +#endif +; + +/** Replacement for inet_ntop for platforms which lack it. */ +EVENT2_EXPORT_SYMBOL +const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len); +/** Variation of inet_pton that also parses IPv6 scopes. Public for + unit tests. No reason to call this directly. + */ +EVENT2_EXPORT_SYMBOL +int evutil_inet_pton_scope(int af, const char *src, void *dst, + unsigned *indexp); +/** Replacement for inet_pton for platforms which lack it. */ +EVENT2_EXPORT_SYMBOL +int evutil_inet_pton(int af, const char *src, void *dst); +struct sockaddr; + +/** Parse an IPv4 or IPv6 address, with optional port, from a string. + + Recognized formats are: + - [IPv6Address]:port + - [IPv6Address] + - IPv6Address + - IPv4Address:port + - IPv4Address + + If no port is specified, the port in the output is set to 0. + + @param str The string to parse. + @param out A struct sockaddr to hold the result. This should probably be + a struct sockaddr_storage. + @param outlen A pointer to the number of bytes that that 'out' can safely + hold. Set to the number of bytes used in 'out' on success. + @return -1 if the address is not well-formed, if the port is out of range, + or if out is not large enough to hold the result. Otherwise returns + 0 on success. +*/ +EVENT2_EXPORT_SYMBOL +int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int *outlen); + +/** Compare two sockaddrs; return 0 if they are equal, or less than 0 if sa1 + * preceeds sa2, or greater than 0 if sa1 follows sa2. If include_port is + * true, consider the port as well as the address. Only implemented for + * AF_INET and AF_INET6 addresses. The ordering is not guaranteed to remain + * the same between Libevent versions. */ +EVENT2_EXPORT_SYMBOL +int evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2, + int include_port); + +/** As strcasecmp, but always compares the characters in locale-independent + ASCII. That's useful if you're handling data in ASCII-based protocols. + */ +EVENT2_EXPORT_SYMBOL +int evutil_ascii_strcasecmp(const char *str1, const char *str2); +/** As strncasecmp, but always compares the characters in locale-independent + ASCII. That's useful if you're handling data in ASCII-based protocols. + */ +EVENT2_EXPORT_SYMBOL +int evutil_ascii_strncasecmp(const char *str1, const char *str2, size_t n); + +/* Here we define evutil_addrinfo to the native addrinfo type, or redefine it + * if this system has no getaddrinfo(). */ +#ifdef EVENT__HAVE_STRUCT_ADDRINFO +#define evutil_addrinfo addrinfo +#else +/** A definition of struct addrinfo for systems that lack it. + + (This is just an alias for struct addrinfo if the system defines + struct addrinfo.) +*/ +struct evutil_addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for nodename */ + struct sockaddr *ai_addr; /* binary address */ + struct evutil_addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +/** @name evutil_getaddrinfo() error codes + + These values are possible error codes for evutil_getaddrinfo() and + related functions. + + @{ +*/ +#if defined(EAI_ADDRFAMILY) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_ADDRFAMILY EAI_ADDRFAMILY +#else +#define EVUTIL_EAI_ADDRFAMILY -901 +#endif +#if defined(EAI_AGAIN) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_AGAIN EAI_AGAIN +#else +#define EVUTIL_EAI_AGAIN -902 +#endif +#if defined(EAI_BADFLAGS) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_BADFLAGS EAI_BADFLAGS +#else +#define EVUTIL_EAI_BADFLAGS -903 +#endif +#if defined(EAI_FAIL) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_FAIL EAI_FAIL +#else +#define EVUTIL_EAI_FAIL -904 +#endif +#if defined(EAI_FAMILY) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_FAMILY EAI_FAMILY +#else +#define EVUTIL_EAI_FAMILY -905 +#endif +#if defined(EAI_MEMORY) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_MEMORY EAI_MEMORY +#else +#define EVUTIL_EAI_MEMORY -906 +#endif +/* This test is a bit complicated, since some MS SDKs decide to + * remove NODATA or redefine it to be the same as NONAME, in a + * fun interpretation of RFC 2553 and RFC 3493. */ +#if defined(EAI_NODATA) && defined(EVENT__HAVE_GETADDRINFO) && (!defined(EAI_NONAME) || EAI_NODATA != EAI_NONAME) +#define EVUTIL_EAI_NODATA EAI_NODATA +#else +#define EVUTIL_EAI_NODATA -907 +#endif +#if defined(EAI_NONAME) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_NONAME EAI_NONAME +#else +#define EVUTIL_EAI_NONAME -908 +#endif +#if defined(EAI_SERVICE) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_SERVICE EAI_SERVICE +#else +#define EVUTIL_EAI_SERVICE -909 +#endif +#if defined(EAI_SOCKTYPE) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_SOCKTYPE EAI_SOCKTYPE +#else +#define EVUTIL_EAI_SOCKTYPE -910 +#endif +#if defined(EAI_SYSTEM) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_SYSTEM EAI_SYSTEM +#else +#define EVUTIL_EAI_SYSTEM -911 +#endif + +#define EVUTIL_EAI_CANCEL -90001 + +#if defined(AI_PASSIVE) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_PASSIVE AI_PASSIVE +#else +#define EVUTIL_AI_PASSIVE 0x1000 +#endif +#if defined(AI_CANONNAME) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_CANONNAME AI_CANONNAME +#else +#define EVUTIL_AI_CANONNAME 0x2000 +#endif +#if defined(AI_NUMERICHOST) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_NUMERICHOST AI_NUMERICHOST +#else +#define EVUTIL_AI_NUMERICHOST 0x4000 +#endif +#if defined(AI_NUMERICSERV) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_NUMERICSERV AI_NUMERICSERV +#else +#define EVUTIL_AI_NUMERICSERV 0x8000 +#endif +#if defined(AI_V4MAPPED) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_V4MAPPED AI_V4MAPPED +#else +#define EVUTIL_AI_V4MAPPED 0x10000 +#endif +#if defined(AI_ALL) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_ALL AI_ALL +#else +#define EVUTIL_AI_ALL 0x20000 +#endif +#if defined(AI_ADDRCONFIG) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_ADDRCONFIG AI_ADDRCONFIG +#else +#define EVUTIL_AI_ADDRCONFIG 0x40000 +#endif +/**@}*/ + +struct evutil_addrinfo; +/** + * This function clones getaddrinfo for systems that don't have it. For full + * details, see RFC 3493, section 6.1. + * + * Limitations: + * - When the system has no getaddrinfo, we fall back to gethostbyname_r or + * gethostbyname, with their attendant issues. + * - The AI_V4MAPPED and AI_ALL flags are not currently implemented. + * + * For a nonblocking variant, see evdns_getaddrinfo. + */ +EVENT2_EXPORT_SYMBOL +int evutil_getaddrinfo(const char *nodename, const char *servname, + const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res); + +/** Release storage allocated by evutil_getaddrinfo or evdns_getaddrinfo. */ +EVENT2_EXPORT_SYMBOL +void evutil_freeaddrinfo(struct evutil_addrinfo *ai); + +EVENT2_EXPORT_SYMBOL +const char *evutil_gai_strerror(int err); + +/** Generate n bytes of secure pseudorandom data, and store them in buf. + * + * Current versions of Libevent use an ARC4-based random number generator, + * seeded using the platform's entropy source (/dev/urandom on Unix-like + * systems; BCryptGenRandom on Windows). This is not actually as secure as it + * should be: ARC4 is a pretty lousy cipher, and the current implementation + * provides only rudimentary prediction- and backtracking-resistance. Don't + * use this for serious cryptographic applications. + */ +EVENT2_EXPORT_SYMBOL +void evutil_secure_rng_get_bytes(void *buf, size_t n); + +/** + * Seed the secure random number generator if needed, and return 0 on + * success or -1 on failure. + * + * It is okay to call this function more than once; it will still return + * 0 if the RNG has been successfully seeded and -1 if it can't be + * seeded. + * + * Ordinarily you don't need to call this function from your own code; + * Libevent will seed the RNG itself the first time it needs good random + * numbers. You only need to call it if (a) you want to double-check + * that one of the seeding methods did succeed, or (b) you plan to drop + * the capability to seed (by chrooting, or dropping capabilities, or + * whatever), and you want to make sure that seeding happens before your + * program loses the ability to do it. + */ +EVENT2_EXPORT_SYMBOL +int evutil_secure_rng_init(void); + +/** + * Set a filename to use in place of /dev/urandom for seeding the secure + * PRNG. Return 0 on success, -1 on failure. + * + * Call this function BEFORE calling any other initialization or RNG + * functions. + * + * (This string will _NOT_ be copied internally. Do not free it while any + * user of the secure RNG might be running. Don't pass anything other than a + * real /dev/...random device file here, or you might lose security.) + * + * This API is unstable, and might change in a future libevent version. + */ +EVENT2_EXPORT_SYMBOL +int evutil_secure_rng_set_urandom_device_file(char *fname); + +#if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM) +/** Seed the random number generator with extra random bytes. + + You should almost never need to call this function; it should be + sufficient to invoke evutil_secure_rng_init(), or let Libevent take + care of calling evutil_secure_rng_init() on its own. + + If you call this function as a _replacement_ for the regular + entropy sources, then you need to be sure that your input + contains a fairly large amount of strong entropy. Doing so is + notoriously hard: most people who try get it wrong. Watch out! + + @param dat a buffer full of a strong source of random numbers + @param datlen the number of bytes to read from datlen + */ +EVENT2_EXPORT_SYMBOL +void evutil_secure_rng_add_bytes(const char *dat, size_t datlen); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT1_EVUTIL_H_INCLUDED_ */ diff --git a/include/libevent/event2/visibility.h b/include/libevent/event2/visibility.h new file mode 100644 index 0000000..2b07994 --- /dev/null +++ b/include/libevent/event2/visibility.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_VISIBILITY_H_INCLUDED_ +#define EVENT2_VISIBILITY_H_INCLUDED_ + +#include + +#if defined(event_shared_EXPORTS) || \ + defined(event_extra_shared_EXPORTS) || \ + defined(event_core_shared_EXPORTS) || \ + defined(event_pthreads_shared_EXPORTS) || \ + defined(event_openssl_shared_EXPORTS) || \ + defined(event_mbedtls_shared_EXPORTS) + +# if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550) +# define EVENT2_EXPORT_SYMBOL __global +# elif defined __GNUC__ +# define EVENT2_EXPORT_SYMBOL __attribute__ ((visibility("default"))) +# elif defined(_MSC_VER) +# define EVENT2_EXPORT_SYMBOL __declspec(dllexport) +# else +# define EVENT2_EXPORT_SYMBOL /* unknown compiler */ +# endif + +#else /* event_*_EXPORTS */ + +# define EVENT2_EXPORT_SYMBOL + +#endif /* event_*_EXPORTS */ + +/** We need to dllimport event_debug_logging_mask_ into event_extra */ +#if defined(_MSC_VER) +# if defined(event_core_shared_EXPORTS) /** from core export */ +# define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllexport) +# elif defined(event_extra_shared_EXPORTS) || /** from extra import */ \ + defined(EVENT_VISIBILITY_WANT_DLLIMPORT) +# define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllimport) +# endif +#endif /* _MSC_VER */ +#if !defined(EVENT2_CORE_EXPORT_SYMBOL) +# define EVENT2_CORE_EXPORT_SYMBOL EVENT2_EXPORT_SYMBOL +#endif + +#endif /* EVENT2_VISIBILITY_H_INCLUDED_ */ diff --git a/include/libevent/event2/watch.h b/include/libevent/event2/watch.h new file mode 100644 index 0000000..90007aa --- /dev/null +++ b/include/libevent/event2/watch.h @@ -0,0 +1,136 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_WATCH_H_INCLUDED_ +#define EVENT2_WATCH_H_INCLUDED_ + +/** @file event2/watch.h + + @brief "Prepare" and "check" watchers. + + "Prepare" and "check" watchers. A "prepare" watcher is a callback that fires + immediately before polling for I/O. A "check" watcher is a callback that + fires immediately after polling and before processing any active events. This + may be useful for embedding other libraries' event loops (e.g. UI toolkits) + into libevent's. + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct event_base; +struct evwatch; +struct evwatch_prepare_cb_info; +struct evwatch_check_cb_info; +struct timeval; + +/** + Prepare callback, invoked by event_base_loop immediately before polling for + I/O. + + @param watcher the prepare watcher that invoked this callback. + @param info contextual information passed from event_base_loop. + @param arg additional user-defined argument, set in `evwatch_prepare_new`. + */ +typedef void (*evwatch_prepare_cb)(struct evwatch *, const struct evwatch_prepare_cb_info *, void *); + +/** + Check callback, invoked by event_base_loop immediately after polling for I/O + and before processing any active events. + + @param watcher the check watcher that invoked this callback. + @param info contextual information passed from event_base_loop. + @param arg additional user-defined argument, set in `evwatch_check_new`. + */ +typedef void (*evwatch_check_cb)(struct evwatch *, const struct evwatch_check_cb_info *, void *); + +/** + Register a new "prepare" watcher, to be called in the event loop prior to + polling for events. Watchers will be called in the order they were + registered. + + @param base the event_base to operate on. + @param callback the callback function to invoke. + @param arg additional user-defined argument provided to the callback. + @return a pointer to the newly allocated event watcher. + */ +EVENT2_EXPORT_SYMBOL +struct evwatch *evwatch_prepare_new(struct event_base *base, evwatch_prepare_cb callback, void *arg); + +/** + Register a new "check" watcher, to be called in the event loop after polling + for events and before handling them. Watchers will be called in the order + they were registered. + + @param base the event_base to operate on. + @param callback the callback function to invoke. + @param arg additional user-defined argument provided to the callback. + @return a pointer to the newly allocated event watcher. + */ +EVENT2_EXPORT_SYMBOL +struct evwatch *evwatch_check_new(struct event_base *base, evwatch_check_cb callback, void *arg); + +/** + Get the event_base that a given evwatch is registered with. + + @param watcher the watcher to get the event_base for. + @return the event_base for the given watcher. + */ +EVENT2_EXPORT_SYMBOL +struct event_base *evwatch_base(struct evwatch *watcher); + +/** + Deregister and deallocate a watcher. Any watchers not freed using + evwatch_free will eventually be deallocated in event_base_free + (calling evwatch_free on a watcher after event_base_free has been + called on its corresponding event_base is an error). + + @param watcher the watcher to deregister and deallocate. + */ +EVENT2_EXPORT_SYMBOL +void evwatch_free(struct evwatch *watcher); + +/** + Get the timeout (the expected polling duration) passed to the underlying + implementation's `dispatch`. This value will only be set if there are pending + EV_TIMEOUT events and if the event_base isn't in EVLOOP_NONBLOCK mode. It may + be a useful performance statistic to compare the expected polling duration + against the actual polling duration (that is, the time difference measured + between this prepare callback and the following check callback). + + @param info the "prepare" callback info. + @param timeout address of a timeval to write the polling duration to. + @return 1 if a value was written to *timeout, or 0 if not. + */ +EVENT2_EXPORT_SYMBOL +int evwatch_prepare_get_timeout(const struct evwatch_prepare_cb_info *info, struct timeval *timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_WATCH_H_INCLUDED_ */ diff --git a/include/libevent/event2/ws.h b/include/libevent/event2/ws.h new file mode 100644 index 0000000..11fc2e5 --- /dev/null +++ b/include/libevent/event2/ws.h @@ -0,0 +1,58 @@ +#ifndef EVENT2_WS_H_INCLUDED_ +#define EVENT2_WS_H_INCLUDED_ + +struct evws_connection; + +#define WS_CR_NONE 0 +#define WS_CR_NORMAL 1000 +#define WS_CR_PROTO_ERR 1002 +#define WS_CR_DATA_TOO_BIG 1009 + +#define WS_TEXT_FRAME 0x1 +#define WS_BINARY_FRAME 0x2 + +typedef void (*ws_on_msg_cb)( + struct evws_connection *, int type, const unsigned char *, size_t, void *); +typedef void (*ws_on_close_cb)(struct evws_connection *, void *); + +/** Opens new WebSocket session from HTTP request. + @param req a request object + @param cb the callback function that gets invoked on receiving message + with len bytes length. In case of receiving text messages user is responsible + to make a string with terminating \0 (with copying-out data) or use text data + other way in which \0 is not required + @param arg an additional context argument for the callback + @return a pointer to a newly initialized WebSocket connection or NULL + on error + @see evws_close() + */ +EVENT2_EXPORT_SYMBOL +struct evws_connection *evws_new_session( + struct evhttp_request *req, ws_on_msg_cb, void *arg, int options); + +/** Sends data over WebSocket connection */ +EVENT2_EXPORT_SYMBOL +void evws_send( + struct evws_connection *evws, const char *packet_str, size_t str_len); + +/** Closes a WebSocket connection with reason code */ +EVENT2_EXPORT_SYMBOL +void evws_close(struct evws_connection *evws, uint16_t reason); + +/** Sets a callback for connection close. */ +EVENT2_EXPORT_SYMBOL +void evws_connection_set_closecb( + struct evws_connection *evws, ws_on_close_cb, void *); + +/** Frees a WebSocket connection */ +EVENT2_EXPORT_SYMBOL +void evws_connection_free(struct evws_connection *evws); + +/** + * Return the bufferevent that an evws_connection is using. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *evws_connection_get_bufferevent( + struct evws_connection *evws); + +#endif diff --git a/include/libevent/evhttp.h b/include/libevent/evhttp.h new file mode 100644 index 0000000..549bc9b --- /dev/null +++ b/include/libevent/evhttp.h @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2007 Niels Provos + * Copyright 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVHTTP_H_INCLUDED_ +#define EVENT1_EVHTTP_H_INCLUDED_ + +/** @file evhttp.h + + An http implementation subsystem for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other + headers. + */ + +#include +#include +#include +#include + +#endif /* EVENT1_EVHTTP_H_INCLUDED_ */ diff --git a/include/libevent/evrpc.h b/include/libevent/evrpc.h new file mode 100644 index 0000000..7e986f7 --- /dev/null +++ b/include/libevent/evrpc.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVRPC_H_INCLUDED_ +#define EVENT1_EVRPC_H_INCLUDED_ + +/** @file evrpc.h + + An RPC system for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other + headers. + */ + +#include +#include +#include +#include + +#endif /* EVENT1_EVRPC_H_INCLUDED_ */ diff --git a/include/libevent/evutil.h b/include/libevent/evutil.h new file mode 100644 index 0000000..12c137d --- /dev/null +++ b/include/libevent/evutil.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVUTIL_H_INCLUDED_ +#define EVENT1_EVUTIL_H_INCLUDED_ + +/** @file evutil.h + + Utility and compatibility functions for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. +*/ + +#include + +#endif /* EVENT1_EVUTIL_H_INCLUDED_ */ diff --git a/include/mp/Body.h b/include/mp/Body.h new file mode 100644 index 0000000..fae55e2 --- /dev/null +++ b/include/mp/Body.h @@ -0,0 +1,39 @@ +// +// Created by dongl on 23-4-21. +// + +#ifndef IM2_BODY_H +#define IM2_BODY_H + +#include "proto/mp.body.pb.h" + +class Body { +public: + Body(uint64_t account, const std::string& password) { + body = new mp::body(); + + body->set_account(account); + body->set_password(password); + } + + Body(uint64_t target, uint64_t source, const std::string& data) { + body = new mp::body(); + + body->set_target(target); + body->set_source(source); + body->set_data(data); + } + + Body() { + body = new mp::body(); + } + + virtual ~Body() { + delete body; + } + +protected: + mp::body* body; +}; + +#endif //IM2_BODY_H diff --git a/include/mp/Cqi.h b/include/mp/Cqi.h new file mode 100644 index 0000000..680c543 --- /dev/null +++ b/include/mp/Cqi.h @@ -0,0 +1,31 @@ +// +// Created by dongl on 23-4-21. +// + +#ifndef IM2_CQI_H +#define IM2_CQI_H + +#include "proto/mp.cqi.pb.h" + +class Cqi { +public: + Cqi() { + cqi = new mp::cqi(); + // 后期读配置文件 +#ifdef _WIN32 + cqi->set_cqi_type(mp::MC_TYPE_WINDOWS); +#else + cqi->set_cqi_type(mp::MC_TYPE_LINUX); +#endif + cqi->set_cqi_version(0.01); + } + + virtual ~Cqi() { + delete cqi; + } + +protected: + mp::cqi* cqi; +}; + +#endif //IM2_CQI_H diff --git a/include/mp/EnumMapping.h b/include/mp/EnumMapping.h new file mode 100644 index 0000000..893c882 --- /dev/null +++ b/include/mp/EnumMapping.h @@ -0,0 +1,56 @@ +// +// Created by dongl on 23-4-25. +// + +#ifndef IM2_ENUMMAPPING_H +#define IM2_ENUMMAPPING_H + +#include "proto/mp.mph.pb.h" + + + + +// 定义一个宏来包含需要用到的枚举值 +#define MY_ENUM_VALUES \ + X(MP_REQUEST_LOGIN) \ + X(MP_REQUEST_LOGOUT) \ + X(MP_REQUEST_REGISTER) \ + X(MP_RESPONSE_LOGIN) \ + X(MP_RESPONSE_LOGOUT) \ + X(MP_RESPONSE_REGISTER) + +#if 0 +// method 1 +// 直接定义枚举值 +enum { + SUMMER, + AUTUMN, + WINTER, +}; + +#else + +// method 2 +// 利用宏展开获取并定义枚举 +#undef X +#define X(x) x, +enum { + MY_ENUM_VALUES +}; +#endif + +// 重新定义宏函数并获取新的展开形式,以获取枚举值对应的字符串; +const char *myenumToString(int n) { +#undef X +#define X(x) case (x): { return #x; } +#define MAKE_ENUM_CASES \ + MY_ENUM_VALUES \ + default: { return "unknown enum string."; } + + switch (n) { + MAKE_ENUM_CASES + } +} + + +#endif //IM2_ENUMMAPPING_H diff --git a/include/mp/Mph.h b/include/mp/Mph.h new file mode 100644 index 0000000..30eea18 --- /dev/null +++ b/include/mp/Mph.h @@ -0,0 +1,29 @@ +// +// Created by dongl on 23-4-21. +// + +#ifndef IM2_MPH_H +#define IM2_MPH_H + +#include "proto/mp.mph.pb.h" + + +class Mph { +public: + Mph(mp::MP_TYPE type) { + mph = new mp::mph(); + mph->set_mp_sum(1); + mph->set_mp_id(1); + mph->set_mp_type(type); + mph->set_mpb_size(1); + } + + virtual ~Mph() { + delete mph; + } + +protected: + mp::mph* mph; +}; + +#endif //IM2_MPH_H diff --git a/include/mp/Packet.h b/include/mp/Packet.h new file mode 100644 index 0000000..62e15f3 --- /dev/null +++ b/include/mp/Packet.h @@ -0,0 +1,8 @@ +// +// Created by dongl on 23-4-26. +// + +#ifndef IM2_PACKET_H +#define IM2_PACKET_H + +#endif //IM2_PACKET_H diff --git a/include/mp/Request.h b/include/mp/Request.h new file mode 100644 index 0000000..09c4049 --- /dev/null +++ b/include/mp/Request.h @@ -0,0 +1,31 @@ +// +// Created by dongl on 23-4-21. +// + +#ifndef IM2_REQUEST_H +#define IM2_REQUEST_H + +#include "proto/mp.request.pb.h" +#include "Mph.h" +#include "Body.h" +#include "Cqi.h" + + +class Request : public Mph, Body, Cqi { +public: + Request(mp::MP_TYPE type, uint64_t account, const std::string& password); + + Request(mp::MP_TYPE type, uint64_t target, uint64_t source, const std::string& data); + + ~Request() override; +public: + std::string operator ()(); +private: + void init(); +private: + mp::request* request = nullptr; + char temp[256]{}; +}; + + +#endif //IM2_REQUEST_H diff --git a/include/mp/Response.h b/include/mp/Response.h new file mode 100644 index 0000000..f87e93c --- /dev/null +++ b/include/mp/Response.h @@ -0,0 +1,32 @@ +// +// Created by dongl on 23-4-21. +// + +#ifndef IM2_RESPONSE_H +#define IM2_RESPONSE_H + + + +#include "proto/mp.response.pb.h" +#include "Mph.h" +#include "Body.h" +#include "Sri.h" + +class Response : public Mph, Sri{ +public: + Response(mp::MP_TYPE type, mp::MP_SRI code, const std::string &username, const std::string &msg, const std::string &token); + + ~Response() override; + + std::string operator () (); + std::string packet (); + +private: + void init(); +private: + mp::response* response = nullptr; + char temp[256]{}; +}; + + +#endif //IM2_RESPONSE_H diff --git a/include/mp/Sri.h b/include/mp/Sri.h new file mode 100644 index 0000000..bbf0881 --- /dev/null +++ b/include/mp/Sri.h @@ -0,0 +1,28 @@ +// +// Created by dongl on 23-4-23. +// + +#ifndef IM2_SRI_H +#define IM2_SRI_H + + +#include "proto/mp.sri.pb.h" + +class Sri { +public: + Sri(mp::MP_SRI code, const std::string& username, const std::string& msg, const std::string& token) { + sri = new mp::sri(); + sri->set_sri_code(code); + sri->set_sri_msg(msg); + sri->set_sri_token(token); + sri->set_sri_username(username); + } + + Sri() {} + +public: + mp::sri* sri = nullptr; +}; + + +#endif //IM2_SRI_H diff --git a/include/mp/proto/mp.body.pb.h b/include/mp/proto/mp.body.pb.h new file mode 100644 index 0000000..50ffec6 --- /dev/null +++ b/include/mp/proto/mp.body.pb.h @@ -0,0 +1,524 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.body.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_mp_2ebody_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_mp_2ebody_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3012000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3012004 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_mp_2ebody_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_mp_2ebody_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxillaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2ebody_2eproto; +namespace mp { +class body; +class bodyDefaultTypeInternal; +extern bodyDefaultTypeInternal _body_default_instance_; +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> ::mp::body* Arena::CreateMaybeMessage<::mp::body>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace mp { + +// =================================================================== + +class body PROTOBUF_FINAL : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mp.body) */ { + public: + inline body() : body(nullptr) {}; + virtual ~body(); + + body(const body& from); + body(body&& from) noexcept + : body() { + *this = ::std::move(from); + } + + inline body& operator=(const body& from) { + CopyFrom(from); + return *this; + } + inline body& operator=(body&& from) noexcept { + if (GetArena() == from.GetArena()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return GetMetadataStatic().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return GetMetadataStatic().reflection; + } + static const body& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const body* internal_default_instance() { + return reinterpret_cast( + &_body_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(body& a, body& b) { + a.Swap(&b); + } + inline void Swap(body* other) { + if (other == this) return; + if (GetArena() == other->GetArena()) { + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(body* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + inline body* New() const final { + return CreateMaybeMessage(nullptr); + } + + body* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void CopyFrom(const body& from); + void MergeFrom(const body& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + inline void SharedCtor(); + inline void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(body* other); + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "mp.body"; + } + protected: + explicit body(::PROTOBUF_NAMESPACE_ID::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + private: + static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_mp_2ebody_2eproto); + return ::descriptor_table_mp_2ebody_2eproto.file_level_metadata[kIndexInFileMessages]; + } + + public: + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kPasswordFieldNumber = 2, + kDataFieldNumber = 5, + kAccountFieldNumber = 1, + kTargetFieldNumber = 3, + kSourceFieldNumber = 4, + }; + // string password = 2; + void clear_password(); + const std::string& password() const; + void set_password(const std::string& value); + void set_password(std::string&& value); + void set_password(const char* value); + void set_password(const char* value, size_t size); + std::string* mutable_password(); + std::string* release_password(); + void set_allocated_password(std::string* password); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + std::string* unsafe_arena_release_password(); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + void unsafe_arena_set_allocated_password( + std::string* password); + private: + const std::string& _internal_password() const; + void _internal_set_password(const std::string& value); + std::string* _internal_mutable_password(); + public: + + // string data = 5; + void clear_data(); + const std::string& data() const; + void set_data(const std::string& value); + void set_data(std::string&& value); + void set_data(const char* value); + void set_data(const char* value, size_t size); + std::string* mutable_data(); + std::string* release_data(); + void set_allocated_data(std::string* data); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + std::string* unsafe_arena_release_data(); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + void unsafe_arena_set_allocated_data( + std::string* data); + private: + const std::string& _internal_data() const; + void _internal_set_data(const std::string& value); + std::string* _internal_mutable_data(); + public: + + // uint64 account = 1; + void clear_account(); + ::PROTOBUF_NAMESPACE_ID::uint64 account() const; + void set_account(::PROTOBUF_NAMESPACE_ID::uint64 value); + private: + ::PROTOBUF_NAMESPACE_ID::uint64 _internal_account() const; + void _internal_set_account(::PROTOBUF_NAMESPACE_ID::uint64 value); + public: + + // uint64 target = 3; + void clear_target(); + ::PROTOBUF_NAMESPACE_ID::uint64 target() const; + void set_target(::PROTOBUF_NAMESPACE_ID::uint64 value); + private: + ::PROTOBUF_NAMESPACE_ID::uint64 _internal_target() const; + void _internal_set_target(::PROTOBUF_NAMESPACE_ID::uint64 value); + public: + + // uint64 source = 4; + void clear_source(); + ::PROTOBUF_NAMESPACE_ID::uint64 source() const; + void set_source(::PROTOBUF_NAMESPACE_ID::uint64 value); + private: + ::PROTOBUF_NAMESPACE_ID::uint64 _internal_source() const; + void _internal_set_source(::PROTOBUF_NAMESPACE_ID::uint64 value); + public: + + // @@protoc_insertion_point(class_scope:mp.body) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr password_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr data_; + ::PROTOBUF_NAMESPACE_ID::uint64 account_; + ::PROTOBUF_NAMESPACE_ID::uint64 target_; + ::PROTOBUF_NAMESPACE_ID::uint64 source_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_mp_2ebody_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// body + +// uint64 account = 1; +inline void body::clear_account() { + account_ = PROTOBUF_ULONGLONG(0); +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 body::_internal_account() const { + return account_; +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 body::account() const { + // @@protoc_insertion_point(field_get:mp.body.account) + return _internal_account(); +} +inline void body::_internal_set_account(::PROTOBUF_NAMESPACE_ID::uint64 value) { + + account_ = value; +} +inline void body::set_account(::PROTOBUF_NAMESPACE_ID::uint64 value) { + _internal_set_account(value); + // @@protoc_insertion_point(field_set:mp.body.account) +} + +// string password = 2; +inline void body::clear_password() { + password_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline const std::string& body::password() const { + // @@protoc_insertion_point(field_get:mp.body.password) + return _internal_password(); +} +inline void body::set_password(const std::string& value) { + _internal_set_password(value); + // @@protoc_insertion_point(field_set:mp.body.password) +} +inline std::string* body::mutable_password() { + // @@protoc_insertion_point(field_mutable:mp.body.password) + return _internal_mutable_password(); +} +inline const std::string& body::_internal_password() const { + return password_.Get(); +} +inline void body::_internal_set_password(const std::string& value) { + + password_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena()); +} +inline void body::set_password(std::string&& value) { + + password_.Set( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena()); + // @@protoc_insertion_point(field_set_rvalue:mp.body.password) +} +inline void body::set_password(const char* value) { + GOOGLE_DCHECK(value != nullptr); + + password_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArena()); + // @@protoc_insertion_point(field_set_char:mp.body.password) +} +inline void body::set_password(const char* value, + size_t size) { + + password_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArena()); + // @@protoc_insertion_point(field_set_pointer:mp.body.password) +} +inline std::string* body::_internal_mutable_password() { + + return password_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline std::string* body::release_password() { + // @@protoc_insertion_point(field_release:mp.body.password) + return password_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline void body::set_allocated_password(std::string* password) { + if (password != nullptr) { + + } else { + + } + password_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), password, + GetArena()); + // @@protoc_insertion_point(field_set_allocated:mp.body.password) +} +inline std::string* body::unsafe_arena_release_password() { + // @@protoc_insertion_point(field_unsafe_arena_release:mp.body.password) + GOOGLE_DCHECK(GetArena() != nullptr); + + return password_.UnsafeArenaRelease(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + GetArena()); +} +inline void body::unsafe_arena_set_allocated_password( + std::string* password) { + GOOGLE_DCHECK(GetArena() != nullptr); + if (password != nullptr) { + + } else { + + } + password_.UnsafeArenaSetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + password, GetArena()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.body.password) +} + +// uint64 target = 3; +inline void body::clear_target() { + target_ = PROTOBUF_ULONGLONG(0); +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 body::_internal_target() const { + return target_; +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 body::target() const { + // @@protoc_insertion_point(field_get:mp.body.target) + return _internal_target(); +} +inline void body::_internal_set_target(::PROTOBUF_NAMESPACE_ID::uint64 value) { + + target_ = value; +} +inline void body::set_target(::PROTOBUF_NAMESPACE_ID::uint64 value) { + _internal_set_target(value); + // @@protoc_insertion_point(field_set:mp.body.target) +} + +// uint64 source = 4; +inline void body::clear_source() { + source_ = PROTOBUF_ULONGLONG(0); +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 body::_internal_source() const { + return source_; +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 body::source() const { + // @@protoc_insertion_point(field_get:mp.body.source) + return _internal_source(); +} +inline void body::_internal_set_source(::PROTOBUF_NAMESPACE_ID::uint64 value) { + + source_ = value; +} +inline void body::set_source(::PROTOBUF_NAMESPACE_ID::uint64 value) { + _internal_set_source(value); + // @@protoc_insertion_point(field_set:mp.body.source) +} + +// string data = 5; +inline void body::clear_data() { + data_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline const std::string& body::data() const { + // @@protoc_insertion_point(field_get:mp.body.data) + return _internal_data(); +} +inline void body::set_data(const std::string& value) { + _internal_set_data(value); + // @@protoc_insertion_point(field_set:mp.body.data) +} +inline std::string* body::mutable_data() { + // @@protoc_insertion_point(field_mutable:mp.body.data) + return _internal_mutable_data(); +} +inline const std::string& body::_internal_data() const { + return data_.Get(); +} +inline void body::_internal_set_data(const std::string& value) { + + data_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena()); +} +inline void body::set_data(std::string&& value) { + + data_.Set( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena()); + // @@protoc_insertion_point(field_set_rvalue:mp.body.data) +} +inline void body::set_data(const char* value) { + GOOGLE_DCHECK(value != nullptr); + + data_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArena()); + // @@protoc_insertion_point(field_set_char:mp.body.data) +} +inline void body::set_data(const char* value, + size_t size) { + + data_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArena()); + // @@protoc_insertion_point(field_set_pointer:mp.body.data) +} +inline std::string* body::_internal_mutable_data() { + + return data_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline std::string* body::release_data() { + // @@protoc_insertion_point(field_release:mp.body.data) + return data_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline void body::set_allocated_data(std::string* data) { + if (data != nullptr) { + + } else { + + } + data_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), data, + GetArena()); + // @@protoc_insertion_point(field_set_allocated:mp.body.data) +} +inline std::string* body::unsafe_arena_release_data() { + // @@protoc_insertion_point(field_unsafe_arena_release:mp.body.data) + GOOGLE_DCHECK(GetArena() != nullptr); + + return data_.UnsafeArenaRelease(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + GetArena()); +} +inline void body::unsafe_arena_set_allocated_data( + std::string* data) { + GOOGLE_DCHECK(GetArena() != nullptr); + if (data != nullptr) { + + } else { + + } + data_.UnsafeArenaSetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + data, GetArena()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.body.data) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) + +} // namespace mp + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_mp_2ebody_2eproto diff --git a/include/mp/proto/mp.cqi.pb.h b/include/mp/proto/mp.cqi.pb.h new file mode 100644 index 0000000..948c89d --- /dev/null +++ b/include/mp/proto/mp.cqi.pb.h @@ -0,0 +1,313 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.cqi.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_mp_2ecqi_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_mp_2ecqi_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3012000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3012004 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +#include +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_mp_2ecqi_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_mp_2ecqi_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxillaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2ecqi_2eproto; +namespace mp { +class cqi; +class cqiDefaultTypeInternal; +extern cqiDefaultTypeInternal _cqi_default_instance_; +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> ::mp::cqi* Arena::CreateMaybeMessage<::mp::cqi>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace mp { + +enum MP_C_TYPE : int { + MC_TYPE_LINUX = 0, + MC_TYPE_WINDOWS = 1, + MP_C_TYPE_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::PROTOBUF_NAMESPACE_ID::int32>::min(), + MP_C_TYPE_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::PROTOBUF_NAMESPACE_ID::int32>::max() +}; +bool MP_C_TYPE_IsValid(int value); +constexpr MP_C_TYPE MP_C_TYPE_MIN = MC_TYPE_LINUX; +constexpr MP_C_TYPE MP_C_TYPE_MAX = MC_TYPE_WINDOWS; +constexpr int MP_C_TYPE_ARRAYSIZE = MP_C_TYPE_MAX + 1; + +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MP_C_TYPE_descriptor(); +template +inline const std::string& MP_C_TYPE_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function MP_C_TYPE_Name."); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum( + MP_C_TYPE_descriptor(), enum_t_value); +} +inline bool MP_C_TYPE_Parse( + const std::string& name, MP_C_TYPE* value) { + return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( + MP_C_TYPE_descriptor(), name, value); +} +// =================================================================== + +class cqi PROTOBUF_FINAL : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mp.cqi) */ { + public: + inline cqi() : cqi(nullptr) {}; + virtual ~cqi(); + + cqi(const cqi& from); + cqi(cqi&& from) noexcept + : cqi() { + *this = ::std::move(from); + } + + inline cqi& operator=(const cqi& from) { + CopyFrom(from); + return *this; + } + inline cqi& operator=(cqi&& from) noexcept { + if (GetArena() == from.GetArena()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return GetMetadataStatic().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return GetMetadataStatic().reflection; + } + static const cqi& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const cqi* internal_default_instance() { + return reinterpret_cast( + &_cqi_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(cqi& a, cqi& b) { + a.Swap(&b); + } + inline void Swap(cqi* other) { + if (other == this) return; + if (GetArena() == other->GetArena()) { + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(cqi* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + inline cqi* New() const final { + return CreateMaybeMessage(nullptr); + } + + cqi* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void CopyFrom(const cqi& from); + void MergeFrom(const cqi& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + inline void SharedCtor(); + inline void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(cqi* other); + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "mp.cqi"; + } + protected: + explicit cqi(::PROTOBUF_NAMESPACE_ID::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + private: + static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_mp_2ecqi_2eproto); + return ::descriptor_table_mp_2ecqi_2eproto.file_level_metadata[kIndexInFileMessages]; + } + + public: + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kCqiTypeFieldNumber = 1, + kCqiVersionFieldNumber = 2, + }; + // .mp.MP_C_TYPE cqi_type = 1; + void clear_cqi_type(); + ::mp::MP_C_TYPE cqi_type() const; + void set_cqi_type(::mp::MP_C_TYPE value); + private: + ::mp::MP_C_TYPE _internal_cqi_type() const; + void _internal_set_cqi_type(::mp::MP_C_TYPE value); + public: + + // float cqi_version = 2; + void clear_cqi_version(); + float cqi_version() const; + void set_cqi_version(float value); + private: + float _internal_cqi_version() const; + void _internal_set_cqi_version(float value); + public: + + // @@protoc_insertion_point(class_scope:mp.cqi) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + int cqi_type_; + float cqi_version_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_mp_2ecqi_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// cqi + +// .mp.MP_C_TYPE cqi_type = 1; +inline void cqi::clear_cqi_type() { + cqi_type_ = 0; +} +inline ::mp::MP_C_TYPE cqi::_internal_cqi_type() const { + return static_cast< ::mp::MP_C_TYPE >(cqi_type_); +} +inline ::mp::MP_C_TYPE cqi::cqi_type() const { + // @@protoc_insertion_point(field_get:mp.cqi.cqi_type) + return _internal_cqi_type(); +} +inline void cqi::_internal_set_cqi_type(::mp::MP_C_TYPE value) { + + cqi_type_ = value; +} +inline void cqi::set_cqi_type(::mp::MP_C_TYPE value) { + _internal_set_cqi_type(value); + // @@protoc_insertion_point(field_set:mp.cqi.cqi_type) +} + +// float cqi_version = 2; +inline void cqi::clear_cqi_version() { + cqi_version_ = 0; +} +inline float cqi::_internal_cqi_version() const { + return cqi_version_; +} +inline float cqi::cqi_version() const { + // @@protoc_insertion_point(field_get:mp.cqi.cqi_version) + return _internal_cqi_version(); +} +inline void cqi::_internal_set_cqi_version(float value) { + + cqi_version_ = value; +} +inline void cqi::set_cqi_version(float value) { + _internal_set_cqi_version(value); + // @@protoc_insertion_point(field_set:mp.cqi.cqi_version) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) + +} // namespace mp + +PROTOBUF_NAMESPACE_OPEN + +template <> struct is_proto_enum< ::mp::MP_C_TYPE> : ::std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::mp::MP_C_TYPE>() { + return ::mp::MP_C_TYPE_descriptor(); +} + +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_mp_2ecqi_2eproto diff --git a/include/mp/proto/mp.mph.pb.h b/include/mp/proto/mp.mph.pb.h new file mode 100644 index 0000000..713d045 --- /dev/null +++ b/include/mp/proto/mp.mph.pb.h @@ -0,0 +1,487 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.mph.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_mp_2emph_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_mp_2emph_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3012000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3012004 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +#include +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_mp_2emph_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_mp_2emph_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxillaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2emph_2eproto; +namespace mp { +class mph; +class mphDefaultTypeInternal; +extern mphDefaultTypeInternal _mph_default_instance_; +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> ::mp::mph* Arena::CreateMaybeMessage<::mp::mph>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace mp { + +enum MP_TYPE : int { + MP_REQUEST_LOGIN = 0, + MP_REQUEST_LOGOUT = 1, + MP_REQUEST_REGISTER = 2, + MP_RESPONSE_LOGIN = 20, + MP_RESPONSE_LOGOUT = 21, + MP_RESPONSE_REGISTER = 22, + MP_TYPE_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::PROTOBUF_NAMESPACE_ID::int32>::min(), + MP_TYPE_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::PROTOBUF_NAMESPACE_ID::int32>::max() +}; +bool MP_TYPE_IsValid(int value); +constexpr MP_TYPE MP_TYPE_MIN = MP_REQUEST_LOGIN; +constexpr MP_TYPE MP_TYPE_MAX = MP_RESPONSE_REGISTER; +constexpr int MP_TYPE_ARRAYSIZE = MP_TYPE_MAX + 1; + +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MP_TYPE_descriptor(); +template +inline const std::string& MP_TYPE_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function MP_TYPE_Name."); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum( + MP_TYPE_descriptor(), enum_t_value); +} +inline bool MP_TYPE_Parse( + const std::string& name, MP_TYPE* value) { + return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( + MP_TYPE_descriptor(), name, value); +} +// =================================================================== + +class mph PROTOBUF_FINAL : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mp.mph) */ { + public: + inline mph() : mph(nullptr) {}; + virtual ~mph(); + + mph(const mph& from); + mph(mph&& from) noexcept + : mph() { + *this = ::std::move(from); + } + + inline mph& operator=(const mph& from) { + CopyFrom(from); + return *this; + } + inline mph& operator=(mph&& from) noexcept { + if (GetArena() == from.GetArena()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return GetMetadataStatic().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return GetMetadataStatic().reflection; + } + static const mph& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const mph* internal_default_instance() { + return reinterpret_cast( + &_mph_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(mph& a, mph& b) { + a.Swap(&b); + } + inline void Swap(mph* other) { + if (other == this) return; + if (GetArena() == other->GetArena()) { + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(mph* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + inline mph* New() const final { + return CreateMaybeMessage(nullptr); + } + + mph* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void CopyFrom(const mph& from); + void MergeFrom(const mph& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + inline void SharedCtor(); + inline void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(mph* other); + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "mp.mph"; + } + protected: + explicit mph(::PROTOBUF_NAMESPACE_ID::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + private: + static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_mp_2emph_2eproto); + return ::descriptor_table_mp_2emph_2eproto.file_level_metadata[kIndexInFileMessages]; + } + + public: + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kPathFieldNumber = 5, + kMpIdFieldNumber = 2, + kMpbSizeFieldNumber = 1, + kMpSumFieldNumber = 3, + kMpTypeFieldNumber = 4, + }; + // string path = 5; + void clear_path(); + const std::string& path() const; + void set_path(const std::string& value); + void set_path(std::string&& value); + void set_path(const char* value); + void set_path(const char* value, size_t size); + std::string* mutable_path(); + std::string* release_path(); + void set_allocated_path(std::string* path); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + std::string* unsafe_arena_release_path(); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + void unsafe_arena_set_allocated_path( + std::string* path); + private: + const std::string& _internal_path() const; + void _internal_set_path(const std::string& value); + std::string* _internal_mutable_path(); + public: + + // uint64 mp_id = 2; + void clear_mp_id(); + ::PROTOBUF_NAMESPACE_ID::uint64 mp_id() const; + void set_mp_id(::PROTOBUF_NAMESPACE_ID::uint64 value); + private: + ::PROTOBUF_NAMESPACE_ID::uint64 _internal_mp_id() const; + void _internal_set_mp_id(::PROTOBUF_NAMESPACE_ID::uint64 value); + public: + + // uint32 mpb_size = 1; + void clear_mpb_size(); + ::PROTOBUF_NAMESPACE_ID::uint32 mpb_size() const; + void set_mpb_size(::PROTOBUF_NAMESPACE_ID::uint32 value); + private: + ::PROTOBUF_NAMESPACE_ID::uint32 _internal_mpb_size() const; + void _internal_set_mpb_size(::PROTOBUF_NAMESPACE_ID::uint32 value); + public: + + // uint32 mp_sum = 3; + void clear_mp_sum(); + ::PROTOBUF_NAMESPACE_ID::uint32 mp_sum() const; + void set_mp_sum(::PROTOBUF_NAMESPACE_ID::uint32 value); + private: + ::PROTOBUF_NAMESPACE_ID::uint32 _internal_mp_sum() const; + void _internal_set_mp_sum(::PROTOBUF_NAMESPACE_ID::uint32 value); + public: + + // .mp.MP_TYPE mp_type = 4; + void clear_mp_type(); + ::mp::MP_TYPE mp_type() const; + void set_mp_type(::mp::MP_TYPE value); + private: + ::mp::MP_TYPE _internal_mp_type() const; + void _internal_set_mp_type(::mp::MP_TYPE value); + public: + + // @@protoc_insertion_point(class_scope:mp.mph) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr path_; + ::PROTOBUF_NAMESPACE_ID::uint64 mp_id_; + ::PROTOBUF_NAMESPACE_ID::uint32 mpb_size_; + ::PROTOBUF_NAMESPACE_ID::uint32 mp_sum_; + int mp_type_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_mp_2emph_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// mph + +// uint32 mpb_size = 1; +inline void mph::clear_mpb_size() { + mpb_size_ = 0u; +} +inline ::PROTOBUF_NAMESPACE_ID::uint32 mph::_internal_mpb_size() const { + return mpb_size_; +} +inline ::PROTOBUF_NAMESPACE_ID::uint32 mph::mpb_size() const { + // @@protoc_insertion_point(field_get:mp.mph.mpb_size) + return _internal_mpb_size(); +} +inline void mph::_internal_set_mpb_size(::PROTOBUF_NAMESPACE_ID::uint32 value) { + + mpb_size_ = value; +} +inline void mph::set_mpb_size(::PROTOBUF_NAMESPACE_ID::uint32 value) { + _internal_set_mpb_size(value); + // @@protoc_insertion_point(field_set:mp.mph.mpb_size) +} + +// uint64 mp_id = 2; +inline void mph::clear_mp_id() { + mp_id_ = PROTOBUF_ULONGLONG(0); +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 mph::_internal_mp_id() const { + return mp_id_; +} +inline ::PROTOBUF_NAMESPACE_ID::uint64 mph::mp_id() const { + // @@protoc_insertion_point(field_get:mp.mph.mp_id) + return _internal_mp_id(); +} +inline void mph::_internal_set_mp_id(::PROTOBUF_NAMESPACE_ID::uint64 value) { + + mp_id_ = value; +} +inline void mph::set_mp_id(::PROTOBUF_NAMESPACE_ID::uint64 value) { + _internal_set_mp_id(value); + // @@protoc_insertion_point(field_set:mp.mph.mp_id) +} + +// uint32 mp_sum = 3; +inline void mph::clear_mp_sum() { + mp_sum_ = 0u; +} +inline ::PROTOBUF_NAMESPACE_ID::uint32 mph::_internal_mp_sum() const { + return mp_sum_; +} +inline ::PROTOBUF_NAMESPACE_ID::uint32 mph::mp_sum() const { + // @@protoc_insertion_point(field_get:mp.mph.mp_sum) + return _internal_mp_sum(); +} +inline void mph::_internal_set_mp_sum(::PROTOBUF_NAMESPACE_ID::uint32 value) { + + mp_sum_ = value; +} +inline void mph::set_mp_sum(::PROTOBUF_NAMESPACE_ID::uint32 value) { + _internal_set_mp_sum(value); + // @@protoc_insertion_point(field_set:mp.mph.mp_sum) +} + +// .mp.MP_TYPE mp_type = 4; +inline void mph::clear_mp_type() { + mp_type_ = 0; +} +inline ::mp::MP_TYPE mph::_internal_mp_type() const { + return static_cast< ::mp::MP_TYPE >(mp_type_); +} +inline ::mp::MP_TYPE mph::mp_type() const { + // @@protoc_insertion_point(field_get:mp.mph.mp_type) + return _internal_mp_type(); +} +inline void mph::_internal_set_mp_type(::mp::MP_TYPE value) { + + mp_type_ = value; +} +inline void mph::set_mp_type(::mp::MP_TYPE value) { + _internal_set_mp_type(value); + // @@protoc_insertion_point(field_set:mp.mph.mp_type) +} + +// string path = 5; +inline void mph::clear_path() { + path_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline const std::string& mph::path() const { + // @@protoc_insertion_point(field_get:mp.mph.path) + return _internal_path(); +} +inline void mph::set_path(const std::string& value) { + _internal_set_path(value); + // @@protoc_insertion_point(field_set:mp.mph.path) +} +inline std::string* mph::mutable_path() { + // @@protoc_insertion_point(field_mutable:mp.mph.path) + return _internal_mutable_path(); +} +inline const std::string& mph::_internal_path() const { + return path_.Get(); +} +inline void mph::_internal_set_path(const std::string& value) { + + path_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena()); +} +inline void mph::set_path(std::string&& value) { + + path_.Set( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena()); + // @@protoc_insertion_point(field_set_rvalue:mp.mph.path) +} +inline void mph::set_path(const char* value) { + GOOGLE_DCHECK(value != nullptr); + + path_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArena()); + // @@protoc_insertion_point(field_set_char:mp.mph.path) +} +inline void mph::set_path(const char* value, + size_t size) { + + path_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArena()); + // @@protoc_insertion_point(field_set_pointer:mp.mph.path) +} +inline std::string* mph::_internal_mutable_path() { + + return path_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline std::string* mph::release_path() { + // @@protoc_insertion_point(field_release:mp.mph.path) + return path_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline void mph::set_allocated_path(std::string* path) { + if (path != nullptr) { + + } else { + + } + path_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), path, + GetArena()); + // @@protoc_insertion_point(field_set_allocated:mp.mph.path) +} +inline std::string* mph::unsafe_arena_release_path() { + // @@protoc_insertion_point(field_unsafe_arena_release:mp.mph.path) + GOOGLE_DCHECK(GetArena() != nullptr); + + return path_.UnsafeArenaRelease(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + GetArena()); +} +inline void mph::unsafe_arena_set_allocated_path( + std::string* path) { + GOOGLE_DCHECK(GetArena() != nullptr); + if (path != nullptr) { + + } else { + + } + path_.UnsafeArenaSetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + path, GetArena()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.mph.path) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) + +} // namespace mp + +PROTOBUF_NAMESPACE_OPEN + +template <> struct is_proto_enum< ::mp::MP_TYPE> : ::std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::mp::MP_TYPE>() { + return ::mp::MP_TYPE_descriptor(); +} + +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_mp_2emph_2eproto diff --git a/include/mp/proto/mp.request.pb.h b/include/mp/proto/mp.request.pb.h new file mode 100644 index 0000000..26a51cd --- /dev/null +++ b/include/mp/proto/mp.request.pb.h @@ -0,0 +1,407 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.request.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_mp_2erequest_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_mp_2erequest_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3012000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3012004 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +#include "mp.body.pb.h" +#include "mp.cqi.pb.h" +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_mp_2erequest_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_mp_2erequest_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxillaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2erequest_2eproto; +namespace mp { +class request; +class requestDefaultTypeInternal; +extern requestDefaultTypeInternal _request_default_instance_; +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> ::mp::request* Arena::CreateMaybeMessage<::mp::request>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace mp { + +// =================================================================== + +class request PROTOBUF_FINAL : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mp.request) */ { + public: + inline request() : request(nullptr) {}; + virtual ~request(); + + request(const request& from); + request(request&& from) noexcept + : request() { + *this = ::std::move(from); + } + + inline request& operator=(const request& from) { + CopyFrom(from); + return *this; + } + inline request& operator=(request&& from) noexcept { + if (GetArena() == from.GetArena()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return GetMetadataStatic().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return GetMetadataStatic().reflection; + } + static const request& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const request* internal_default_instance() { + return reinterpret_cast( + &_request_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(request& a, request& b) { + a.Swap(&b); + } + inline void Swap(request* other) { + if (other == this) return; + if (GetArena() == other->GetArena()) { + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(request* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + inline request* New() const final { + return CreateMaybeMessage(nullptr); + } + + request* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void CopyFrom(const request& from); + void MergeFrom(const request& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + inline void SharedCtor(); + inline void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(request* other); + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "mp.request"; + } + protected: + explicit request(::PROTOBUF_NAMESPACE_ID::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + private: + static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_mp_2erequest_2eproto); + return ::descriptor_table_mp_2erequest_2eproto.file_level_metadata[kIndexInFileMessages]; + } + + public: + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kBodyFieldNumber = 2, + kCqiFieldNumber = 3, + }; + // .mp.body body = 2; + bool has_body() const; + private: + bool _internal_has_body() const; + public: + void clear_body(); + const ::mp::body& body() const; + ::mp::body* release_body(); + ::mp::body* mutable_body(); + void set_allocated_body(::mp::body* body); + private: + const ::mp::body& _internal_body() const; + ::mp::body* _internal_mutable_body(); + public: + void unsafe_arena_set_allocated_body( + ::mp::body* body); + ::mp::body* unsafe_arena_release_body(); + + // .mp.cqi cqi = 3; + bool has_cqi() const; + private: + bool _internal_has_cqi() const; + public: + void clear_cqi(); + const ::mp::cqi& cqi() const; + ::mp::cqi* release_cqi(); + ::mp::cqi* mutable_cqi(); + void set_allocated_cqi(::mp::cqi* cqi); + private: + const ::mp::cqi& _internal_cqi() const; + ::mp::cqi* _internal_mutable_cqi(); + public: + void unsafe_arena_set_allocated_cqi( + ::mp::cqi* cqi); + ::mp::cqi* unsafe_arena_release_cqi(); + + // @@protoc_insertion_point(class_scope:mp.request) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::mp::body* body_; + ::mp::cqi* cqi_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_mp_2erequest_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// request + +// .mp.body body = 2; +inline bool request::_internal_has_body() const { + return this != internal_default_instance() && body_ != nullptr; +} +inline bool request::has_body() const { + return _internal_has_body(); +} +inline const ::mp::body& request::_internal_body() const { + const ::mp::body* p = body_; + return p != nullptr ? *p : *reinterpret_cast( + &::mp::_body_default_instance_); +} +inline const ::mp::body& request::body() const { + // @@protoc_insertion_point(field_get:mp.request.body) + return _internal_body(); +} +inline void request::unsafe_arena_set_allocated_body( + ::mp::body* body) { + if (GetArena() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(body_); + } + body_ = body; + if (body) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.request.body) +} +inline ::mp::body* request::release_body() { + auto temp = unsafe_arena_release_body(); + if (GetArena() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + return temp; +} +inline ::mp::body* request::unsafe_arena_release_body() { + // @@protoc_insertion_point(field_release:mp.request.body) + + ::mp::body* temp = body_; + body_ = nullptr; + return temp; +} +inline ::mp::body* request::_internal_mutable_body() { + + if (body_ == nullptr) { + auto* p = CreateMaybeMessage<::mp::body>(GetArena()); + body_ = p; + } + return body_; +} +inline ::mp::body* request::mutable_body() { + // @@protoc_insertion_point(field_mutable:mp.request.body) + return _internal_mutable_body(); +} +inline void request::set_allocated_body(::mp::body* body) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); + if (message_arena == nullptr) { + delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(body_); + } + if (body) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(body)->GetArena(); + if (message_arena != submessage_arena) { + body = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, body, submessage_arena); + } + + } else { + + } + body_ = body; + // @@protoc_insertion_point(field_set_allocated:mp.request.body) +} + +// .mp.cqi cqi = 3; +inline bool request::_internal_has_cqi() const { + return this != internal_default_instance() && cqi_ != nullptr; +} +inline bool request::has_cqi() const { + return _internal_has_cqi(); +} +inline const ::mp::cqi& request::_internal_cqi() const { + const ::mp::cqi* p = cqi_; + return p != nullptr ? *p : *reinterpret_cast( + &::mp::_cqi_default_instance_); +} +inline const ::mp::cqi& request::cqi() const { + // @@protoc_insertion_point(field_get:mp.request.cqi) + return _internal_cqi(); +} +inline void request::unsafe_arena_set_allocated_cqi( + ::mp::cqi* cqi) { + if (GetArena() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(cqi_); + } + cqi_ = cqi; + if (cqi) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.request.cqi) +} +inline ::mp::cqi* request::release_cqi() { + auto temp = unsafe_arena_release_cqi(); + if (GetArena() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + return temp; +} +inline ::mp::cqi* request::unsafe_arena_release_cqi() { + // @@protoc_insertion_point(field_release:mp.request.cqi) + + ::mp::cqi* temp = cqi_; + cqi_ = nullptr; + return temp; +} +inline ::mp::cqi* request::_internal_mutable_cqi() { + + if (cqi_ == nullptr) { + auto* p = CreateMaybeMessage<::mp::cqi>(GetArena()); + cqi_ = p; + } + return cqi_; +} +inline ::mp::cqi* request::mutable_cqi() { + // @@protoc_insertion_point(field_mutable:mp.request.cqi) + return _internal_mutable_cqi(); +} +inline void request::set_allocated_cqi(::mp::cqi* cqi) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); + if (message_arena == nullptr) { + delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(cqi_); + } + if (cqi) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(cqi)->GetArena(); + if (message_arena != submessage_arena) { + cqi = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, cqi, submessage_arena); + } + + } else { + + } + cqi_ = cqi; + // @@protoc_insertion_point(field_set_allocated:mp.request.cqi) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) + +} // namespace mp + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_mp_2erequest_2eproto diff --git a/include/mp/proto/mp.response.pb.h b/include/mp/proto/mp.response.pb.h new file mode 100644 index 0000000..8d5ed10 --- /dev/null +++ b/include/mp/proto/mp.response.pb.h @@ -0,0 +1,311 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.response.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_mp_2eresponse_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_mp_2eresponse_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3012000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3012004 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +#include "mp.sri.pb.h" +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_mp_2eresponse_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_mp_2eresponse_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxillaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2eresponse_2eproto; +namespace mp { +class response; +class responseDefaultTypeInternal; +extern responseDefaultTypeInternal _response_default_instance_; +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> ::mp::response* Arena::CreateMaybeMessage<::mp::response>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace mp { + +// =================================================================== + +class response PROTOBUF_FINAL : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mp.response) */ { + public: + inline response() : response(nullptr) {}; + virtual ~response(); + + response(const response& from); + response(response&& from) noexcept + : response() { + *this = ::std::move(from); + } + + inline response& operator=(const response& from) { + CopyFrom(from); + return *this; + } + inline response& operator=(response&& from) noexcept { + if (GetArena() == from.GetArena()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return GetMetadataStatic().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return GetMetadataStatic().reflection; + } + static const response& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const response* internal_default_instance() { + return reinterpret_cast( + &_response_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(response& a, response& b) { + a.Swap(&b); + } + inline void Swap(response* other) { + if (other == this) return; + if (GetArena() == other->GetArena()) { + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(response* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + inline response* New() const final { + return CreateMaybeMessage(nullptr); + } + + response* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void CopyFrom(const response& from); + void MergeFrom(const response& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + inline void SharedCtor(); + inline void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(response* other); + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "mp.response"; + } + protected: + explicit response(::PROTOBUF_NAMESPACE_ID::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + private: + static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_mp_2eresponse_2eproto); + return ::descriptor_table_mp_2eresponse_2eproto.file_level_metadata[kIndexInFileMessages]; + } + + public: + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kSriFieldNumber = 3, + }; + // .mp.sri sri = 3; + bool has_sri() const; + private: + bool _internal_has_sri() const; + public: + void clear_sri(); + const ::mp::sri& sri() const; + ::mp::sri* release_sri(); + ::mp::sri* mutable_sri(); + void set_allocated_sri(::mp::sri* sri); + private: + const ::mp::sri& _internal_sri() const; + ::mp::sri* _internal_mutable_sri(); + public: + void unsafe_arena_set_allocated_sri( + ::mp::sri* sri); + ::mp::sri* unsafe_arena_release_sri(); + + // @@protoc_insertion_point(class_scope:mp.response) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::mp::sri* sri_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_mp_2eresponse_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// response + +// .mp.sri sri = 3; +inline bool response::_internal_has_sri() const { + return this != internal_default_instance() && sri_ != nullptr; +} +inline bool response::has_sri() const { + return _internal_has_sri(); +} +inline const ::mp::sri& response::_internal_sri() const { + const ::mp::sri* p = sri_; + return p != nullptr ? *p : *reinterpret_cast( + &::mp::_sri_default_instance_); +} +inline const ::mp::sri& response::sri() const { + // @@protoc_insertion_point(field_get:mp.response.sri) + return _internal_sri(); +} +inline void response::unsafe_arena_set_allocated_sri( + ::mp::sri* sri) { + if (GetArena() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(sri_); + } + sri_ = sri; + if (sri) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.response.sri) +} +inline ::mp::sri* response::release_sri() { + auto temp = unsafe_arena_release_sri(); + if (GetArena() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + return temp; +} +inline ::mp::sri* response::unsafe_arena_release_sri() { + // @@protoc_insertion_point(field_release:mp.response.sri) + + ::mp::sri* temp = sri_; + sri_ = nullptr; + return temp; +} +inline ::mp::sri* response::_internal_mutable_sri() { + + if (sri_ == nullptr) { + auto* p = CreateMaybeMessage<::mp::sri>(GetArena()); + sri_ = p; + } + return sri_; +} +inline ::mp::sri* response::mutable_sri() { + // @@protoc_insertion_point(field_mutable:mp.response.sri) + return _internal_mutable_sri(); +} +inline void response::set_allocated_sri(::mp::sri* sri) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); + if (message_arena == nullptr) { + delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(sri_); + } + if (sri) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(sri)->GetArena(); + if (message_arena != submessage_arena) { + sri = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, sri, submessage_arena); + } + + } else { + + } + sri_ = sri; + // @@protoc_insertion_point(field_set_allocated:mp.response.sri) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) + +} // namespace mp + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_mp_2eresponse_2eproto diff --git a/include/mp/proto/mp.sri.pb.h b/include/mp/proto/mp.sri.pb.h new file mode 100644 index 0000000..abdabdc --- /dev/null +++ b/include/mp/proto/mp.sri.pb.h @@ -0,0 +1,611 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: mp.sri.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_mp_2esri_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_mp_2esri_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3012000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3012004 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +#include +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_mp_2esri_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_mp_2esri_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxillaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_mp_2esri_2eproto; +namespace mp { +class sri; +class sriDefaultTypeInternal; +extern sriDefaultTypeInternal _sri_default_instance_; +} // namespace mp +PROTOBUF_NAMESPACE_OPEN +template<> ::mp::sri* Arena::CreateMaybeMessage<::mp::sri>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace mp { + +enum MP_SRI : int { + MP_LOGIN_ACCOUNT_NOT = 0, + MP_LOGIN_SUCCESS = 1, + MP_LOGIN_FAIL = 2, + MP_REGISTER_SUCCESS = 10, + MP_REGISTER_EXIST = 11, + MP_LOGOUT_SUCCESS = 20, + MP_LOGOUT_FAIL = 21, + MP_SRI_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::PROTOBUF_NAMESPACE_ID::int32>::min(), + MP_SRI_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::PROTOBUF_NAMESPACE_ID::int32>::max() +}; +bool MP_SRI_IsValid(int value); +constexpr MP_SRI MP_SRI_MIN = MP_LOGIN_ACCOUNT_NOT; +constexpr MP_SRI MP_SRI_MAX = MP_LOGOUT_FAIL; +constexpr int MP_SRI_ARRAYSIZE = MP_SRI_MAX + 1; + +const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MP_SRI_descriptor(); +template +inline const std::string& MP_SRI_Name(T enum_t_value) { + static_assert(::std::is_same::value || + ::std::is_integral::value, + "Incorrect type passed to function MP_SRI_Name."); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum( + MP_SRI_descriptor(), enum_t_value); +} +inline bool MP_SRI_Parse( + const std::string& name, MP_SRI* value) { + return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( + MP_SRI_descriptor(), name, value); +} +// =================================================================== + +class sri PROTOBUF_FINAL : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mp.sri) */ { + public: + inline sri() : sri(nullptr) {}; + virtual ~sri(); + + sri(const sri& from); + sri(sri&& from) noexcept + : sri() { + *this = ::std::move(from); + } + + inline sri& operator=(const sri& from) { + CopyFrom(from); + return *this; + } + inline sri& operator=(sri&& from) noexcept { + if (GetArena() == from.GetArena()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return GetMetadataStatic().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return GetMetadataStatic().reflection; + } + static const sri& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const sri* internal_default_instance() { + return reinterpret_cast( + &_sri_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(sri& a, sri& b) { + a.Swap(&b); + } + inline void Swap(sri* other) { + if (other == this) return; + if (GetArena() == other->GetArena()) { + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(sri* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArena() == other->GetArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + inline sri* New() const final { + return CreateMaybeMessage(nullptr); + } + + sri* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; + void CopyFrom(const sri& from); + void MergeFrom(const sri& from); + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( + ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + inline void SharedCtor(); + inline void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(sri* other); + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "mp.sri"; + } + protected: + explicit sri(::PROTOBUF_NAMESPACE_ID::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + private: + static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { + ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_mp_2esri_2eproto); + return ::descriptor_table_mp_2esri_2eproto.file_level_metadata[kIndexInFileMessages]; + } + + public: + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kSriUsernameFieldNumber = 2, + kSriMsgFieldNumber = 3, + kSriTokenFieldNumber = 4, + kSriCodeFieldNumber = 1, + }; + // string sri_username = 2; + void clear_sri_username(); + const std::string& sri_username() const; + void set_sri_username(const std::string& value); + void set_sri_username(std::string&& value); + void set_sri_username(const char* value); + void set_sri_username(const char* value, size_t size); + std::string* mutable_sri_username(); + std::string* release_sri_username(); + void set_allocated_sri_username(std::string* sri_username); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + std::string* unsafe_arena_release_sri_username(); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + void unsafe_arena_set_allocated_sri_username( + std::string* sri_username); + private: + const std::string& _internal_sri_username() const; + void _internal_set_sri_username(const std::string& value); + std::string* _internal_mutable_sri_username(); + public: + + // string sri_msg = 3; + void clear_sri_msg(); + const std::string& sri_msg() const; + void set_sri_msg(const std::string& value); + void set_sri_msg(std::string&& value); + void set_sri_msg(const char* value); + void set_sri_msg(const char* value, size_t size); + std::string* mutable_sri_msg(); + std::string* release_sri_msg(); + void set_allocated_sri_msg(std::string* sri_msg); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + std::string* unsafe_arena_release_sri_msg(); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + void unsafe_arena_set_allocated_sri_msg( + std::string* sri_msg); + private: + const std::string& _internal_sri_msg() const; + void _internal_set_sri_msg(const std::string& value); + std::string* _internal_mutable_sri_msg(); + public: + + // string sri_token = 4; + void clear_sri_token(); + const std::string& sri_token() const; + void set_sri_token(const std::string& value); + void set_sri_token(std::string&& value); + void set_sri_token(const char* value); + void set_sri_token(const char* value, size_t size); + std::string* mutable_sri_token(); + std::string* release_sri_token(); + void set_allocated_sri_token(std::string* sri_token); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + std::string* unsafe_arena_release_sri_token(); + GOOGLE_PROTOBUF_RUNTIME_DEPRECATED("The unsafe_arena_ accessors for" + " string fields are deprecated and will be removed in a" + " future release.") + void unsafe_arena_set_allocated_sri_token( + std::string* sri_token); + private: + const std::string& _internal_sri_token() const; + void _internal_set_sri_token(const std::string& value); + std::string* _internal_mutable_sri_token(); + public: + + // .mp.MP_SRI sri_code = 1; + void clear_sri_code(); + ::mp::MP_SRI sri_code() const; + void set_sri_code(::mp::MP_SRI value); + private: + ::mp::MP_SRI _internal_sri_code() const; + void _internal_set_sri_code(::mp::MP_SRI value); + public: + + // @@protoc_insertion_point(class_scope:mp.sri) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr sri_username_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr sri_msg_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr sri_token_; + int sri_code_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_mp_2esri_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// sri + +// .mp.MP_SRI sri_code = 1; +inline void sri::clear_sri_code() { + sri_code_ = 0; +} +inline ::mp::MP_SRI sri::_internal_sri_code() const { + return static_cast< ::mp::MP_SRI >(sri_code_); +} +inline ::mp::MP_SRI sri::sri_code() const { + // @@protoc_insertion_point(field_get:mp.sri.sri_code) + return _internal_sri_code(); +} +inline void sri::_internal_set_sri_code(::mp::MP_SRI value) { + + sri_code_ = value; +} +inline void sri::set_sri_code(::mp::MP_SRI value) { + _internal_set_sri_code(value); + // @@protoc_insertion_point(field_set:mp.sri.sri_code) +} + +// string sri_username = 2; +inline void sri::clear_sri_username() { + sri_username_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline const std::string& sri::sri_username() const { + // @@protoc_insertion_point(field_get:mp.sri.sri_username) + return _internal_sri_username(); +} +inline void sri::set_sri_username(const std::string& value) { + _internal_set_sri_username(value); + // @@protoc_insertion_point(field_set:mp.sri.sri_username) +} +inline std::string* sri::mutable_sri_username() { + // @@protoc_insertion_point(field_mutable:mp.sri.sri_username) + return _internal_mutable_sri_username(); +} +inline const std::string& sri::_internal_sri_username() const { + return sri_username_.Get(); +} +inline void sri::_internal_set_sri_username(const std::string& value) { + + sri_username_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena()); +} +inline void sri::set_sri_username(std::string&& value) { + + sri_username_.Set( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena()); + // @@protoc_insertion_point(field_set_rvalue:mp.sri.sri_username) +} +inline void sri::set_sri_username(const char* value) { + GOOGLE_DCHECK(value != nullptr); + + sri_username_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArena()); + // @@protoc_insertion_point(field_set_char:mp.sri.sri_username) +} +inline void sri::set_sri_username(const char* value, + size_t size) { + + sri_username_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArena()); + // @@protoc_insertion_point(field_set_pointer:mp.sri.sri_username) +} +inline std::string* sri::_internal_mutable_sri_username() { + + return sri_username_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline std::string* sri::release_sri_username() { + // @@protoc_insertion_point(field_release:mp.sri.sri_username) + return sri_username_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline void sri::set_allocated_sri_username(std::string* sri_username) { + if (sri_username != nullptr) { + + } else { + + } + sri_username_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), sri_username, + GetArena()); + // @@protoc_insertion_point(field_set_allocated:mp.sri.sri_username) +} +inline std::string* sri::unsafe_arena_release_sri_username() { + // @@protoc_insertion_point(field_unsafe_arena_release:mp.sri.sri_username) + GOOGLE_DCHECK(GetArena() != nullptr); + + return sri_username_.UnsafeArenaRelease(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + GetArena()); +} +inline void sri::unsafe_arena_set_allocated_sri_username( + std::string* sri_username) { + GOOGLE_DCHECK(GetArena() != nullptr); + if (sri_username != nullptr) { + + } else { + + } + sri_username_.UnsafeArenaSetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + sri_username, GetArena()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.sri.sri_username) +} + +// string sri_msg = 3; +inline void sri::clear_sri_msg() { + sri_msg_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline const std::string& sri::sri_msg() const { + // @@protoc_insertion_point(field_get:mp.sri.sri_msg) + return _internal_sri_msg(); +} +inline void sri::set_sri_msg(const std::string& value) { + _internal_set_sri_msg(value); + // @@protoc_insertion_point(field_set:mp.sri.sri_msg) +} +inline std::string* sri::mutable_sri_msg() { + // @@protoc_insertion_point(field_mutable:mp.sri.sri_msg) + return _internal_mutable_sri_msg(); +} +inline const std::string& sri::_internal_sri_msg() const { + return sri_msg_.Get(); +} +inline void sri::_internal_set_sri_msg(const std::string& value) { + + sri_msg_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena()); +} +inline void sri::set_sri_msg(std::string&& value) { + + sri_msg_.Set( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena()); + // @@protoc_insertion_point(field_set_rvalue:mp.sri.sri_msg) +} +inline void sri::set_sri_msg(const char* value) { + GOOGLE_DCHECK(value != nullptr); + + sri_msg_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArena()); + // @@protoc_insertion_point(field_set_char:mp.sri.sri_msg) +} +inline void sri::set_sri_msg(const char* value, + size_t size) { + + sri_msg_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArena()); + // @@protoc_insertion_point(field_set_pointer:mp.sri.sri_msg) +} +inline std::string* sri::_internal_mutable_sri_msg() { + + return sri_msg_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline std::string* sri::release_sri_msg() { + // @@protoc_insertion_point(field_release:mp.sri.sri_msg) + return sri_msg_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline void sri::set_allocated_sri_msg(std::string* sri_msg) { + if (sri_msg != nullptr) { + + } else { + + } + sri_msg_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), sri_msg, + GetArena()); + // @@protoc_insertion_point(field_set_allocated:mp.sri.sri_msg) +} +inline std::string* sri::unsafe_arena_release_sri_msg() { + // @@protoc_insertion_point(field_unsafe_arena_release:mp.sri.sri_msg) + GOOGLE_DCHECK(GetArena() != nullptr); + + return sri_msg_.UnsafeArenaRelease(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + GetArena()); +} +inline void sri::unsafe_arena_set_allocated_sri_msg( + std::string* sri_msg) { + GOOGLE_DCHECK(GetArena() != nullptr); + if (sri_msg != nullptr) { + + } else { + + } + sri_msg_.UnsafeArenaSetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + sri_msg, GetArena()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.sri.sri_msg) +} + +// string sri_token = 4; +inline void sri::clear_sri_token() { + sri_token_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline const std::string& sri::sri_token() const { + // @@protoc_insertion_point(field_get:mp.sri.sri_token) + return _internal_sri_token(); +} +inline void sri::set_sri_token(const std::string& value) { + _internal_set_sri_token(value); + // @@protoc_insertion_point(field_set:mp.sri.sri_token) +} +inline std::string* sri::mutable_sri_token() { + // @@protoc_insertion_point(field_mutable:mp.sri.sri_token) + return _internal_mutable_sri_token(); +} +inline const std::string& sri::_internal_sri_token() const { + return sri_token_.Get(); +} +inline void sri::_internal_set_sri_token(const std::string& value) { + + sri_token_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena()); +} +inline void sri::set_sri_token(std::string&& value) { + + sri_token_.Set( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena()); + // @@protoc_insertion_point(field_set_rvalue:mp.sri.sri_token) +} +inline void sri::set_sri_token(const char* value) { + GOOGLE_DCHECK(value != nullptr); + + sri_token_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArena()); + // @@protoc_insertion_point(field_set_char:mp.sri.sri_token) +} +inline void sri::set_sri_token(const char* value, + size_t size) { + + sri_token_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArena()); + // @@protoc_insertion_point(field_set_pointer:mp.sri.sri_token) +} +inline std::string* sri::_internal_mutable_sri_token() { + + return sri_token_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline std::string* sri::release_sri_token() { + // @@protoc_insertion_point(field_release:mp.sri.sri_token) + return sri_token_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena()); +} +inline void sri::set_allocated_sri_token(std::string* sri_token) { + if (sri_token != nullptr) { + + } else { + + } + sri_token_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), sri_token, + GetArena()); + // @@protoc_insertion_point(field_set_allocated:mp.sri.sri_token) +} +inline std::string* sri::unsafe_arena_release_sri_token() { + // @@protoc_insertion_point(field_unsafe_arena_release:mp.sri.sri_token) + GOOGLE_DCHECK(GetArena() != nullptr); + + return sri_token_.UnsafeArenaRelease(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + GetArena()); +} +inline void sri::unsafe_arena_set_allocated_sri_token( + std::string* sri_token) { + GOOGLE_DCHECK(GetArena() != nullptr); + if (sri_token != nullptr) { + + } else { + + } + sri_token_.UnsafeArenaSetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + sri_token, GetArena()); + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:mp.sri.sri_token) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) + +} // namespace mp + +PROTOBUF_NAMESPACE_OPEN + +template <> struct is_proto_enum< ::mp::MP_SRI> : ::std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::mp::MP_SRI>() { + return ::mp::MP_SRI_descriptor(); +} + +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_mp_2esri_2eproto diff --git a/include/mp/protohuf/mp.body.proto b/include/mp/protohuf/mp.body.proto new file mode 100644 index 0000000..220a8a7 --- /dev/null +++ b/include/mp/protohuf/mp.body.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package mp; + +message body { + uint64 account = 1; + string password = 2; + uint64 target = 3; + uint64 source = 4; + string data = 5; +} \ No newline at end of file diff --git a/include/mp/protohuf/mp.cqi.proto b/include/mp/protohuf/mp.cqi.proto new file mode 100644 index 0000000..6066597 --- /dev/null +++ b/include/mp/protohuf/mp.cqi.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +package mp; + +enum MP_C_TYPE { + MC_TYPE_LINUX = 0; + MC_TYPE_WINDOWS = 1; +}; + +// 客户端请求消息 +message cqi { + MP_C_TYPE cqi_type = 1; + float cqi_version = 2; +} \ No newline at end of file diff --git a/include/mp/protohuf/mp.mph.proto b/include/mp/protohuf/mp.mph.proto new file mode 100644 index 0000000..53795c8 --- /dev/null +++ b/include/mp/protohuf/mp.mph.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; +package mp; + +enum MP_TYPE { + MP_REQUEST_LOGIN = 0; + MP_REQUEST_LOGOUT = 1; + MP_REQUEST_REGISTER = 2; + + MP_RESPONSE_LOGIN = 20; + MP_RESPONSE_LOGOUT = 21; + MP_RESPONSE_REGISTER = 22; + + // 100 以后为 聊天消息包 +} + +message mph { + uint32 mpb_size = 1; // 包体大小 + uint64 mp_id = 2; // 包id + uint32 mp_sum = 3; // 包序号 + MP_TYPE mp_type = 4; // 包类型 + string path = 5; +} \ No newline at end of file diff --git a/include/mp/protohuf/mp.request.proto b/include/mp/protohuf/mp.request.proto new file mode 100644 index 0000000..ee79d62 --- /dev/null +++ b/include/mp/protohuf/mp.request.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package mp; + +import "mp.body.proto"; +import "mp.cqi.proto"; + +message request { + body body = 2; + cqi cqi = 3; +} \ No newline at end of file diff --git a/include/mp/protohuf/mp.response.proto b/include/mp/protohuf/mp.response.proto new file mode 100644 index 0000000..0f660c4 --- /dev/null +++ b/include/mp/protohuf/mp.response.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; +package mp; + +import "mp.sri.proto"; + +message response { + sri sri = 3; +} \ No newline at end of file diff --git a/include/mp/protohuf/mp.sri.proto b/include/mp/protohuf/mp.sri.proto new file mode 100644 index 0000000..167b149 --- /dev/null +++ b/include/mp/protohuf/mp.sri.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; +package mp; + +enum MP_SRI { + MP_LOGIN_ACCOUNT_NOT = 0; + MP_LOGIN_SUCCESS = 1; + MP_LOGIN_FAIL = 2; + + MP_REGISTER_SUCCESS = 10; + MP_REGISTER_EXIST = 11; + + MP_LOGOUT_SUCCESS = 20; + MP_LOGOUT_FAIL = 21; +} + +message sri { + MP_SRI sri_code = 1; + string sri_username = 2; + string sri_msg = 3; + string sri_token = 4; +} \ No newline at end of file diff --git a/include/mysql++/autoflag.h b/include/mysql++/autoflag.h new file mode 100644 index 0000000..ef3ac72 --- /dev/null +++ b/include/mysql++/autoflag.h @@ -0,0 +1,61 @@ +/// \file autoflag.h +/// \brief Defines a template for setting a flag within a given variable +/// scope, and resetting it when exiting that scope. + +/*********************************************************************** + Copyright © 2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the + CREDITS.txt file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_AUTOFLAG_H) +#define MYSQLPP_AUTOFLAG_H + +namespace mysqlpp { + +/// \brief A template for setting a flag on a variable as long as the +/// object that set it is in scope. Flag resets when object goes +/// out of scope. Works on anything that looks like bool. + +template +class AutoFlag +{ +public: + /// \brief Constructor: sets ref to true. + AutoFlag(T& ref) : + referent_(ref) + { + referent_ = true; + } + + /// \brief Destructor: sets referent passed to ctor to false. + ~AutoFlag() + { + referent_ = false; + } + +private: + T& referent_; +}; + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_AUTOFLAG_H) + diff --git a/include/mysql++/beemutex.h b/include/mysql++/beemutex.h new file mode 100644 index 0000000..c3e4412 --- /dev/null +++ b/include/mysql++/beemutex.h @@ -0,0 +1,129 @@ +/// \file beemutex.h +/// \brief MUTually EXclusive lock class. +/// \author Bob Deblier +/// +/// Modified by Warren Young of Educational Technology Resources, Inc. +/// from version in Beecrypt 4.1.2: +/// +/// - minor style changes to make it fit within MySQL++ +/// - changed init() to a ctor and destroy() to a dtor +/// - class just becomes a no-op if no supported mutex type is available +/// - throwing MutexFailed instead of \c char* +/// - moved all method implementations from inline in the .h file to +/// a .cpp file so we don't have to make the header depend on config.h +/// on autoconf-using systems +/// - made private mutex member a void* so we don't have to define the +/// full type in the .h file, due to previous item +/// - added more Doxygen comments, and changed some existing comments +/// - using MAY_THROW() from MySQL++'s common.h to allow it to compile +/// on C++17 and newer compilers + +/*********************************************************************** + Copyright © 2004 Beeyond Software Holding BV and © 2007-2008, 2018 + by Educational Technology Resources, Inc. Others may also hold + copyrights on code in this file. See the CREDITS.txt file in the + top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_BEEMUTEX_H) +#define MYSQLPP_BEEMUTEX_H + +#include "exceptions.h" + +namespace mysqlpp { + +/// \brief Wrapper around platform-specific mutexes. +/// +/// This class is only intended to be used within the library. We don't +/// really want to support this as a general purpose class. If it works +/// for you as-is, that's great, we won't try to stop you. But if you +/// run into a problem that doesn't affect MySQL++ itself, we're not +/// likely to bother enhancing this class to fix the problem. +class MYSQLPP_EXPORT BeecryptMutex +{ +public: + /// \brief Create the mutex object + /// + /// Throws a MutexFailed exception if we can't acquire the lock for + /// some reason. The exception contains a message saying why. + BeecryptMutex() MAY_THROW(MutexFailed); + + /// \brief Destroy the mutex + /// + /// Failures are quietly ignored. + ~BeecryptMutex(); + + /// \brief Acquire the mutex, blocking if it can't be acquired + /// immediately. + void lock() MAY_THROW(MutexFailed); + + /// \brief Acquire the mutex immediately and return true, or return + /// false if it would have to block to acquire the mutex. + bool trylock() MAY_THROW(MutexFailed); + + /// \brief Release the mutex + void unlock() MAY_THROW(MutexFailed); + +private: + void* pmutex_; +}; + + +/// \brief Wrapper around BeecryptMutex to add scope-bound locking +/// and unlocking. +/// +/// This allows code to lock a mutex and ensure it will unlock on exit +/// from the enclosing scope even in the face of exceptions. This is +/// separate from BeecryptMutex because we don't want to make this +/// behavior mandatory. + +class ScopedLock +{ +public: + /// \brief Lock the mutex. + explicit ScopedLock(BeecryptMutex& mutex) : + mutex_(mutex) + { + mutex.lock(); + } + +#if __cplusplus >= 201103L + // Disallow copies and assignments + ScopedLock(const ScopedLock&) = delete; + const ScopedLock& operator =(const ScopedLock&) = delete; +#endif + + /// \brief Unlock the mutex. + ~ScopedLock() { mutex_.unlock(); } + +private: +#if __cplusplus < 201103L + // Pre-C++11 alternatives to disallow copies and assignments. + ScopedLock(const ScopedLock&); + ScopedLock& operator =(const ScopedLock&); +#endif + + BeecryptMutex& mutex_; ///< the mutex object we manage +}; + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_BEEMUTEX_H) + diff --git a/include/mysql++/cmdline.h b/include/mysql++/cmdline.h new file mode 100644 index 0000000..b0dac04 --- /dev/null +++ b/include/mysql++/cmdline.h @@ -0,0 +1,241 @@ +/*********************************************************************** + cmdline.h - Declares the interface to the MySQL++'s command line + parsing logic, used by the examples and the utility programs. + Not intended for use by third parties! If it breaks, you + get to keep all the pieces. + + Copyright (c) 2007-2009 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the + CREDITS.txt file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_CMDLINE_H) +#define MYSQLPP_CMDLINE_H + +#include "common.h" + +#include +#include + +#include + +namespace mysqlpp { + /// \brief Parses command line arguments and holds the results. + /// + /// This class just contains common functionality and data + /// structures; instantiable subclasses follow. + class MYSQLPP_EXPORT CommandLineBase + { + public: + //// Public types + /// \brief Type for a list of arguments + typedef std::vector ArgumentList; + /// \brief Iterator into ArgumentList + typedef ArgumentList::const_iterator ArgumentListIt; + + //// Public interface + /// \brief Get reference to list of command line arguments past + /// the last flag and its possible argument. + const ArgumentList& extra_args() const + { return extra_args_; } + + /// \brief Return truthy value if command line was parsed + /// successfully + operator void*() const + { + return successful_ ? const_cast(&successful_) : 0; + } + + protected: + //// Subclass interface + /// \brief Hidden ctor to prevent instantiation + CommandLineBase(int argc, char* const argv[], const char* opts) : + argc_(argc), + argv_(argv), + opts_(opts), + successful_(argc > 0 && argv && opts) + { + assert(successful_); + } + /// \brief Hidden dtor to prevent instantiation + virtual ~CommandLineBase() { } + + /// \brief If object is still marked as "successful", save + /// non-option arguments to extra_args_ list. Subclass ctor + /// should call this after the parse_next() loop gets EOF. + void finish_parse(); + + /// \brief Accessor for getopt()'s optarg global + const char* option_argument() const; + /// \brief Accessor for getopt()'s optind global + int option_index() const; + + /// \brief Called by a subclass when encountering a command + /// line parsing error. + /// + /// Prints the passed message, calls subclass's print_usage(), + /// and marks the object as no longer successful. + void parse_error(const char* message = 0); + + /// \brief Wrapper for getopt() + int parse_next() const; + + /// \brief Show a message explaining the program's proper usage + virtual void print_usage() const = 0; + + /// \brief Get the file name of the program's executable + const char* program_name() const { return argv_[0]; } + + /// \brief Returns true if nothing has gone wrong since calling + /// the ctor. + bool successful() const { return successful_; } + + private: + //// Internal data + int argc_; + char* const* argv_; + const char* opts_; + bool successful_; + ArgumentList extra_args_; + }; + + + /// \brief Stuff related to MySQL++ examples specifically + namespace examples { + /// \brief Name of examples' DB + extern MYSQLPP_EXPORT const char* db_name; + + /// \brief Command line parsing mechanism for ../examples/*.cpp + class MYSQLPP_EXPORT CommandLine : public CommandLineBase + { + public: + //// Public interface + /// \brief Constructor + CommandLine(int argc, char* const argv[], + const char* user = 0, const char* pass = 0, + const char* usage_extra = 0); + + /// \brief Show a message explaining the program's proper usage + /// + /// Calls print_usage(const char*), passing along the + /// "usage_extra" parameter passed to the ctor + void print_usage() const { print_usage(usage_extra_); } + + /// \brief Show a message explaining the program's proper + /// usage, with custom extra info after standard command + /// line usage bits. + void print_usage(const char* extra) const; + + /// \brief Return true if we're in "dtest" mode + /// This happens when an example gets the -D flag, always + /// passed by the dtest script to ask the programs it runs + /// to suppress any nondeterministic output. + bool dtest_mode() const { return dtest_mode_; } + + /// \brief Return the DB password (-p argument) + const char* pass() const { return pass_; } + + /// \brief Return the -m flag value + /// + /// This flag is currently only used by examples/deadlock, + /// but it's really a nonspecific "mode" value, which could + /// be used by other examples in the future. + int run_mode() const { return run_mode_; } + + /// \brief Return the DB server name (-s argument) + const char* server() const { return server_; } + + /// \brief Return the DB user name (-u argument) + const char* user() const { return user_; } + + private: + //// Internal data + // Examples-specific command line parse results + bool dtest_mode_; + int run_mode_; + const char* server_; + const char* user_; + const char* pass_; + const char* usage_extra_; + }; + } // end namespace mysqlpp::examples + + + /// \brief Stuff specific to the ssqlsxlat tool + namespace ssqlsxlat { + /// \brief Command line parser for MySQL++'s ssqlsxlat tool + class MYSQLPP_EXPORT CommandLine : public CommandLineBase + { + public: + //// Public types + /// \brief Types of inputs that ssqlsxlat will accept + enum SourceSink { + ss_unknown, ///< no known input type given yet + ss_ssqls1, ///< a C++ file containing an SSQLS v1 declaration + ss_ssqls2, ///< an SSQLS v2 file + ss_table ///< an existing DB table schema + }; + + //// Public interface + /// \brief Constructor + CommandLine(int argc, char* const argv[]); + + /// \brief Show a message explaining the program's proper usage + void print_usage() const; + + /// \brief Return the name of the input source + /// + /// This can be a file name, a table name, etc. Call + /// input_source() to determine the proper interpretation. + const char* input() const { return input_; } + + /// \brief The input source type + SourceSink input_source() const { return input_source_; } + + /// \brief The output sink (destination) type + SourceSink output_sink() const { return output_sink_; } + + /// \brief The base name of the output file + const char* output() const { return output_; } + + /// \brief DB password, when input type is is_table + const char* pass() const { return pass_; } + + /// \brief DB server name, when input type is is_table + const char* server() const { return server_; } + + /// \brief DB user name, when input type is is_table + const char* user() const { return user_; } + + private: + //// Internal data: command line parse results + const char* input_; + const char* output_; + const char* pass_; + const char* server_; + const char* user_; + SourceSink input_source_; + SourceSink output_sink_; + }; + } // end namespace mysqlpp::ssqlsxlat +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_CMDLINE_H) + diff --git a/include/mysql++/common.h b/include/mysql++/common.h new file mode 100644 index 0000000..5cd7182 --- /dev/null +++ b/include/mysql++/common.h @@ -0,0 +1,262 @@ +/// \file common.h +/// \brief This file includes top-level definitions for use both +/// internal to the library, and outside it. Contrast mysql++.h +/// +/// This file mostly takes care of platform differences. + +/*********************************************************************** + Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB, + © 2004-2009, 2018 by Educational Technology Resources, Inc., and + © 2009 by Warren Young. Others may also hold copyrights on code + in this file. See the CREDITS.txt file in the top directory of the + distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_COMMON_H) +#define MYSQLPP_COMMON_H + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for the following stuff. + +// Enable SSQLS by default. Turned off below on platforms where we +// know it doesn't work. +#define MYSQLPP_SSQLS_COMPATIBLE + +// For all platforms but Visual C++ 2003, the following macro is just +// an alias for "*this". It needs a more complicated definition on +// VC++ 2003 to work around an error in the overloaded operator lookup +// logic. For an explanation of the problem, see: +// http://groups.google.com/group/microsoft.public.vc.stl/browse_thread/thread/9a68d84644e64f15 +#define MYSQLPP_QUERY_THISPTR *this + +// Work out major platform-specific stuff here. +#if defined(__WIN32__) || defined(_WIN32) +# define MYSQLPP_PLATFORM_WINDOWS + // Windows compiler support. Tested with Microsoft Visual C++, + // Borland C++ Builder, and MinGW GCC. + + // Don't let windows.h (via Connector/C) #define min/max + #define NOMINMAX + + // Stuff for Visual C++ only +# if defined(_MSC_VER) +# define MYSQLPP_PLATFORM_VISUAL_CPP + // MS *still* doesn't ship stdint.h, through VC++ 2008 at least. + // This means we have to take a wild guess at appropriate + // integer types in lib/sql_types.h. See test/inttypes.cpp for + // tests that check whether we've guessed well. +# define MYSQLPP_NO_STDINT_H +# if _MSC_VER < 1400 + // Workarounds for limitations of VC++ 2003 that are fixed + // in 2005 and later. +# undef MYSQLPP_QUERY_THISPTR +# define MYSQLPP_QUERY_THISPTR dynamic_cast(*this) +# undef MYSQLPP_SSQLS_COMPATIBLE +# elif !defined(_STLP_VERSION) && !defined(_STLP_VERSION_STR) + // VC++ 2005 or newer and not using STLport, so #define + // portability flags indicating features we can use from + // the compiler's native RTL. +# define MYSQLPP_HAVE_LOCALTIME_S +# define MYSQLPP_HAVE_STD__NOINIT +# endif + + // Disable complaints about STL data members: VC++ believes + // these need to be __declspec(dllexport) for some reason. +# pragma warning(disable: 4251) + // Disable complaint that VC++ doesn't grok throw specs +# pragma warning(disable: 4290) + // Disable whining about using 'this' as a member initializer on VC++. +# pragma warning(disable: 4355) + // Disable whining about implicit conversions to bool +# pragma warning(disable: 4800) + // Disable nagging about new "secure" functions like strncpy_s() +# pragma warning(disable: 4996) + + // Disable warning about exporting a class from a DLL which is + // derived from a non-exported class in another DLL. This is + // safe to do with Standard C++ library types per: + // + // https://msdn.microsoft.com/en-us/library/3tdb471s.aspx + // + // We don't hit this any other way in MySQL++. +# pragma warning(disable: 4275) + + // Squish warning about passing no args to MAY_THROW() when + // building with newer C++ support. We're doing it on purpose. +# pragma warning(disable: 4003) + + // Prior to Visual C++ 2015, we must use _snprintf() +# if _MSC_VER < 1900 +# define snprintf _snprintf +# endif +# endif + + // Define DLL import/export tags for Windows compilers, where we build + // the library into a DLL, for LGPL license compatibility reasons. + // (This is based on a similar mechanism in wxWindows.) + + #ifdef MYSQLPP_MAKING_DLL + // When making the DLL, export tagged symbols, so they appear + // in the import library. + #define MYSQLPP_EXPORT __declspec(dllexport) + #elif !defined(MYSQLPP_NO_DLL) + // We must be _using_ the DLL, so import symbols instead. + #define MYSQLPP_EXPORT __declspec(dllimport) + #else + // Not making a DLL at all, so no-op these declspecs + #define MYSQLPP_EXPORT + #endif + + // We need to use the DOS/Windows path separator here + #define MYSQLPP_PATH_SEPARATOR '\\' +#else + // If not VC++, MinGW, or Xcode, we assume we're on a system using + // autoconf, so bring in the config.h file it wrote containing the + // config test results. Only do this during the library build, and + // even then, not if included from a MySQL++ header file, since + // config.h cannot be safely installed with the other headers. +# if defined(MYSQLPP_NOT_HEADER) && !defined(MYSQLPP_XCODE) +# include "config.h" +# endif + + // Make DLL stuff a no-op on this platform. + #define MYSQLPP_EXPORT + + // Assume POSIX path separator + #define MYSQLPP_PATH_SEPARATOR '/' +#endif + +// Workarounds for deprecations in C++11 and newer. We must still +// support systems whose contemporaneous C++ compiler only understands +// C++98. Because of the large gap between C++98 and C++11, it will +// likely be years yet until we can start using C++11 unconditionally +// within MySQL++, then years more until we can use C++14, etc. +// +// C++11 deprecated throwspecs, a feature of C++ that is only used by +// the oldest parts of MySQL++. We can't drop the throwspecs until +// MySQL++ 4, if we ever get around to that, since that would break +// the library's ABI on systems whose C++ compiler still supports +// throwspecs. This feature isn't completely gone until C++17, but we +// don't want the warnings on certain newer compilers expecting C++11 +// or newer C++ dialects. +#if __cplusplus < 201103L +# define MAY_THROW(what) throw(what) +#else +# define MAY_THROW(junk) noexcept(false) +#endif + +// C++11 added unique_ptr as a replacement for auto_ptr. We don't have +// the ABI problem above with this one, so we switch to it with the +// oldest release possible. As with the above ifdef, this one only +// currently works for g++ and clang++. +#if __cplusplus >= 201103L +# define UNIQUE_PTR(what) std::unique_ptr +#else +# define UNIQUE_PTR(what) std::auto_ptr +#endif + + +namespace mysqlpp { + +/// \brief Alias for 'true', to make code requesting exceptions more +/// readable. +const bool use_exceptions = true; + +/// \brief Used to disambiguate overloads of equal_list() in SSQLSes. +enum sql_cmp_type { sql_use_compare }; + +#if !defined(DOXYGEN_IGNORE) +// Figure out how to get large integer support on this system. Suppress +// refman documentation for these typedefs, as they're system-dependent. +#if defined(MYSQLPP_NO_LONG_LONGS) +// Alias "longlong" and "ulonglong" to the regular "long" counterparts +typedef unsigned long ulonglong; +typedef long longlong; +#elif defined(_MSC_VER) +// It's VC++, so we'll use Microsoft's 64-bit integer types +typedef unsigned __int64 ulonglong; +typedef __int64 longlong; +#else +// No better idea, so assume the C99 convention. If your compiler +// doesn't support this, please provide a patch to extend this ifdef, or +// define MYSQLPP_NO_LONG_LONGS. +typedef unsigned long long ulonglong; +typedef long long longlong; +#endif +#endif // !defined(DOXYGEN_IGNORE) + +#if !defined(MYSQLPP_NO_UNSIGNED_INT_TYPES) +/// \brief Contraction for 'unsigned long' +/// +/// This is not to be used within the library or directly by end-user +/// code. It exists to make the MySQL C API headers happy: my_global.h +/// defines it, but we can't use it in MySQL++, so we do it ourselves. +typedef unsigned long ulong; +#endif + +} // end namespace mysqlpp + +// The MySQL headers define these macros, which is completely wrong in a +// C++ project. Undo the damage. +#undef min +#undef max + +#endif // !defined(DOXYGEN_IGNORE) + + +// Now that we've defined all the stuff above, we can pull in the full +// MySQL header. Basically, the above largely replaces MySQL's my_global.h +// while actually working with C++. This is why we disobey the MySQL +// developer docs, which recommend including my_global.h before mysql.h. +extern "C" { +#if defined(MYSQLPP_MYSQL_HEADERS_BURIED) +# include +#else +# include +#endif +} + +// The Unicode chapter of the user manual justifies the following. +#if MYSQL_VERSION_ID >= 50500 + /// \brief Use this macro in CREATE TABLE strings to get the best + /// available UTF-8 character set. + /// + /// MySQL++ is built against MySQL or MariaDB 5.5 or newer, so these + /// macros are defined so that programs using them get the complete + /// UTF-8 character set. +# define MYSQLPP_UTF8_CS "utf8mb4" + + /// \brief Use this macro in CREATE TABLE strings to get a matching + /// collation to the character set selected by MYSQLPP_UTF8_CS +# define MYSQLPP_UTF8_COL "utf8mb4_general_ci" +#else + /// \brief Use this macro in CREATE TABLE strings to get the best + /// available UTF-8 character set and correpsonding collation. + /// + /// MySQL++ is built against a version of MySQL or MariaDB older than + /// 5.5, so we must use the legacy 3-byte-limited subset of UTF-8. +# define MYSQLPP_UTF8_CS "utf8" + + /// \brief Use this macro in CREATE TABLE strings to get a matching + /// collation to the character set selected by MYSQLPP_UTF8_CS +# define MYSQLPP_UTF8_COL "utf8_general_ci" +#endif + +#endif // !defined(MYSQLPP_COMMON_H) diff --git a/include/mysql++/comparable.h b/include/mysql++/comparable.h new file mode 100644 index 0000000..cde42a1 --- /dev/null +++ b/include/mysql++/comparable.h @@ -0,0 +1,98 @@ +/// \file comparable.h +/// \brief Declares the Comparable mixin + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and + (c) 2004-2008 by Educational Technology Resources, Inc. Others may + also hold copyrights on code in this file. See the CREDITS.txt file + in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_COMPARABLE_H) +#define MYSQLPP_COMPARABLE_H + +namespace mysqlpp { + +/// \brief Mix-in that gives its subclass a full set of comparison +/// operators. +/// +/// Simply by inheriting publically from this and implementing +/// compare(), the subclass gains a full set of comparison operators, +/// because all of the operators are implemented in terms of compare(). +template +class Comparable +{ +public: + /// \brief Returns true if "other" is equal to this object + bool operator ==(const T& other) const + { + return !compare(other); + } + + /// \brief Returns true if "other" is not equal to this object + bool operator !=(const T& other) const + { + return compare(other); + } + + /// \brief Returns true if "other" is less than this object + bool operator <(const T& other) const + { + return compare(other) < 0; + } + + /// \brief Returns true if "other" is less than or equal to this object + bool operator <=(const T& other) const + { + return compare(other) <= 0; + } + + /// \brief Returns true if "other" is greater than this object + bool operator >(const T& other) const + { + return compare(other) > 0; + } + + /// \brief Returns true if "other" is greater than or equal to this object + bool operator >=(const T& other) const + { + return compare(other) >= 0; + } + +protected: + /// \brief Destroy object + /// + /// This class has nothing to destroy, but declaring the dtor + /// virtual placates some compilers set to high warning levels. + /// Protecting it ensures you can't delete subclasses through base + /// class pointers, which makes no sense because this class isn't + /// made for polymorphism. It's just a mixin. + virtual ~Comparable() { } + + /// \brief Compare this object to another of the same type + /// + /// Returns < 0 if this object is "before" the other, 0 of they are + /// equal, and > 0 if this object is "after" the other. + virtual int compare(const T& other) const = 0; +}; + +} + +#endif // !defined(MYSQLPP_COMPARABLE_H) diff --git a/include/mysql++/connection.h b/include/mysql++/connection.h new file mode 100644 index 0000000..8cf7390 --- /dev/null +++ b/include/mysql++/connection.h @@ -0,0 +1,368 @@ +/// \file connection.h +/// \brief Declares the Connection class. +/// +/// Every program using MySQL++ must create a Connection object, which +/// manages information about the connection to the database server, and +/// performs connection-related operations once the connection is up. +/// Subordinate classes, such as Query and Row take their defaults as +/// to whether exceptions are thrown when errors are encountered from +/// the Connection object that created them, directly or indirectly. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and + (c) 2004-2007 by Educational Technology Resources, Inc. Others may + also hold copyrights on code in this file. See the CREDITS.txt file + in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_CONNECTION_H) +#define MYSQLPP_CONNECTION_H + +#include "common.h" + +#include "noexceptions.h" +#include "options.h" + +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT Query; +class DBDriver; +#endif + +/// \brief Manages the connection to the database server. +/// +/// This class is a thick wrapper around DBDriver, adding high-level +/// error handling, utility functions, and abstraction away from +/// underlying C API details. + +class MYSQLPP_EXPORT Connection : public OptionalExceptions +{ +private: + /// \brief Pointer to bool data member, for use by safe bool + /// conversion operator. + /// + /// \see http://www.artima.com/cppsource/safebool.html + typedef bool Connection::*private_bool_type; + +public: + /// \brief Create object without connecting to the database server. + /// + /// \param te if true, exceptions are thrown on errors + Connection(bool te = true); + + /// \brief Create object and connect to database server in one step. + /// + /// This constructor allows you to most fully specify the options + /// used when connecting to the database server. + /// + /// \param db name of database to select upon connection + /// \param server specifies the IPC method and parameters for + /// contacting the server; see below for details + /// \param user user name to log in under, or 0 to use the user + /// name this program is running under + /// \param password password to use when logging in + /// \param port TCP port number database server is listening on, or + /// 0 to use default value; note that you may also give this as + /// part of the \c server parameter + /// + /// The server parameter can be any of several different forms: + /// + /// - \b 0: Let the database driver decide how to connect; usually + /// some sort of localhost IPC method. + /// - \b ".": On Windows, this means named pipes, if the server + /// supports it + /// - \b "/some/domain/socket/path": If the passed string doesn't + /// match one of the previous alternatives and we're on a system + /// that supports Unix domain sockets, MySQL++ will test it to see + /// if it names one, and use it if we have permission. + /// - \b "host.name.or.ip:port": If the previous test fails, or if + /// the system doesn't support Unix domain sockets at all, it + /// assumes the string is some kind of network address, optionally + /// followed by a colon and port. The name can be in dotted quad + /// form, a host name, or a domain name. The port can either be a + /// TCP/IP port number or a symbolic service name. If a port or + /// service name is given here and a nonzero value is passed for + /// the \c port parameter, the latter takes precedence. + Connection(const char* db, const char* server = 0, const char* user = 0, + const char* password = 0, unsigned int port = 0); + + /// \brief Establish a new connection using the same parameters as + /// an existing connection. + /// + /// \param other existing Connection object + Connection(const Connection& other); + + /// \brief Destroy object + virtual ~Connection(); + + /// \brief Get version of library underpinning the current database + /// driver. + std::string client_version() const; + + /// \brief Connect to database after object is created. + /// + /// It's better to use the connect-on-create constructor if you can. + /// See its documentation for the meaning of these parameters. + /// + /// If you call this method on an object that is already connected + /// to a database server, the previous connection is dropped and a + /// new connection is established. + virtual bool connect(const char* db = 0, const char* server = 0, + const char* user = 0, const char* password = 0, + unsigned int port = 0); + + /// \brief Returns true if connection was established successfully + /// + /// \return true if connection was established successfully + bool connected() const; + + /// \brief Returns the number of rows in a table + /// + /// \param table name of table whose rows you want counted + /// + /// This is syntactic sugar for a \c SELECT \c COUNT(*) + /// \c FROM \c table SQL query. + ulonglong count_rows(const std::string& table); + + /// \brief Ask the database server to create a database + /// + /// \param db name of database to create + /// + /// \return true if database was created successfully + bool create_db(const std::string& db); + + /// \brief Drop the connection to the database server + void disconnect(); + + /// \brief Returns a reference to the current database driver + /// + /// \internal This exists mostly for the benefit of Query, Result + /// and ResUse. If there is something you want to use in the + /// DBDriver interface, look for something similar in one of these + /// classes instead. If you still can't find it, send a message to + /// the mailing list asking about it. Unless you're doing something + /// very low-level, there should never be a reason to use the + /// driver directly. + DBDriver* driver() { return driver_; } + + /// \brief Asks the database server to drop (destroy) a database + /// + /// \param db name of database to destroy + /// + /// \return true if database was dropped successfully + bool drop_db(const std::string& db); + + /// \brief Return last error number associated with this + /// connection + int errnum(); + + /// \brief Return error message for last error associated with + /// this connection. + /// + /// Returns either a MySQL++-specific error message if one exists, + /// or one from the current database driver otherwise. + const char* error() const; + + /// \brief Get information about the IPC connection to the + /// database server + /// + /// String contains info about type of connection (e.g. TCP/IP, + /// named pipe, Unix socket...) and the server hostname. + std::string ipc_info() const; + + /// \brief Kill a database server thread + /// + /// \param tid ID of thread to kill + /// + /// \see thread_id() + bool kill(unsigned long tid) const; + + /// \brief Test whether any error has occurred within the object. + /// + /// Allows the object to be used in bool context, like this: + /// + /// \code + /// Connection conn; + /// .... use conn + /// if (conn) { + /// ... nothing bad has happened since last successful use + /// } + /// else { + /// ... some error has occurred + /// } + /// \endcode + /// + /// Prior to MySQL++ v3, the object was always falsy when we + /// weren't connected. Now a true return simply indicates a lack of + /// errors. If you've been using this to test for whether the + /// connection is still up, you need to call connected() instead. + operator private_bool_type() const + { + return copacetic_ ? &Connection::copacetic_ : 0; + } + + /// \brief Copy an existing Connection object's state into this + /// object. + Connection& operator=(const Connection& rhs); + + /// \brief "Pings" the database server + /// + /// \retval true if server is responding + /// \retval false if either we already know the connection is down + /// and cannot re-establish it, or if the server did not respond to + /// the ping and we could not re-establish the connection. + bool ping(); + + /// \brief Returns version number of the protocol the database + /// driver uses to communicate with the server. + int protocol_version() const; + + /// \brief Return a new query object. + /// + /// The returned query object is tied to this connection object, + /// so when you call a method like + /// \link Query::execute() execute() \endlink + /// on that object, the query is sent to the server this object + /// is connected to. + /// + /// \param qstr an optional query string for populating the + /// new Query object + Query query(const char* qstr = 0); + + /// \brief Return a new query object + /// + /// \param qstr initial query string + Query query(const std::string& qstr); + + /// \brief Change to a different database managed by the + /// database server we are connected to. + /// + /// \param db database to switch to + /// + /// \retval true if we changed databases successfully + bool select_db(const std::string& db); + + /// \brief Get the database server's version string + std::string server_version() const; + + /// \brief Sets a connection option + /// + /// \param o pointer to any derivative of Option allocated on + /// the heap + /// + /// Objects passed to this method and successfully set will be + /// released when this Connection object is destroyed. If an error + /// occurs while setting the option the object will be deleted + /// immediately. + /// + /// Because there are so many Option subclasses, the actual effect + /// of this function has a wide range. This mechanism abstracts + /// away many things that are unrelated down at the database driver + /// level, hiding them behind a coherent, type-safe interface. + /// + /// The rules about which options can be set, when, are up to the + /// underlying database driver. Some must be set before the + /// connection is established because they can only be used during + /// that connection setup process. Others can be set at any time + /// after the connection comes up. If you get it wrong, you'll get + /// a BadOption exception. + /// + /// \retval true if option was successfully set + bool set_option(Option* o); + + /// \brief Ask database server to shut down. + bool shutdown(); + + /// \brief Returns information about database server's status + std::string server_status() const; + + /// \brief Returns true if both MySQL++ and database driver we're + /// using were compiled with thread awareness. + static bool thread_aware(); + + /// \brief Tells the underlying database driver that this thread + /// is done using the library. + static void thread_end(); + + /// \brief Returns the database server's thread ID for this connection + /// + /// This has nothing to do with threading on the client side. The + /// only thing you can do with this value is pass it to kill(). + unsigned long thread_id(); + + /// \brief Tells the underlying database driver that the current + /// thread is now using its services. + /// + /// It's not necessary to call this from the thread that creates + /// the connection as it's done automatically. This method exists + /// for times when multiple threads may use this object; it allows + /// the underlying database driver to set up any per-thread data + /// structures it needs. + /// + /// The MySQL++ user manual's chapter + /// on threads details two major strategies for dealing with + /// connections in the face of threads. The Connection-per-thread + /// option frees you from ever having to call this method. The + /// other documented strategy is to use ConnectionPool, which opens + /// the possibility for one thread to create a connection that + /// another uses, so you do need to call this method in that case, + /// or with any other similar strategy. + /// + /// \retval True if there was no problem + static bool thread_start(); + +protected: + /// \brief Build an error message in the standard form used whenever + /// one of the methods can't succeed because we're not connected to + /// the database server. + void build_error_message(const char* core); + + /// \brief Establish a new connection as a copy of an existing one + /// + /// \param other the connection to copy + void copy(const Connection& other); + + /// \brief Extract elements from the server parameter in formats + /// suitable for passing to DBDriver::connect(). + bool parse_ipc_method(const char* server, std::string& host, + unsigned int& port, std::string& socket_name); + + //// Subclass data + mutable std::string error_message_; ///< MySQL++ specific error, if any + +private: + DBDriver* driver_; + bool copacetic_; +}; + + +} // end namespace mysqlpp + +// Not strictly required, but bring in our specialization subclasses +#include "tcp_connection.h" +#include "uds_connection.h" +#include "wnp_connection.h" + +#endif // !defined(MYSQLPP_CONNECTION_H) + diff --git a/include/mysql++/cpool.h b/include/mysql++/cpool.h new file mode 100644 index 0000000..80068c2 --- /dev/null +++ b/include/mysql++/cpool.h @@ -0,0 +1,255 @@ +/// \file cpool.h +/// \brief Declares the ConnectionPool class. + +/*********************************************************************** + Copyright (c) 2007-2008 by Educational Technology Resources, Inc. and + (c) 2007 by Jonathan Wakely. Others may also hold copyrights on + code in this file. See the CREDITS.txt file in the top directory + of the distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_CPOOL_H) +#define MYSQLPP_CPOOL_H + +#include "beemutex.h" + +#include + +#include +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT Connection; +#endif + +/// \brief Manages a pool of connections for programs that need more +/// than one Connection object at a time, but can't predict how many +/// they need in advance. +/// +/// This class is useful in programs that need to make multiple +/// simultaneous queries on the database; this requires multiple +/// Connection objects due to a hard limitation of the underlying +/// C API. Connection pools are most useful in multithreaded programs, +/// but it can be helpful to have one in a single-threaded program as +/// well. Sometimes it's necessary to get more data from the server +/// while in the middle of processing data from an earlier query; this +/// requires multiple connections. Whether you use a pool or manage +/// connections yourself is up to you, but realize that this class +/// takes care of a lot of subtle details for you that aren't obvious. +/// +/// The pool's policy for connection reuse is to always return the +/// \em most recently used connection that's not being used right now. +/// This ensures that excess connections don't hang around any longer +/// than they must. If the pool were to return the \em least recently +/// used connection, it would be likely to result in a large pool of +/// sparsely used connections because we'd keep resetting the last-used +/// time of whichever connection is least recently used at that moment. + +class MYSQLPP_EXPORT ConnectionPool +{ +public: + /// \brief Create empty pool + ConnectionPool() { } + + /// \brief Destroy object + /// + /// If the pool raises an assertion on destruction, it means our + /// subclass isn't calling clear() in its dtor as it should. + virtual ~ConnectionPool() { assert(empty()); } + + /// \brief Returns true if pool is empty + bool empty() const { return pool_.empty(); } + + /// \brief Return a defective connection to the pool and get a new + /// one back. + /// + /// Call this on receiving a BadQuery exception, with errnum() + /// equal to CR_SERVER_GONE_ERROR. It means the server was + /// restarted or otherwise dropped your connection to it, so the + /// Connection object is no longer usable. You can avoid the + /// need to use this by setting the ReconnectOption in your grab() + /// override, but perhaps there are other reasons to need to + /// exchange a bad connection for a good one. + /// + /// This function wraps grab(), not safe_grab(), even though that + /// could return another dead connection. The assumption is that if + /// your code is smart enough to detect one bad connection, it should + /// be smart enough to detect a whole string of them. Worst case, + /// the whole pool is bad -- remote server went away -- and we have + /// to empty the pool and start re-filling it. + /// + /// \param pc pointer to a Connection object to be returned to the + /// pool and marked as unused. + /// + /// \retval a pointer to a different Connection object; not + /// guaranteed to still be connected! + virtual Connection* exchange(const Connection* pc); + + /// \brief Grab a free connection from the pool. + /// + /// This method creates a new connection if an unused one doesn't + /// exist, and destroys any that have remained unused for too long. + /// If there is more than one free connection, we return the most + /// recently used one; this allows older connections to die off over + /// time when the caller's need for connections decreases. + /// + /// Do not delete the returned pointer. This object manages the + /// lifetime of connection objects it creates. + /// + /// \retval a pointer to the connection + virtual Connection* grab(); + + /// \brief Return a connection to the pool + /// + /// Marks the connection as no longer in use. + /// + /// The pool updates the last-used time of a connection only on + /// release, on the assumption that it was used just prior. There's + /// nothing forcing you to do it this way: your code is free to + /// delay releasing idle connections as long as it likes. You + /// want to avoid this because it will make the pool perform poorly; + /// if it doesn't know approximately how long a connection has + /// really been idle, it can't make good judgements about when to + /// remove it from the pool. + /// + /// \param pc pointer to a Connection object to be returned to the + /// pool and marked as unused. + virtual void release(const Connection* pc); + + /// \brief Removes the given connection from the pool + /// + /// If you mean to simply return a connection to the pool after + /// you're finished using it, call release() instead. This method + /// is primarily for error handling: you somehow have figured out + /// that the connection is defective, so want it destroyed and + /// removed from the pool. If you also want a different connection + /// to retry your operation on, call exchange() instead. + /// + /// \param pc pointer to a Connection object to be removed from + /// the pool and destroyed + void remove(const Connection* pc); + + /// \brief Grab a free connection from the pool, testing that it's + /// connected before returning it. + /// + /// This is just a wrapper around grab(), Connection::ping() and + /// release(), and is thus less efficient than grab(). Use it only + /// when it's possible for MySQL server connections to go away + /// unexpectedly, such as when the DB server can be restarted out + /// from under your application. + /// + /// \retval a pointer to the connection + virtual Connection* safe_grab(); + + /// \brief Remove all unused connections from the pool + void shrink() { clear(false); } + +protected: + /// \brief Drains the pool, freeing all allocated memory. + /// + /// A derived class must call this in its dtor to avoid leaking all + /// Connection objects still in existence. We can't do it up at + /// this level because this class's dtor can't call our subclass's + /// destroy() method. + /// + /// \param all if true, remove all connections, even those in use + void clear(bool all = true); + + /// \brief Create a new connection + /// + /// Subclasses must override this. + /// + /// Essentially, this method lets your code tell ConnectionPool + /// what server to connect to, what login parameters to use, what + /// connection options to enable, etc. ConnectionPool can't know + /// any of this without your help. + /// + /// \retval A connected Connection object + virtual Connection* create() = 0; + + /// \brief Destroy a connection + /// + /// Subclasses must override this. + /// + /// This is for destroying the objects returned by create(). + /// Because we can't know what the derived class did to create the + /// connection we can't reliably know how to destroy it. + virtual void destroy(Connection*) = 0; + + /// \brief Returns the maximum number of seconds a connection is + /// able to remain idle before it is dropped. + /// + /// Subclasses must override this as it encodes a policy issue, + /// something that MySQL++ can't declare by fiat. + /// + /// \retval number of seconds before an idle connection is destroyed + /// due to lack of use + virtual unsigned int max_idle_time() = 0; + + /// \brief Returns the current size of the internal connection pool. + size_t size() const { return pool_.size(); } + +private: + //// Internal types + struct ConnectionInfo { + Connection* conn; + time_t last_used; + bool in_use; + + ConnectionInfo(Connection* c) : + conn(c), + last_used(time(0)), + in_use(true) + { + } + + // Strict weak ordering for ConnectionInfo objects. + // + // This ordering defines all in-use connections to be "less + // than" those not in use. Within each group, connections + // less recently touched are less than those more recent. + bool operator<(const ConnectionInfo& rhs) const + { + const ConnectionInfo& lhs = *this; + return lhs.in_use == rhs.in_use ? + lhs.last_used < rhs.last_used : + lhs.in_use; + } + }; + typedef std::list PoolT; + typedef PoolT::iterator PoolIt; + + //// Internal support functions + Connection* find_mru(); + void remove(const PoolIt& it); + void remove_old_connections(); + + //// Internal data + PoolT pool_; + BeecryptMutex mutex_; +}; + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_CPOOL_H) + diff --git a/include/mysql++/datetime.h b/include/mysql++/datetime.h new file mode 100644 index 0000000..62faf50 --- /dev/null +++ b/include/mysql++/datetime.h @@ -0,0 +1,462 @@ +/// \file datetime.h +/// \brief Declares classes to add SQL-compatible date and time +/// types to C++'s type system. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and + (c) 2004-2008 by Educational Technology Resources, Inc. Others may + also hold copyrights on code in this file. See the CREDITS.txt file + in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + MySQL++ is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_DATETIME_H) +#define MYSQLPP_DATETIME_H + +#include "common.h" + +#include "comparable.h" + +#include +#include + +namespace mysqlpp { + +/// \brief C++ form of SQL's DATETIME type. +/// +/// This object exists primarily for conversion purposes. You can +/// initialize it in several different ways, and then convert the object +/// to SQL string form, extract the individual y/m/d h:m:s values, +/// convert it to C's time_t, etc. + +class MYSQLPP_EXPORT DateTime : public Comparable +{ +public: + /// \brief Default constructor + DateTime() : + Comparable(), + year_(0), + month_(0), + day_(0), + hour_(0), + minute_(0), + second_(0), + now_(true) + { + } + + /// \brief Initialize object from discrete y/m/d h:m:s values. + /// + /// \param y year, 1000-9999 + /// \param mon month, 1-12 + /// \param d day of month, 1-31 + /// \param h hour, 0-23 + /// \param min minute, 0-59 + /// \param s second, 0-59 + DateTime(unsigned short y, unsigned char mon, unsigned char d, + unsigned char h, unsigned char min, unsigned char s) : + Comparable(), + year_(y), + month_(mon), + day_(d), + hour_(h), + minute_(min), + second_(s), + now_(false) + { + } + + /// \brief Initialize object as a copy of another Date + DateTime(const DateTime& other) : + Comparable(), + year_(other.year_), + month_(other.month_), + day_(other.day_), + hour_(other.hour_), + minute_(other.minute_), + second_(other.second_), + now_(other.now_) + { + } + + /// \brief Initialize object from a C string containing a SQL + /// date-and-time string + /// + /// String must be in the HH:MM:SS format. It doesn't have to be + /// zero-padded. + explicit DateTime(const char* str) { convert(str); } + + /// \brief Initialize object from a C++ string containing a + /// SQL date-and-time string + /// + /// This works with any stringish class that declares a c_str() + /// member function: std::string, mysqlpp::String... + /// + /// \sa DateTime(const char*) + template + explicit DateTime(const Str& str) + { + convert(str.c_str()); + } + + /// \brief Initialize object from a \c time_t + explicit DateTime(time_t t); + + /// \brief Compare this object to another. + /// + /// Returns < 0 if this object is before the other, 0 of they are + /// equal, and > 0 if this object is after the other. + int compare(const DateTime& other) const; + + /// \brief Parse a SQL date and time string into this object. + const char* convert(const char*); + + /// \brief Get the date/time value's day part, 1-31 + unsigned char day() const { return day_; } + + /// \brief Change the date/time value's day part, 1-31 + void day(unsigned char d) { day_ = d; now_ = false; } + + /// \brief Get the date/time value's hour part, 0-23 + unsigned char hour() const { return hour_; } + + /// \brief Change the date/time value's hour part, 0-23 + void hour(unsigned char h) { hour_ = h; now_ = false; } + + /// \brief Returns true if object will evaluate to SQL "NOW()" on + /// conversion to string. + bool is_now() const { return now_; } + + /// \brief Get the date/time value's minute part, 0-59 + unsigned char minute() const { return minute_; } + + /// \brief Change the date/time value's minute part, 0-59 + void minute(unsigned char m) { minute_ = m; now_ = false; } + + /// \brief Get the date/time value's month part, 1-12 + unsigned char month() const { return month_; } + + /// \brief Change the date/time value's month part, 1-12 + void month(unsigned char m) { month_ = m; now_ = false; } + + /// \brief Factory to create an object instance that will convert + /// to SQL "NOW()" on insertion into a query + /// + /// This is just syntactic sugar around the default ctor + static DateTime now() { return DateTime(); } + + /// \brief Convert to std::string + operator std::string() const; + + /// \brief Convert to time_t + operator time_t() const; + + /// \brief Get the date/time value's second part, 0-59 + unsigned char second() const { return second_; } + + /// \brief Change the date/time value's second part, 0-59 + void second(unsigned char s) { second_ = s; now_ = false; } + + /// \brief Return our value in std::string form + std::string str() const { return *this; } + + /// \brief Get the date/time value's year part + /// + /// There's no trickery here like in some date/time implementations + /// where you have to add 1900 or something like that. It simply + /// returns the year in natural form, in the range 1000-9999. + unsigned short year() const { return year_; } + + /// \brief Change the date/time value's year part + /// + /// Pass the year value normally; we don't optimize the value by + /// subtracting 1900 like some other date/time implementations. + void year(unsigned short y) { year_ = y; now_ = false; } + +private: + unsigned short year_; ///< the year, as a simple integer + unsigned char month_; ///< the month, 1-12 + unsigned char day_; ///< the day, 1-31 + unsigned char hour_; ///< the hour, 0-23 (not 0-255 as in Time!) + unsigned char minute_; ///< the minute, 0-59 + unsigned char second_; ///< the second, 0-59 + + bool now_; ///< true if object not initialized with explicit value +}; + + +/// \brief Returns a DateTime object that, when inserted into query +/// will yield a SQL "NOW()" function call. +inline DateTime NOW() { return DateTime(); } + + +/// \brief Inserts a DateTime object into a C++ stream in a +/// SQL-compatible format. +/// +/// The date and time are inserted into the stream, in that order, +/// with a space between them. +/// +/// \param os stream to insert date and time into +/// \param dt date/time object to insert into stream +MYSQLPP_EXPORT std::ostream& operator <<(std::ostream& os, + const DateTime& dt); + + +/// \brief C++ form of SQL's DATE type. +/// +/// Objects of this class can be inserted into streams, and +/// initialized from SQL DATE strings. +class MYSQLPP_EXPORT Date : public Comparable +{ +public: + /// \brief Default constructor + Date() : year_(0), month_(0), day_(0) { } + + /// \brief Initialize object + /// + /// \param y year, 1000-9999 + /// \param m month, 1-12 + /// \param d day of month, 1-31 + Date(unsigned short y, unsigned char m, unsigned char d) : + Comparable(), + year_(y), + month_(m), + day_(d) + { + } + + /// \brief Initialize object as a copy of another Date + Date(const Date& other) : + Comparable(), + year_(other.year_), + month_(other.month_), + day_(other.day_) + { + } + + /// \brief Initialize object from date part of date/time object + Date(const DateTime& other) : + Comparable(), + year_(other.year()), + month_(other.month()), + day_(other.day()) + { + } + + /// \brief Initialize object from a C string containing a date + /// + /// String must be in the YYYY-MM-DD format. It doesn't have to be + /// zero-padded. + explicit Date(const char* str) { convert(str); } + + /// \brief Initialize object from a C++ string containing a date + /// + /// This works with any stringish class that declares a c_str() + /// member function: std::string, mysqlpp::String... + /// + /// \sa Date(const char*) + template + explicit Date(const Str& str) { convert(str.c_str()); } + + /// \brief Initialize object from a \c time_t + /// + /// Naturally, we throw away the "time" part of the \c time_t. If + /// you need to keep it, you want to use DateTime instead. + explicit Date(time_t t); + + /// \brief Compare this date to another. + /// + /// Returns < 0 if this date is before the other, 0 of they are + /// equal, and > 0 if this date is after the other. + int compare(const Date& other) const; + + /// \brief Parse a SQL date string into this object. + const char* convert(const char*); + + /// \brief Get the date's day part, 1-31 + unsigned char day() const { return day_; } + + /// \brief Change the date's day part, 1-31 + void day(unsigned char d) { day_ = d; } + + /// \brief Get the date's month part, 1-12 + unsigned char month() const { return month_; } + + /// \brief Change the date's month part, 1-12 + void month(unsigned char m) { month_ = m; } + + /// \brief Convert to std::string + operator std::string() const; + + /// \brief Convert to time_t + /// + /// The "time" part of the \c time_t is "now" + operator time_t() const; + + /// \brief Return our value in std::string form + std::string str() const { return *this; } + + /// \brief Get the date's year part + /// + /// There's no trickery here like in some date implementations + /// where you have to add 1900 or something like that. + unsigned short year() const { return year_; } + + /// \brief Change the date's year part + /// + /// Pass the year value normally; we don't optimize the value by + /// subtracting 1900 like some other date implementations. + void year(unsigned short y) { year_ = y; } + +private: + unsigned short year_; ///< the year, as a simple integer, 1000-9999 + unsigned char month_; ///< the month, 1-12 + unsigned char day_; ///< the day, 1-31 +}; + +/// \brief Inserts a Date object into a C++ stream +/// +/// The format is YYYY-MM-DD, zero-padded. +/// +/// \param os stream to insert date into +/// \param d date to insert into stream +MYSQLPP_EXPORT std::ostream& operator <<(std::ostream& os, + const Date& d); + + +/// \brief C++ form of SQL's TIME type. +/// +/// Objects of this class can be inserted into streams, and +/// initialized from SQL TIME strings. +class MYSQLPP_EXPORT Time : public Comparable