diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e1c8543 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +*.o +*.a +*.pb.* +*_dispatcher.* +!base_dispatcher.* +*_stub.* +*_service.* +*_tool.* +*_main +third_party/* +sbin/* +sample/* + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2816042 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +# Ubuntu 14.04 Trusty support +sudo: required +dist: trusty + +language: cpp +compiler: g++ +git: + submodules: false +script: + - ./build.sh +notifications: + email: true diff --git a/AUTHORS b/AUTHORS index a337409..000cc63 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,7 +4,7 @@ Tencent Inc. Sifan Liu -Haochuan Cui +Haochuan Cui Duokai Huang diff --git a/Makefile b/Makefile index 39d3d04..3a8118f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ - version = 0.8.0 all: @@ -19,8 +18,9 @@ phxrpc-$(version).src.tar.gz: clean: @( rm -rf lib/*; ) - @( cd plugin_boost; make clean ) @( cd phxrpc; make clean ) @( cd codegen; make clean ) @( cd sample; test -f Makefile && make clean ) + @( cd plugin_boost; make clean ) + @( cd plugin_darwin; make clean ) diff --git a/README.md b/README.md index 70c8518..897764b 100644 --- a/README.md +++ b/README.md @@ -2,32 +2,45 @@ **PhxRPC是微信后台团队推出的一个非常简洁小巧的RPC框架,编译生成的库只有450K。** -作者: Sifan Liu (stephenliu@tencent.com), Haochuan Cui (lynncui@tencent.com) 和 Duokai Huang (mariohuang@tencent.com) - -# 总览 - - 使用Protobuf作为IDL用于描述RPC接口以及通信数据结构。 - - 基于Protobuf文件自动生成Client以及Server接口,用于Client的构建,以及Server的实现。 - - 半同步半异步模式,采用独立多IO线程,通过Epoll管理请求的接入以及读写,工作线程采用固定线程池。IO线程与工作线程通过内存队列进行交互。 - - 提供完善的过载保护,无需配置阀值,支持动态自适应拒绝请求。 - - 提供简易的Client/Server配置读入方式。 - - 基于lambda函数实现并发访问Server,可以非常方便地实现Google提出的 [Backup Requests](http://static.googleusercontent.com/media/research.google.com/zh-CN//people/jeff/Berkeley-Latency-Mar2012.pdf) 模式。 - -# 局限 - - 不支持多进程模式。 - -# 性能 +作者: Sifan Liu, Haochuan Cui 和 Duokai Huang + +联系我们:phxteam@tencent.com + +想了解更多, 以及更详细的编译手册,请进入[中文WIKI](https://github.com/Tencent/phxrpc/wiki),和扫描右侧二维码关注我们的公众号 + +PhxRPC[![Build Status](https://travis-ci.org/Tencent/phxrpc.png)](https://travis-ci.org/Tencent/phxrpc) + +## 总览 + +- 使用Protobuf作为IDL用于描述RPC接口以及通信数据结构。 +- 基于Protobuf文件自动生成Client以及Server接口,用于Client的构建,以及Server的实现。 +- 半同步半异步模式,采用独立多IO线程,通过Epoll管理请求的接入以及读写,工作线程采用固定线程池。IO线程与工作线程通过内存队列进行交互。 +- 支持协程Worker,可配置多个线程,每个线程多个协程。 +- 提供完善的过载保护,无需配置阈值,支持动态自适应拒绝请求。 +- New: 支持HTTP和MQTT协议。 +- 提供简易的Client/Server配置读入方式。 +- 基于lambda函数实现并发访问Server,可以非常方便地实现Google提出的 [Backup Requests](http://static.googleusercontent.com/media/research.google.com/zh-CN//people/jeff/Berkeley-Latency-Mar2012.pdf) 模式。 + +## 局限 + +- 不支持多进程模式。 + +## 性能 + >使用Sample目录下的Search RPC C/S进行Echo RPC调用的压测,相当于Worker空转情况。 ### 运行环境 - CPU:24 x Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz - 内存:32 GB - 网卡:千兆网卡 - Client/Server机器之间PING值: 0.05ms - 请求写入并发:1000个线程 - 业务数据大小:除去HTTP协议部分20b - Worker线程数:20 + +CPU:24 x Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz +内存:32 GB +网卡:千兆网卡 +Client/Server机器之间PING值: 0.05ms +请求写入并发:1000个线程 +业务数据大小:除去HTTP协议部分20b +Worker线程数:20 ### 性能测试结果(qps) + #### 短连接 | ucontext类型/IO线程 | 1 | 3 | 8 | 20 | @@ -42,29 +55,39 @@ | system | 55k | 160k | 360k | 500k | | boost | 62k | 175k | 410k | 500k | -# 如何编译 -#### Protobuf准备 -PhxRPC必须依赖的第三方库只有Protobuf。在编译前,在third_party目录放置好protobuf目录,或者通过软链的形式。 +## 如何编译 + +### Protobuf准备 + +PhxRPC必须依赖的第三方库只有Protobuf。在编译前,在`third_party`目录放置好`protobuf`目录,或者通过软链的形式。 + +### boost优化 -#### boost优化 PhxRPC在ServerIO以及Client并发连接管理上使用了ucontext,而boost的ucontext实现要比system默认的更为高效,推荐使用boost。如果需要使用boost的话需要在third_party目录放置好boost目录,或者通过软链的形式。 -#### 编译环境 - - Linux. - - GCC-4.8及以上版本。 - - boost 1.56及以上版本.(可选) +### 编译环境 + +- Linux +- GCC-4.8及以上版本 +- boost 1.56及以上版本(可选) + +### 编译安装方法 -#### 编译安装方法 进入PhxRPC根目录。 - make (默认是-O2编译,如需编译debug版,执行 make debug=y) - make boost (可选,编译PhxRPC的boost优化插件,编译之前先准备放置好boost库) - -# 如何使用 -#### 编写proto文件 +```sh +make (默认是-O2编译,如需编译debug版,执行 make debug=y) +make boost (可选,编译PhxRPC的boost优化插件,编译之前先准备好boost库) +``` + +## 如何使用 + +### 编写proto文件 + 下面是sample目录下的proto文件样例。 ```c++ +syntax = "proto3"; package search; import "google/protobuf/wrappers.proto"; import "google/protobuf/empty.proto"; @@ -76,124 +99,176 @@ enum SiteType { VIDEO = 2; UNKNOWN = 3; } + message Site { - required string url = 1; - required string title = 2; - required SiteType type = 3; - optional string summary = 4; + string url = 1; + string title = 2; + SiteType type = 3; + tring summary = 4; } + message SearchRequest { - required string query = 1; + string query = 1; } + message SearchResult { repeated Site sites = 1; } -service Search{ - rpc Search( SearchRequest ) returns( SearchResult ) { - option( phxrpc.CmdID ) = 1; - option( phxrpc.OptString ) = "q:"; - option( phxrpc.Usage ) = "-q "; - } - rpc Notify( google.protobuf.StringValue ) returns( google.protobuf.Empty ) { - option( phxrpc.CmdID ) = 2; - option( phxrpc.OptString ) = "m:"; - option( phxrpc.Usage ) = "-m "; - } + +service Search { + rpc Search(SearchRequest) returns (SearchResult) { + option(phxrpc.CmdID) = 1; + option(phxrpc.OptString) = "q:"; + option(phxrpc.Usage) = "-q "; + } + rpc Notify(google.protobuf.StringValue) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2; + option(phxrpc.OptString) = "m:"; + option(phxrpc.Usage) = "-m "; + } } ``` -#### 生成代码 + +### 生成代码 ```bash -(PhxRPC根目录)/codegen/phxrpc_pb2server --I (PhxRPC根目录) -I (Protobuf include目录) -f (proto文件路径) -d (生成代码放置路径) +(PhxRPC根目录)/codegen/phxrpc_pb2server -I (PhxRPC根目录) -I (Protobuf include目录) -f (proto文件路径) -d (生成代码放置路径) -#sample +# sample ../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d . - -调用完工具后,在生成代码放置目录下执行make,即可生成全部的RPC相关代码。 +../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d . -u ``` -#### 选择是否启用boost优化 -打开生成代码放置目录下的Makefile文件。 +两种生成模式,区别在于`-u`参数。 + +第一种生成默认的线程池worker模型。 + +第二种`-u`参数指定生成uthread worker模型,也就是工作线程池里面每个线程里面运行着多个协程。 + +调用完工具后,在生成代码放置目录下执行`make`,即可生成全部的RPC相关代码。 + +### 选择是否启用MQTT协议支持 + +打开生成代码放置目录下的`Makefile`文件。 + +默认开启了`-p mqtt`生成支持MQTT协议的代码。如不想支持,可以将此参数去掉。重新`make clean && make`。 + +### 选择是否启用Boost优化 + +打开生成代码放置目录下的`Makefile`文件。 + ```bash -#choose to use boost for network +# choose to use boost for network #LDFLAGS := $(PLUGIN_BOOST_LDFLAGS) $(LDFLAGS) ``` -可以看到以上两行,取消注释掉第二行,重新make clean, make即可开启boost对PhxRPC的优化。开启前记得编译好PhxRPC的boost插件。 -#### 补充自己的代码 -##### Server(xxx_service_impl.cpp) +可以看到以上两行,取消注释掉第二行,重新`make clean && make`即可开启Boost对PhxRPC的优化。开启前记得编译好PhxRPC的Boost插件。 + +### 补充自己的代码 + +#### Server(xxx_service_impl.cpp) ```c++ -int SearchServiceImpl :: PHXEcho( const google::protobuf::StringValue & req, - google::protobuf::StringValue * resp ) -{ - resp->set_value( req.value() ); +int SearchServiceImpl::PhxEcho(const google::protobuf::StringValue &req, + google::protobuf::StringValue *resp) { + resp->set_value(req.value()); return 0; } -int SearchServiceImpl :: Search( const search::SearchRequest & req, - search::SearchResult * resp ) -{ - //这里补充这个RPC调用的Server端代码 - return -1; +int SearchServiceImpl::Search(const search::SearchRequest &req, + search::SearchResult *resp) { + // 这里补充这个RPC调用的Server端代码 + return -1; } -int SearchServiceImpl :: Notify( const google::protobuf::StringValue & req, - google::protobuf::Empty * resp ) -{ - //这里补充这个RPC调用的Server端代码 - return -1; +int SearchServiceImpl::Notify(const google::protobuf::StringValue &req, + google::protobuf::Empty *resp) { + // 这里补充这个RPC调用的Server端代码 + return -1; } ``` -##### Client (xxx_client.cpp) +如果要使用MQTT协议,可对应补充`PhxMqttXxx`实现。 + +#### Client (xxx_client.cpp) ```c++ -//这个是默认生成的代码, 可自行修改,或利用我们提供的stub API自定义封装Client -int SearchClient :: PHXEcho( const google::protobuf::StringValue & req, - google::protobuf::StringValue * resp ) -{ - const phxrpc::Endpoint_t * ep = global_searchclient_config_.GetRandom(); +// 这个是默认生成的代码,可自行修改,或利用我们提供的stub API自定义封装Client + +int SearchClient::PhxEcho(const google::protobuf::StringValue &req, + google::protobuf::StringValue *resp) { + const phxrpc::Endpoint_t *ep = global_searchclient_config_.GetRandom(); - if(ep != nullptr) { + if (ep != nullptr) { phxrpc::BlockTcpStream socket; bool open_ret = phxrpc::PhxrpcTcpUtils::Open(&socket, ep->ip, ep->port, - global_searchclient_config_.GetConnectTimeoutMS(), NULL, 0, + global_searchclient_config_.GetConnectTimeoutMS(), nullptr, 0, *(global_searchclient_monitor_.get())); - if ( open_ret ) { + if (open_ret) { socket.SetTimeout(global_searchclient_config_.GetSocketTimeoutMS()); SearchStub stub(socket, *(global_searchclient_monitor_.get())); - return stub.PHXEcho(req, resp); - } - } + return stub.PhxEcho(req, resp); + } + } - return -1; + return -1; } ``` -##### Client并发调用样例 +如果要使用MQTT协议,可对应补充`PhxMqttXxx`实现。 + +#### UThread Client (xxx_client_uthread.cpp) ```c++ -int SearchClient :: PhxBatchEcho( const google::protobuf::StringValue & req, - google::protobuf::StringValue * resp ) -{ - int ret = -1; +// 这个是默认生成的代码,可自行修改,或利用我们提供的stub API自定义封装Client +// UThread Client只能在采用PhxRPC uthread worker模型的server中调用。 +// UThread Client构造函数需要传入UThreadEpollScheduler*类型参数, +// 这个参数来源可以在xxx_service_impl.h的私有变量中获得。 + +int SearchClientUThread::PhxEcho(const google::protobuf::StringValue &req, + google::protobuf::StringValue *resp) { + const phxrpc::Endpoint_t *ep = global_searchclientuthread_config_.GetRandom(); + + if (uthread_scheduler_ != nullptr && ep != nullptr) { + phxrpc::UThreadTcpStream socket; + bool open_ret = phxrpc::PhxrpcTcpUtils::Open(uthread_scheduler_, &socket, ep->ip, ep->port, + global_searchclientuthread_config_.GetConnectTimeoutMS(), + *(global_searchclientuthread_monitor_.get())); + if (open_ret) { + socket.SetTimeout(global_searchclientuthread_config_.GetSocketTimeoutMS()); + + SearchStub stub(socket, *(global_searchclientuthread_monitor_.get())); + return stub.PhxEcho(req, resp); + } + } + + return -1; +} +``` + +如果要使用MQTT协议,可对应补充`PhxMqttXxx`实现。 + +#### Client并发调用样例 + +```c++ +int SearchClient::PhxBatchEcho(const google::protobuf::StringValue &req, + google::protobuf::StringValue *resp) { + int ret = -1; size_t echo_server_count = 2; uthread_begin; for (size_t i = 0; i < echo_server_count; i++) { uthread_t [=, &uthread_s, &ret](void *) { - const phxrpc::Endpoint_t * ep = global_searchclient_config_.GetByIndex(i); + const phxrpc::Endpoint_t *ep = global_searchclient_config_.GetByIndex(i); if (ep != nullptr) { phxrpc::UThreadTcpStream socket; if(phxrpc::PhxrpcTcpUtils::Open(&uthread_s, &socket, ep->ip, ep->port, - global_searchclient_config_.GetConnectTimeoutMS(), + global_searchclient_config_.GetConnectTimeoutMS(), *(global_searchclient_monitor_.get()))) { socket.SetTimeout(global_searchclient_config_.GetSocketTimeoutMS()); SearchStub stub(socket, *(global_searchclient_monitor_.get())); - int this_ret = stub.PHXEcho(req, resp); + int this_ret = stub.PhxEcho(req, resp); if (this_ret == 0) { ret = this_ret; uthread_s.Close(); @@ -207,26 +282,28 @@ int SearchClient :: PhxBatchEcho( const google::protobuf::StringValue & req, } ``` -`uthread_begin`, `uthread_end`, `uthread_s`, `uthread_t`这几个关键字是PhxRPC自定义的宏,分别表示协程的准备,结束,协程调度器以及协程的创建。 +`uthread_begin`, `uthread_end`, `uthread_s`, `uthread_t`这几个关键字是PhxRPC自定义的宏,分别表示协程的准备、结束,协程调度器以及协程的创建。 上面的代码实现了Google提出的 [Backup Requests](http://static.googleusercontent.com/media/research.google.com/zh-CN//people/jeff/Berkeley-Latency-Mar2012.pdf) 模式。实现的功能是分别对两个Server同时发起Echo调用,当有一个Server响应的时候,则整个函数结束。在这段代码里面,我们提供了一种异步IO的同步写法,并给予了一些方便使用的宏定义。首先使用`uthread_begin`进行准备,然后使用`uthread_t`以lambda的形式创建一个协程,而在任意一个协程里面都可使用我们PhxRPC生成的Client API进行RPC调用,并可使用`uthread_s`随时结束所有RPC调用。最后的`uthread_end`真正通过协程调度发起这些lambda内的RPC调用,并等待结束。 当然你可以借用这4个宏定义,以同步代码的写法,进行更自定义的并发访问。 -##### Server配置说明 (xxx_server.conf) +#### Server配置说明 (xxx_server.conf) -```c++ +```ini [Server] -BindIP = 127.0.0.1 //Server IP -Port = 16161 //Server Port -MaxThreads = 16 //Worker 线程数 -IOThreadCount = 3 //IO线程数,针对业务请自行调节 -PackageName = search //Server 名字,用于自行实现的监控统计上报 -MaxConnections = 800000 //最大并发连接数 -MaxQueueLength = 20480 //IO队列最大长度 -FastRejectThresholdMS = 20 //快速拒绝自适应调节阀值,建议保持默认20ms,不做修改 +BindIP = 127.0.0.1 // Server IP +Port = 16161 // Server Port +MaxThreads = 16 // Worker 线程数 +WorkerUThreadCount = 50     // 每个线程开启的协程数,采用-u生成的Server必须配置这一项 +WorkerUThreadStackSize = 65536 // UThread worker的栈大小 +IOThreadCount = 3               // IO线程数,针对业务请自行调节 +PackageName = search // Server 名字,用于自行实现的监控统计上报 +MaxConnections = 800000 // 最大并发连接数 +MaxQueueLength = 20480 // IO队列最大长度 +FastRejectThresholdMS = 20 // 快速拒绝自适应调节阀值,建议保持默认20ms,不做修改 [ServerTimeout] -SocketTimeoutMS = 5000 //Server读写超时,Worker处理超时 +SocketTimeoutMS = 5000 // Server读写超时,Worker处理超时 ``` diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..d4e8044 --- /dev/null +++ b/build.sh @@ -0,0 +1,28 @@ + +set -e # exit immediately on error +set -x # display all commands + +mkdir -p third_party + +cd third_party; + +if [ ! -f protobuf/bin/protoc ]; then + if [ ! -f protobuf-cpp-3.0.0.tar.gz ]; then + wget https://github.com/google/protobuf/releases/download/v3.0.0/protobuf-cpp-3.0.0.tar.gz + fi + + tar zxvf protobuf-cpp-3.0.0.tar.gz + cd protobuf-3.0.0 + + ./configure --prefix=`pwd`/../protobuf + make -j2 + make install + + cd ../ +fi + +cd .. + +make + +exit $? diff --git a/codegen/Makefile b/codegen/Makefile index 49d408a..de7fa37 100644 --- a/codegen/Makefile +++ b/codegen/Makefile @@ -21,7 +21,7 @@ phxrpc_pb2tool: $(COMM_OBJS) tool_code_render.o tool_template.o phxrpc_pb2tool.o phxrpc_pb2server: $(COMM_OBJS) server_code_render.o server_template.o phxrpc_pb2server.o $(LINKER) $^ $(LDFLAGS) -o $@ -test_proto_utils: test_proto_utils.o syntax_tree.o proto_utils.o +test_proto_utils: test_proto_utils.o syntax_tree.o proto_utils.o code_utils.o $(LINKER) $^ $(LDFLAGS) -o $@ diff --git a/codegen/client_code_render.cpp b/codegen/client_code_render.cpp index 921784c..42078d4 100644 --- a/codegen/client_code_render.cpp +++ b/codegen/client_code_render.cpp @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -30,19 +30,22 @@ See the AUTHORS file for names of contributors. #include #include -using namespace std; using namespace phxrpc; +using namespace std; + -ClientCodeRender::ClientCodeRender(NameRender & name_render) +ClientCodeRender::ClientCodeRender(NameRender &name_render) : name_render_(name_render) { } ClientCodeRender::~ClientCodeRender() { } -void ClientCodeRender::GenerateStubHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ClientCodeRender::GenerateStubHpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetStubFileName(stree->GetName(), filename, sizeof(filename)); string buffer; @@ -60,41 +63,57 @@ void ClientCodeRender::GenerateStubHpp(SyntaxTree * stree, FILE * write) { name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "\n"); fprintf(write, "\n"); fprintf(write, "namespace phxrpc {\n"); - fprintf(write, " class BaseTcpStream;\n"); - fprintf(write, " class ClientMonitor;\n"); + fprintf(write, "\n"); + fprintf(write, "\n"); + fprintf(write, "class BaseTcpStream;\n"); + fprintf(write, "class ClientMonitor;\n"); + fprintf(write, "\n"); + fprintf(write, "\n"); fprintf(write, "}\n"); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetStubClasname(stree->GetName(), clasname, sizeof(clasname)); + char class_name[128]{'\0'}; + name_render_.GetStubClassName(stree->GetName(), class_name, sizeof(class_name)); { - fprintf(write, "class %s\n", clasname); - fprintf(write, "{\n"); - fprintf(write, "public:\n"); - fprintf(write, " %s( phxrpc::BaseTcpStream & socket, phxrpc::ClientMonitor & client_monitor );\n", clasname); - fprintf(write, " ~%s();\n", clasname); + fprintf(write, "class %s {\n", class_name); + fprintf(write, " public:\n"); + fprintf(write, " %s(phxrpc::BaseTcpStream &socket, phxrpc::ClientMonitor &client_monitor);\n", class_name); + fprintf(write, " virtual ~%s();\n", class_name); fprintf(write, "\n"); - fprintf(write, " void SetKeepAlive( const bool keep_alive );\n\n"); + fprintf(write, " void SetKeepAlive(const bool keep_alive);\n\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, " // %s protocol\n", kv.first.c_str()); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + string buffer; + GetStubFuncDeclaration(stree, &func, 1, &buffer); + fprintf(write, " %s;\n", buffer.c_str()); + } + fprintf(write, "\n"); + } - std::string buffer; + fprintf(write, " // user custom\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; GetStubFuncDeclaration(stree, &(*fit), 1, &buffer); fprintf(write, " %s;\n", buffer.c_str()); - fprintf(write, "\n"); } + fprintf(write, "\n"); - fprintf(write, "private:\n"); - fprintf(write, " phxrpc::BaseTcpStream & socket_;\n"); - fprintf(write, " phxrpc::ClientMonitor & client_monitor_;\n"); + fprintf(write, " private:\n"); + fprintf(write, " phxrpc::BaseTcpStream &socket_;\n"); + fprintf(write, " phxrpc::ClientMonitor &client_monitor_;\n"); fprintf(write, " bool keep_alive_;\n"); fprintf(write, "};\n"); @@ -103,32 +122,37 @@ void ClientCodeRender::GenerateStubHpp(SyntaxTree * stree, FILE * write) { } } -void ClientCodeRender::GetStubFuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, - std::string * result) { - char clasname[128] = { 0 }, type_name[128] = { 0 }; +void ClientCodeRender::GetStubFuncDeclaration(const SyntaxTree *const stree, const SyntaxFunc *const func, + int is_header, string *result) { + char class_name[128]{'\0'}, type_name[128]{'\0'}; - name_render_.GetStubClasname(stree->GetName(), clasname, sizeof(clasname)); + name_render_.GetStubClassName(stree->GetName(), class_name, sizeof(class_name)); if (is_header) { - phxrpc::StrAppendFormat(result, "int %s( ", func->GetName()); + phxrpc::StrAppendFormat(result, "int %s(", func->GetName()); } else { - phxrpc::StrAppendFormat(result, "int %s :: %s( ", clasname, func->GetName()); + phxrpc::StrAppendFormat(result, "int %s::%s(", class_name, func->GetName()); } - name_render_.GetMessageClasname(func->GetReq()->GetType(), type_name, sizeof(type_name)); - phxrpc::StrAppendFormat(result, "const %s & req,\n", type_name); + name_render_.GetMessageClassName(func->GetReq()->GetType(), type_name, sizeof(type_name)); + phxrpc::StrAppendFormat(result, "const %s &req", type_name); - name_render_.GetMessageClasname(func->GetResp()->GetType(), type_name, sizeof(type_name)); - phxrpc::StrAppendFormat(result, " %s * resp", type_name); + const char *const resp_type{func->GetResp()->GetType()}; + if (resp_type && 0 < strlen(resp_type)) { + name_render_.GetMessageClassName(resp_type, type_name, sizeof(type_name)); + phxrpc::StrAppendFormat(result, ", %s *resp", type_name); + } - phxrpc::StrAppendFormat(result, " )"); + phxrpc::StrAppendFormat(result, ")"); } -void ClientCodeRender::GenerateStubCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ClientCodeRender::GenerateStubCpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetStubFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2client", stree->GetProtoFile(), &buffer); fprintf(write, "/* %s.cpp\n", filename); @@ -136,71 +160,99 @@ void ClientCodeRender::GenerateStubCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "*/\n"); fprintf(write, "\n"); - fprintf(write, "#include \"phxrpc/rpc.h\"\n"); - fprintf(write, "#include \"phxrpc/network.h\"\n"); + fprintf(write, "#include \"%s.h\"\n", filename); fprintf(write, "\n"); - fprintf(write, "#include \"%s.h\"\n", filename); - - name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); - fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "#include \"phxrpc/rpc.h\"\n"); + fprintf(write, "#include \"phxrpc/network.h\"\n"); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetStubClasname(stree->GetName(), clasname, sizeof(clasname)); + char class_name[128]{'\0'}; + name_render_.GetStubClassName(stree->GetName(), class_name, sizeof(class_name)); { - fprintf(write, "%s :: %s( phxrpc::BaseTcpStream & socket, phxrpc::ClientMonitor & client_monitor )\n", - clasname, clasname); + fprintf(write, "%s::%s(phxrpc::BaseTcpStream &socket, phxrpc::ClientMonitor &client_monitor)\n", + class_name, class_name); - fprintf(write, " : socket_( socket ), client_monitor_(client_monitor), keep_alive_(false)\n"); - fprintf(write, "{\n"); + fprintf(write, " : socket_(socket), client_monitor_(client_monitor), keep_alive_(false) {\n"); fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "%s :: ~%s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::~%s() {\n", class_name, class_name); fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "void %s :: SetKeepAlive( const bool keep_alive )\n", clasname ); - fprintf(write, "{\n"); + fprintf(write, "void %s::SetKeepAlive(const bool keep_alive) {\n", class_name ); fprintf(write, " keep_alive_ = keep_alive;\n"); fprintf(write, "}\n"); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - GenerateStubFunc(stree, &(*fit), write); + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, "// %s protocol\n", kv.first.c_str()); + fprintf(write, "\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + if ("http" == kv.first) { + GenerateStubFunc(stree, &(kv.second), &func, write, true); + } else { + GenerateStubFunc(stree, &(kv.second), &func, write, false); + } + } + } + + fprintf(write, "// user custom\n"); + fprintf(write, "\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + GenerateStubFunc(stree, stree, &(*fit), write, true); } + } } -void ClientCodeRender::GenerateStubFunc(SyntaxTree * stree, SyntaxFunc * func, FILE * write) { - std::string buffer; +void ClientCodeRender::GenerateStubFunc(const SyntaxTree *const stree, + const SyntaxTree *const stree2, + const SyntaxFunc *const func, + FILE *write, const bool use_default_caller) { + string buffer; GetStubFuncDeclaration(stree, func, 0, &buffer); - fprintf(write, "%s\n", buffer.c_str()); + char caller_name[128]{"HttpCaller"}; + if (!use_default_caller) { + // protocol + name_render_.GetCallerClassName(stree2->GetName(), caller_name, sizeof(caller_name)); + } + + fprintf(write, "%s {\n", buffer.c_str()); - fprintf(write, "{\n"); - fprintf(write, " phxrpc::HttpCaller caller( socket_, client_monitor_ );\n"); - fprintf(write, " caller.SetURI( \"/%s/%s\", %d );\n", stree->GetPackageName(), func->GetName(), - func->GetCmdID()); - fprintf(write, " caller.SetKeepAlive( keep_alive_ );\n"); - fprintf(write, " return caller.Call( req, resp );\n"); + fprintf(write, " phxrpc::%s caller(socket_, client_monitor_);\n", caller_name); + fprintf(write, " caller.SetURI(\"/%s/%s\", %d);\n", + SyntaxTree::Cpp2UriPackageName(stree2->GetCppPackageName()).c_str(), + func->GetName(), func->GetCmdID()); + fprintf(write, " caller.SetKeepAlive(keep_alive_);\n"); + if (!use_default_caller) { + // protocol + fprintf(write, " return caller.%sCall(req, resp);\n", func->GetName()); + } else { + // user custom + fprintf(write, " return caller.Call(req, resp);\n"); + } fprintf(write, "}\n"); fprintf(write, "\n"); } -void ClientCodeRender::GenerateClientHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ClientCodeRender::GenerateClientHpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write, const bool is_uthread_mode) { + char filename[128]{0}; name_render_.GetClientFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2client", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.h\n", filename); @@ -212,56 +264,92 @@ void ClientCodeRender::GenerateClientHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); - std::string declarations; - { - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; - GetClienfuncDeclaration(stree, &(*fit), 1, &buffer); + string declarations; - declarations.append(" ").append(buffer).append(";\n\n"); + { + for (const auto &kv : protocol2syntax_tree_map) { + declarations.append(" // ").append(kv.first).append(" protocol\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + string buffer; + GetClienfuncDeclaration(stree, &func, 1, &buffer, is_uthread_mode); + declarations.append(" ").append(buffer).append(";\n"); + } + declarations.append("\n"); + } + } - if (strcmp(fit->GetName(), "PHXEcho") == 0) { + { + declarations.append(" // user custom\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; + GetClienfuncDeclaration(stree, &(*fit), 1, &buffer, is_uthread_mode); + declarations.append(" ").append(buffer).append(";\n"); + + if (0 == strcmp(fit->GetName(), "PhxEcho")) { SyntaxFunc echo_func = *fit; echo_func.SetName("PhxBatchEcho"); - std::string buffer; - GetClienfuncDeclaration(stree, &echo_func, 1, &buffer); - declarations.append(" ").append(buffer).append(";\n\n"); + string buffer; + GetClienfuncDeclaration(stree, &echo_func, 1, &buffer, is_uthread_mode); + declarations.append(" ").append(buffer).append(";\n"); } - } } - char client_class[128] = { 0 }, message_file[128] = { 0 }; - char client_class_lower[128] = { 0 }; - name_render_.GetClientClasname(stree->GetName(), client_class, sizeof(client_class)); - name_render_.GetClientClasnameLower(stree->GetName(), client_class_lower, sizeof(client_class_lower)); + char client_class[128]{0}, message_file[128]{0}; + char client_class_lower[128]{0}; + name_render_.GetClientClassName(stree->GetName(), client_class, sizeof(client_class)); + name_render_.GetClientClassNameLower(stree->GetName(), client_class_lower, sizeof(client_class_lower)); name_render_.GetMessageFileName(stree->GetProtoFile(), message_file, sizeof(message_file)); - std::string content(PHXRPC_CLIENT_HPP_TEMPLATE); + string client_class_str(client_class); + string client_class_lower_str(client_class_lower); + if (is_uthread_mode) { + client_class_str += "UThread"; + client_class_lower_str += "uthread"; + } + + string content; + if (!is_uthread_mode) { + content = PHXRPC_CLIENT_HPP_TEMPLATE; + } else { + content = PHXRPC_UTHREAD_CLIENT_HPP_TEMPLATE; + } + StrTrim(&content); StrReplaceAll(&content, "$MessageFile$", message_file); - StrReplaceAll(&content, "$ClientClass$", client_class); - StrReplaceAll(&content, "$ClientClassLower$", client_class_lower); + StrReplaceAll(&content, "$ClientClass$", client_class_str.c_str()); + StrReplaceAll(&content, "$ClientClassLower$", client_class_lower_str.c_str()); StrReplaceAll(&content, "$ClientClassFuncDeclarations$", declarations); fprintf(write, "%s", content.c_str()); fprintf(write, "\n"); + fprintf(write, "\n"); } -void ClientCodeRender::GenerateClientCpp(SyntaxTree * stree, FILE * write) { - char client_class[128] = { 0 }, client_file[128] = { 0 }; - char client_class_lower[128] = { 0 }; - char stub_class[128] = { 0 }, stub_file[128] = { 0 }; - name_render_.GetClientClasname(stree->GetName(), client_class, sizeof(client_class)); - name_render_.GetClientClasnameLower(stree->GetName(), client_class_lower, sizeof(client_class_lower)); +void ClientCodeRender::GenerateClientCpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write, const bool is_uthread_mode) { + char client_class[128]{0}, client_file[128]{0}; + char client_class_lower[128]{0}; + char stub_class[128]{0}, stub_file[128]{0}; + name_render_.GetClientClassName(stree->GetName(), client_class, sizeof(client_class)); + name_render_.GetClientClassNameLower(stree->GetName(), client_class_lower, sizeof(client_class_lower)); name_render_.GetClientFileName(stree->GetName(), client_file, sizeof(client_file)); - name_render_.GetStubClasname(stree->GetName(), stub_class, sizeof(stub_class)); + name_render_.GetStubClassName(stree->GetName(), stub_class, sizeof(stub_class)); name_render_.GetStubFileName(stree->GetName(), stub_file, sizeof(stub_file)); - std::string buffer; + string client_class_str = string(client_class); + string client_class_lower_str = string(client_class_lower); + if (is_uthread_mode) { + client_class_str += "UThread"; + client_class_lower_str += "uthread"; + } + + string buffer; name_render_.GetCopyright("phxrpc_pb2client", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.cpp\n", client_file); @@ -270,88 +358,143 @@ void ClientCodeRender::GenerateClientCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); - std::string functions; + string functions; + { - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; - GetClienfuncDeclaration(stree, &(*fit), 0, &buffer); + for (const auto &kv : protocol2syntax_tree_map) { + functions.append("// ").append(kv.first).append(" protocol\n\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + string buffer; + GetClienfuncDeclaration(stree, &(func), 0, &buffer, is_uthread_mode); + + functions.append(buffer).append(" "); + + string content; + if (!is_uthread_mode) { + content = PHXRPC_CLIENT_FUNC_TEMPLATE; + } else { + content = PHXRPC_UTHREAD_CLIENT_FUNC_TEMPLATE; + } - functions.append(buffer).append("\n"); + StrTrim(&content); + StrReplaceAll(&content, "$ClientClass$", client_class_str.c_str()); + StrReplaceAll(&content, "$ClientClassLower$", client_class_lower_str.c_str()); + StrReplaceAll(&content, "$StubClass$", stub_class); + string func_string(func.GetName()); + func_string += "(req, resp)"; + StrReplaceAll(&content, "$Func$", func_string); - std::string content = PHXRPC_CLIENT_FUNC_TEMPLATE; + functions.append(content).append("\n\n"); + } + fprintf(write, "\n"); + } + } + + { + functions.append("// user custom\n\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; + GetClienfuncDeclaration(stree, &(*fit), 0, &buffer, is_uthread_mode); + + functions.append(buffer).append(" "); + + string content; + if (!is_uthread_mode) { + content = PHXRPC_CLIENT_FUNC_TEMPLATE; + } else { + content = PHXRPC_UTHREAD_CLIENT_FUNC_TEMPLATE; + } StrTrim(&content); - StrReplaceAll(&content, "$ClientClass$", client_class); - StrReplaceAll(&content, "$ClientClassLower$", client_class_lower); + StrReplaceAll(&content, "$ClientClass$", client_class_str.c_str()); + StrReplaceAll(&content, "$ClientClassLower$", client_class_lower_str.c_str()); StrReplaceAll(&content, "$StubClass$", stub_class); - StrReplaceAll(&content, "$Func$", fit->GetName()); + string func_string(fit->GetName()); + func_string += "(req, resp)"; + StrReplaceAll(&content, "$Func$", func_string); functions.append(content).append("\n\n"); - if (strcmp(fit->GetName(), "PHXEcho") == 0) { + if (strcmp(fit->GetName(), "PhxEcho") == 0) { SyntaxFunc echo_func = *fit; echo_func.SetName("PhxBatchEcho"); - std::string buffer; - GetClienfuncDeclaration(stree, &echo_func, 0, &buffer); + string buffer; + GetClienfuncDeclaration(stree, &echo_func, 0, &buffer, is_uthread_mode); - functions.append(buffer).append("\n"); + functions.append(buffer).append(" "); - std::string content = PHXRPC_BATCH_CLIENT_FUNC_TEMPLATE; + string content = PHXRPC_BATCH_CLIENT_FUNC_TEMPLATE; StrTrim(&content); - StrReplaceAll(&content, "$ClientClass$", client_class); - StrReplaceAll(&content, "$ClientClassLower$", client_class_lower); + StrReplaceAll(&content, "$ClientClass$", client_class_str.c_str()); + StrReplaceAll(&content, "$ClientClassLower$", client_class_lower_str.c_str()); StrReplaceAll(&content, "$StubClass$", stub_class); - StrReplaceAll(&content, "$Func$", echo_func.GetName()); + string echo_func_string(echo_func.GetName()); + echo_func_string += "(req, resp)"; + StrReplaceAll(&content, "$Func$", echo_func_string); functions.append(content).append("\n\n"); } } } - std::string content(PHXRPC_CLIENT_CPP_TEMPLATE); + string content; + if (!is_uthread_mode) { + content = PHXRPC_CLIENT_CPP_TEMPLATE; + } else { + content = PHXRPC_UTHREAD_CLIENT_CPP_TEMPLATE; + } + StrTrim(&content); - StrReplaceAll(&content, "$PackageName$", stree->GetPackageName() ); + StrReplaceAll(&content, "$PbPackageName$", SyntaxTree::Cpp2PbPackageName(stree->GetCppPackageName())); StrReplaceAll(&content, "$ClientFile$", client_file); StrReplaceAll(&content, "$StubFile$", stub_file); - StrReplaceAll(&content, "$ClientClass$", client_class); - StrReplaceAll(&content, "$ClientClassLower$", client_class_lower); + StrReplaceAll(&content, "$ClientClass$", client_class_str); + StrReplaceAll(&content, "$ClientClassLower$", client_class_lower_str.c_str()); StrReplaceAll(&content, "$ClientClassFuncs$", functions); fprintf(write, "%s", content.c_str()); - - fprintf(write, "\n"); } -void ClientCodeRender::GetClienfuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, - std::string * result) { - char clasname[128] = { 0 }, type_name[128] = { 0 }; +void ClientCodeRender::GetClienfuncDeclaration(SyntaxTree *stree, + const SyntaxFunc *const func, + int is_header, string *result, + const bool is_uthread_mode) { + char class_name[128]{'\0'}, type_name[128]{'\0'}; - name_render_.GetClientClasname(stree->GetName(), clasname, sizeof(clasname)); + name_render_.GetClientClassName(stree->GetName(), class_name, sizeof(class_name)); + string class_name_str(class_name); + if (is_uthread_mode) { + class_name_str += "UThread"; + } if (is_header) { - phxrpc::StrAppendFormat(result, "int %s( ", func->GetName()); + phxrpc::StrAppendFormat(result, "int %s(", func->GetName()); } else { - phxrpc::StrAppendFormat(result, "int %s :: %s( ", clasname, func->GetName()); + phxrpc::StrAppendFormat(result, "int %s::%s(", class_name_str.c_str(), func->GetName()); } - name_render_.GetMessageClasname(func->GetReq()->GetType(), type_name, sizeof(type_name)); - phxrpc::StrAppendFormat(result, "const %s & req,\n", type_name); + name_render_.GetMessageClassName(func->GetReq()->GetType(), type_name, sizeof(type_name)); + phxrpc::StrAppendFormat(result, "const %s &req", type_name); - name_render_.GetMessageClasname(func->GetResp()->GetType(), type_name, sizeof(type_name)); - phxrpc::StrAppendFormat(result, " %s * resp", type_name); + const char *const resp_type{func->GetResp()->GetType()}; + if (resp_type && 0 < strlen(resp_type)) { + name_render_.GetMessageClassName(resp_type, type_name, sizeof(type_name)); + phxrpc::StrAppendFormat(result, ", %s *resp", type_name); + } - phxrpc::StrAppendFormat(result, " )"); + phxrpc::StrAppendFormat(result, ")"); } -void ClientCodeRender::GenerateClientEtc(SyntaxTree * stree, FILE * write) { - char etcfile[128] = { 0 }; +void ClientCodeRender::GenerateClientEtc(SyntaxTree *stree, FILE *write) { + char etcfile[128]{0}; name_render_.GetClientEtcFileName(stree->GetName(), etcfile, sizeof(etcfile)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2server", stree->GetProtoFile(), &buffer, false, "#"); fprintf(write, "# %s\n", etcfile); @@ -359,11 +502,12 @@ void ClientCodeRender::GenerateClientEtc(SyntaxTree * stree, FILE * write) { fprintf(write, "#\n"); fprintf(write, "\n"); - std::string content(PHXRPC_CLIENT_ETC_TEMPLATE); + string content(PHXRPC_CLIENT_ETC_TEMPLATE); StrTrim(&content); - StrReplaceAll(&content, "$PackageName$", stree->GetPackageName() ); + StrReplaceAll(&content, "$PbPackageName$", SyntaxTree::Cpp2PbPackageName(stree->GetCppPackageName())); fprintf(write, "%s", content.c_str()); fprintf(write, "\n"); + fprintf(write, "\n"); } diff --git a/codegen/client_code_render.h b/codegen/client_code_render.h index 0203bdc..0e28e02 100755 --- a/codegen/client_code_render.h +++ b/codegen/client_code_render.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,41 +21,58 @@ See the AUTHORS file for names of contributors. #pragma once -#include +#include +#include #include +#include + namespace phxrpc { + class NameRender; class SyntaxTree; class SyntaxFunc; +typedef std::vector SyntaxFuncVector; class ClientCodeRender { - public: - ClientCodeRender(NameRender & name_render); - ~ClientCodeRender(); + public: + ClientCodeRender(NameRender &name_render); + virtual ~ClientCodeRender(); - void GenerateStubHpp(SyntaxTree * stree, FILE * write); + void GenerateStubHpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - void GenerateStubCpp(SyntaxTree * stree, FILE * write); + void GenerateStubCpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - void GenerateClientHpp(SyntaxTree * stree, FILE * write); + void GenerateClientHpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write, const bool is_uthread_mode); - void GenerateClientCpp(SyntaxTree * stree, FILE * write); + void GenerateClientCpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write, const bool is_uthread_mode); - void GenerateClientEtc(SyntaxTree * stree, FILE * write); + void GenerateClientEtc(SyntaxTree *stree, FILE *write); - private: + private: + void GetStubFuncDeclaration(const SyntaxTree *const stree, const SyntaxFunc *const func, + int is_header, std::string *result); - void GetStubFuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, std::string * result); + void GenerateStubFunc(const SyntaxTree *const stree, const SyntaxTree *const stree2, + const SyntaxFunc *const func, FILE *write, const bool use_default_caller); - void GenerateStubFunc(SyntaxTree * stree, SyntaxFunc * func, FILE * write); + void GetClienfuncDeclaration(SyntaxTree *stree, + const SyntaxFunc *const func, + int is_header, std::string *result, + const bool is_uthread_mode); - void GetClienfuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, std::string * result); - - private: - NameRender & name_render_; + NameRender &name_render_; }; + } diff --git a/codegen/client_template.cpp b/codegen/client_template.cpp index c7f575a..6dfef39 100644 --- a/codegen/client_template.cpp +++ b/codegen/client_template.cpp @@ -1,93 +1,120 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -const char * PHXRPC_CLIENT_HPP_TEMPLATE = +const char *PHXRPC_CLIENT_HPP_TEMPLATE = R"( #include "$MessageFile$.h" #include "phxrpc/rpc.h" -class $ClientClass$ -{ -public: - static bool Init( const char * config_file ); - static const char * GetPackageName(); +class $ClientClass$ { + public: + static bool Init(const char *config_file); + + static const char *GetPackageName(); -public: $ClientClass$(); - ~$ClientClass$(); + virtual ~$ClientClass$(); + +$ClientClassFuncDeclarations$}; + +)"; + +////////////////////////////////////////////////////////////////////// + +const char *PHXRPC_UTHREAD_CLIENT_HPP_TEMPLATE = + R"( + +#include "$MessageFile$.h" +#include "phxrpc/rpc.h" +#include "phxrpc/network.h" + + +class $ClientClass$ { + public: + static bool Init(const char *config_file); + + static const char *GetPackageName(); + + $ClientClass$(phxrpc::UThreadEpollScheduler *uthread_scheduler); + virtual ~$ClientClass$(); $ClientClassFuncDeclarations$ + private: + phxrpc::UThreadEpollScheduler *uthread_scheduler_; }; )"; ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_CLIENT_CPP_TEMPLATE = +const char *PHXRPC_CLIENT_CPP_TEMPLATE = R"( -#include +#include "$ClientFile$.h" + +#include #include -#include #include +#include -#include "$ClientFile$.h" #include "$StubFile$.h" #include "phxrpc/rpc.h" + +using namespace std; + + static phxrpc::ClientConfig global_$ClientClassLower$_config_; static phxrpc::ClientMonitorPtr global_$ClientClassLower$_monitor_; -bool $ClientClass$ :: Init( const char * config_file ) -{ - return global_$ClientClassLower$_config_.Read( config_file ); + +bool $ClientClass$::Init(const char *config_file) { + return global_$ClientClassLower$_config_.Read(config_file); } -const char * $ClientClass$ :: GetPackageName() { - const char * ret = global_$ClientClassLower$_config_.GetPackageName(); +const char *$ClientClass$::GetPackageName() { + const char *ret = global_$ClientClassLower$_config_.GetPackageName(); if (strlen(ret) == 0) { - ret = "$PackageName$"; + ret = "$PbPackageName$"; } return ret; } -$ClientClass$ :: $ClientClass$() -{ - static std::mutex monitor_mutex; - if ( !global_$ClientClassLower$_monitor_.get() ) { +$ClientClass$::$ClientClass$() { + static mutex monitor_mutex; + if (!global_$ClientClassLower$_monitor_.get()) { monitor_mutex.lock(); - if ( !global_$ClientClassLower$_monitor_.get() ) { - global_$ClientClassLower$_monitor_ = phxrpc::MonitorFactory::GetFactory() - ->CreateClientMonitor( GetPackageName() ); + if (!global_$ClientClassLower$_monitor_.get()) { + global_$ClientClassLower$_monitor_ = phxrpc::MonitorFactory::GetFactory()-> + CreateClientMonitor(GetPackageName()); } - global_$ClientClassLower$_config_.SetClientMonitor( global_$ClientClassLower$_monitor_ ); + global_$ClientClassLower$_config_.SetClientMonitor(global_$ClientClassLower$_monitor_); monitor_mutex.unlock(); } } -$ClientClass$ :: ~$ClientClass$() -{ +$ClientClass$::~$ClientClass$() { } $ClientClassFuncs$ @@ -95,22 +122,178 @@ const char * $ClientClass$ :: GetPackageName() { ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_CLIENT_FUNC_TEMPLATE = +const char *PHXRPC_UTHREAD_CLIENT_CPP_TEMPLATE = + R"( + +#include "$ClientFile$_uthread.h" + +#include +#include +#include +#include + +#include "$StubFile$.h" + +#include "phxrpc/rpc.h" + + +using namespace std; + + +static phxrpc::ClientConfig global_$ClientClassLower$_config_; +static phxrpc::ClientMonitorPtr global_$ClientClassLower$_monitor_; + + +bool $ClientClass$::Init(const char *config_file) { + return global_$ClientClassLower$_config_.Read(config_file); +} + +const char *$ClientClass$::GetPackageName() { + const char *ret{global_$ClientClassLower$_config_.GetPackageName()}; + if (strlen(ret) == 0) { + ret = "$PbPackageName$"; + } + return ret; +} + +$ClientClass$::$ClientClass$(phxrpc::UThreadEpollScheduler *uthread_scheduler) { + uthread_scheduler_ = uthread_scheduler; + static mutex monitor_mutex; + if (!global_$ClientClassLower$_monitor_.get()) { + monitor_mutex.lock(); + if (!global_$ClientClassLower$_monitor_.get()) { + global_$ClientClassLower$_monitor_ = phxrpc::MonitorFactory::GetFactory()-> + CreateClientMonitor(GetPackageName()); + } + global_$ClientClassLower$_config_.SetClientMonitor(global_$ClientClassLower$_monitor_); + monitor_mutex.unlock(); + } +} + +$ClientClass$::~$ClientClass$() { +} + +$ClientClassFuncs$ +)"; + +////////////////////////////////////////////////////////////////////// + +const char *PHXRPC_CLIENT_FUNC_TEMPLATE = R"( { - const phxrpc::Endpoint_t * ep = global_$ClientClassLower$_config_.GetRandom(); + const phxrpc::Endpoint_t *ep = global_$ClientClassLower$_config_.GetRandom(); + + if (ep) { + auto &&socket_pool = phxrpc::ResourcePoll::GetInstance(); + // TODO: + uint64_t key(ep->port); + auto socket = move(socket_pool->Get(key)); + + if (nullptr == socket.get()) { + socket.reset(new phxrpc::BlockTcpStream()); + + bool open_ret{phxrpc::PhxrpcTcpUtils::Open(socket.get(), ep->ip, ep->port, + global_$ClientClassLower$_config_.GetConnectTimeoutMS(), nullptr, 0, + *(global_$ClientClassLower$_monitor_.get()))}; + if (!open_ret) { + phxrpc::log(LOG_ERR, "Open %s:%d err %d", ep->ip, ep->port, open_ret); + + return -1; + } + socket->SetTimeout(global_$ClientClassLower$_config_.GetSocketTimeoutMS()); + } + + $StubClass$ stub(*(socket.get()), *(global_$ClientClassLower$_monitor_.get())); + int ret{stub.$Func$}; + socket_pool->Put(key, socket); + + return ret; + } + + return -1; +} +)"; + +////////////////////////////////////////////////////////////////////// + +const char *PHXRPC_UTHREAD_CLIENT_FUNC_TEMPLATE = + R"( +{ + const phxrpc::Endpoint_t *ep = global_$ClientClassLower$_config_.GetRandom(); + + if (uthread_scheduler_ && ep) { + auto &&socket_pool = phxrpc::ResourcePoll::GetInstance(); + // TODO: + uint64_t key(ep->port); + auto socket = move(socket_pool->Get(key)); + + if (nullptr == socket.get()) { + socket.reset(new phxrpc::UThreadTcpStream()); + + bool open_ret{phxrpc::PhxrpcTcpUtils::Open(uthread_scheduler_, socket.get(), ep->ip, ep->port, + global_$ClientClassLower$_config_.GetConnectTimeoutMS(), + *(global_$ClientClassLower$_monitor_.get()))}; + if (!open_ret) { + phxrpc::log(LOG_ERR, "Open %s:%d err %d", ep->ip, ep->port, open_ret); + + return -1; + } + socket->SetTimeout(global_$ClientClassLower$_config_.GetSocketTimeoutMS()); + } - if(ep != nullptr) { + $StubClass$ stub(*(socket.get()), *(global_$ClientClassLower$_monitor_.get())); + int ret{stub.$Func$}; + socket_pool->Put(key, socket); + + return ret; + } + + return -1; +} +)"; + +////////////////////////////////////////////////////////////////////// + +const char *PHXRPC_SHORT_CLIENT_FUNC_TEMPLATE = + R"( +{ + const phxrpc::Endpoint_t *ep = global_$ClientClassLower$_config_.GetRandom(); + + if (ep) { phxrpc::BlockTcpStream socket; - bool open_ret = phxrpc::PhxrpcTcpUtils::Open(&socket, ep->ip, ep->port, - global_$ClientClassLower$_config_.GetConnectTimeoutMS(), NULL, 0, - *(global_$ClientClassLower$_monitor_.get())); - if ( open_ret ) { + bool open_ret{phxrpc::PhxrpcTcpUtils::Open(&socket, ep->ip, ep->port, + global_$ClientClassLower$_config_.GetConnectTimeoutMS(), nullptr, 0, + *(global_$ClientClassLower$_monitor_.get()))}; + if (open_ret) { + socket.SetTimeout(global_$ClientClassLower$_config_.GetSocketTimeoutMS()); + + $StubClass$ stub(socket, *(global_$ClientClassLower$_monitor_.get())); + return stub.$Func$; + } + } + + return -1; +} +)"; + +////////////////////////////////////////////////////////////////////// + +const char *PHXRPC_UTHREAD_SHORT_CLIENT_FUNC_TEMPLATE = + R"( +{ + const phxrpc::Endpoint_t *ep = global_$ClientClassLower$_config_.GetRandom(); + + if (uthread_scheduler_ && ep) { + phxrpc::UThreadTcpStream socket; + bool open_ret{phxrpc::PhxrpcTcpUtils::Open(uthread_scheduler_, &socket, ep->ip, ep->port, + global_$ClientClassLower$_config_.GetConnectTimeoutMS(), + *(global_$ClientClassLower$_monitor_.get()))}; + if (open_ret) { socket.SetTimeout(global_$ClientClassLower$_config_.GetSocketTimeoutMS()); $StubClass$ stub(socket, *(global_$ClientClassLower$_monitor_.get())); - return stub.$Func$(req, resp); - } + return stub.$Func$; + } } return -1; @@ -119,30 +302,30 @@ const char * PHXRPC_CLIENT_FUNC_TEMPLATE = ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_BATCH_CLIENT_FUNC_TEMPLATE = +const char *PHXRPC_BATCH_CLIENT_FUNC_TEMPLATE = R"( { - int ret = -1; - size_t echo_server_count = 2; + int ret{-1}; + size_t echo_server_count{2}; uthread_begin; - for (size_t i = 0; i < echo_server_count; i++) { + for (size_t i{0}; echo_server_count > i; ++i) { uthread_t [=, &uthread_s, &ret](void *) { - const phxrpc::Endpoint_t * ep = global_$ClientClassLower$_config_.GetByIndex(i); + const phxrpc::Endpoint_t *ep = global_$ClientClassLower$_config_.GetByIndex(i); if (ep != nullptr) { phxrpc::UThreadTcpStream socket; if(phxrpc::PhxrpcTcpUtils::Open(&uthread_s, &socket, ep->ip, ep->port, - global_$ClientClassLower$_config_.GetConnectTimeoutMS(), *(global_$ClientClassLower$_monitor_.get()))) { + global_$ClientClassLower$_config_.GetConnectTimeoutMS(), *(global_$ClientClassLower$_monitor_.get()))) { socket.SetTimeout(global_$ClientClassLower$_config_.GetSocketTimeoutMS()); $StubClass$ stub(socket, *(global_$ClientClassLower$_monitor_.get())); - int this_ret = stub.PHXEcho(req, resp); + int this_ret{stub.PhxEcho(req, resp)}; if (this_ret == 0) { ret = this_ret; uthread_s.Close(); - } - } + } + } } - }; - } + }; + } uthread_end; return ret; } @@ -150,7 +333,7 @@ const char * PHXRPC_BATCH_CLIENT_FUNC_TEMPLATE = ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_CLIENT_ETC_TEMPLATE = +const char *PHXRPC_CLIENT_ETC_TEMPLATE = R"( [ClientTimeout] @@ -159,15 +342,15 @@ SocketTimeoutMS = 5000 [Server] ServerCount = 2 -PackageName=$PackageName$ +PackageName = $PbPackageName$ [Server0] IP = 127.0.0.1 -Port = 16161 +Port = 80 [Server1] IP = 127.0.0.1 -Port = 16161 +Port = 80 )"; diff --git a/codegen/client_template.h b/codegen/client_template.h index 5f7e36b..2c74264 100644 --- a/codegen/client_template.h +++ b/codegen/client_template.h @@ -22,7 +22,17 @@ See the AUTHORS file for names of contributors. #pragma once extern const char * PHXRPC_CLIENT_HPP_TEMPLATE; +extern const char * PHXRPC_UTHREAD_CLIENT_HPP_TEMPLATE; + extern const char * PHXRPC_CLIENT_CPP_TEMPLATE; +extern const char * PHXRPC_UTHREAD_CLIENT_CPP_TEMPLATE; + extern const char * PHXRPC_CLIENT_FUNC_TEMPLATE; +extern const char * PHXRPC_UTHREAD_CLIENT_FUNC_TEMPLATE; + +extern const char * PHXRPC_SHORT_CLIENT_FUNC_TEMPLATE; +extern const char * PHXRPC_UTHREAD_SHORT_CLIENT_FUNC_TEMPLATE; + extern const char * PHXRPC_BATCH_CLIENT_FUNC_TEMPLATE; extern const char * PHXRPC_CLIENT_ETC_TEMPLATE; + diff --git a/codegen/code_utils.cpp b/codegen/code_utils.cpp index dc7c1d8..cbbd1ab 100644 --- a/codegen/code_utils.cpp +++ b/codegen/code_utils.cpp @@ -1,34 +1,37 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include +#include +#include #include "code_utils.h" + using namespace std; + namespace phxrpc { -void StrTrim(string * str, const char * to_trim) { + +void StrTrim(string *str, const char *to_trim) { string::size_type start_pos = 0; string::size_type end_pos = 0; @@ -43,7 +46,7 @@ void StrTrim(string * str, const char * to_trim) { } } -void StrReplaceAll(string * haystack, string needle, string s) { +void StrReplaceAll(string *haystack, string needle, string s) { string::size_type pos = 0; while ((pos = haystack->find(needle, pos)) != string::npos) { haystack->erase(pos, needle.length()); @@ -52,8 +55,8 @@ void StrReplaceAll(string * haystack, string needle, string s) { } } -void StrAppendFormat(string * result, const char * fmt, ...) { - if (NULL == fmt) +void StrAppendFormat(string *result, const char *fmt, ...) { + if (nullptr == fmt) return; size_t len = 0; @@ -75,5 +78,6 @@ void StrAppendFormat(string * result, const char * fmt, ...) { } } -} + +} // namespace phxrpc diff --git a/codegen/code_utils.h b/codegen/code_utils.h index f36af10..1229eb8 100644 --- a/codegen/code_utils.h +++ b/codegen/code_utils.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -23,11 +23,16 @@ See the AUTHORS file for names of contributors. #include + namespace phxrpc { -void StrTrim(std::string * str, const char * to_trim = "\t\r\n"); -void StrReplaceAll(std::string * haystack, std::string needle, std::string s); -void StrAppendFormat(std::string * result, const char* fmt, ...) __attribute__((format(printf, 2, 3))); +void StrTrim(std::string *str, const char *to_trim = "\t\r\n"); + +void StrReplaceAll(std::string *haystack, std::string needle, std::string s); + +void StrAppendFormat(std::string *result, const char *fmt, ...) __attribute__((format(printf, 2, 3))); + + } diff --git a/codegen/name_render.cpp b/codegen/name_render.cpp index 9ec63b1..22d2fd7 100644 --- a/codegen/name_render.cpp +++ b/codegen/name_render.cpp @@ -1,28 +1,27 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include - +#include +#include +#include #include #include "name_render.h" @@ -30,9 +29,12 @@ See the AUTHORS file for names of contributors. #include "code_utils.h" + using namespace phxrpc; +using namespace std; -NameRender::NameRender(const char * prefix) { + +NameRender::NameRender(const char *prefix) { memset(prefix_, 0, sizeof(prefix_)); strncpy(prefix_, prefix, sizeof(prefix_) - 1); } @@ -40,7 +42,7 @@ NameRender::NameRender(const char * prefix) { NameRender::~NameRender() { } -const char * NameRender::GetPrefix(char * dest, int size) { +const char *NameRender::GetPrefix(char *dest, int size) { snprintf(dest, size, "%s", prefix_); ToUpper(dest); @@ -48,8 +50,8 @@ const char * NameRender::GetPrefix(char * dest, int size) { return dest; } -const char * NameRender::GetMessageClasname(const char * type, char * name, int size) { - std::string tmp = type; +const char *NameRender::GetMessageClassName(const char *type, char *name, int size) { + string tmp = type; phxrpc::StrReplaceAll(&tmp, ".", "::"); @@ -58,11 +60,11 @@ const char * NameRender::GetMessageClasname(const char * type, char * name, int return name; } -const char * NameRender::GetMessageFileName(const char *name, char * dest, int size) { +const char *NameRender::GetMessageFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%s", prefix_, name); - char * pos = strrchr(dest, '.'); - if (NULL != pos) + char *pos{strrchr(dest, '.')}; + if (nullptr != pos) *pos = '\0'; strncat(dest, ".pb", size); @@ -72,8 +74,8 @@ const char * NameRender::GetMessageFileName(const char *name, char * dest, int s return dest; } -char * NameRender::ToLower(register char *s) { - register char *ret = s; +char *NameRender::ToLower(char *s) { + char *ret = s; for (; *s != '\0'; ++s) *s = tolower(*s); @@ -81,8 +83,8 @@ char * NameRender::ToLower(register char *s) { return ret; } -char * NameRender::ToUpper(register char *s) { - register char * ret = s; +char *NameRender::ToUpper(char *s) { + char * ret = s; for (; *s != '\0'; s++) *s = toupper(*s); @@ -90,13 +92,19 @@ char * NameRender::ToUpper(register char *s) { return ret; } -const char * NameRender::GetStubClasname(const char * name, char *dest, int size) { +const char *NameRender::GetStubClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sStub", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetStubFileName(const char *name, char * dest, int size) { +const char *NameRender::GetCallerClassName(const char *name, char *dest, int size) { + snprintf(dest, size, "%s%c%sCaller", prefix_, toupper(*name), name + 1); + + return dest; +} + +const char *NameRender::GetStubFileName(const char *name, char *dest, int size) { snprintf(dest, size, "phxrpc_%s%c%s_stub", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -104,13 +112,13 @@ const char * NameRender::GetStubFileName(const char *name, char * dest, int size return dest; } -const char * NameRender::GetClientClasname(const char *name, char * dest, int size) { +const char *NameRender::GetClientClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sClient", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetClientClasnameLower(const char *name, char * dest, int size) { +const char *NameRender::GetClientClassNameLower(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sClient", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -118,7 +126,7 @@ const char * NameRender::GetClientClasnameLower(const char *name, char * dest, i return dest; } -const char * NameRender::GetClientFileName(const char *name, char * dest, int size) { +const char *NameRender::GetClientFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%s_client", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -126,7 +134,7 @@ const char * NameRender::GetClientFileName(const char *name, char * dest, int si return dest; } -const char * NameRender::GetClientEtcFileName(const char *name, char * dest, int size) { +const char *NameRender::GetClientEtcFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%s_client.conf", prefix_, name); ToLower(dest); @@ -134,12 +142,12 @@ const char * NameRender::GetClientEtcFileName(const char *name, char * dest, int return dest; } -const char * NameRender::GetServerConfigClasname(const char *name, char * dest, int size) { +const char *NameRender::GetServerConfigClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sServerConfig", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetServerConfigFileName(const char *name, char * dest, int size) { +const char *NameRender::GetServerConfigFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%s_server_config", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -147,7 +155,7 @@ const char * NameRender::GetServerConfigFileName(const char *name, char * dest, return dest; } -const char * NameRender::GetServerEtcFileName(const char *name, char * dest, int size) { +const char *NameRender::GetServerEtcFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%s_server.conf", prefix_, name); ToLower(dest); @@ -155,7 +163,7 @@ const char * NameRender::GetServerEtcFileName(const char *name, char * dest, int return dest; } -const char * NameRender::GetServerMainFileName(const char *name, char * dest, int size) { +const char *NameRender::GetServerMainFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%s_main", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -163,13 +171,13 @@ const char * NameRender::GetServerMainFileName(const char *name, char * dest, in return dest; } -const char * NameRender::GetToolClasname(const char * name, char * dest, int size) { +const char *NameRender::GetToolClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sTool", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetToolFileName(const char * name, char * dest, int size) { +const char *NameRender::GetToolFileName(const char *name, char *dest, int size) { snprintf(dest, size, "phxrpc_%s%s_tool", prefix_, name); ToLower(dest); @@ -177,13 +185,13 @@ const char * NameRender::GetToolFileName(const char * name, char * dest, int siz return dest; } -const char * NameRender::GetToolImplClasname(const char * name, char * dest, int size) { +const char *NameRender::GetToolImplClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sToolImpl", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetToolImplFileName(const char * name, char * dest, int size) { +const char *NameRender::GetToolImplFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%s_tool_impl", prefix_, name); ToLower(dest); @@ -191,7 +199,7 @@ const char * NameRender::GetToolImplFileName(const char * name, char * dest, int return dest; } -const char * NameRender::GetToolMainFileName(const char * name, char * dest, int size) { +const char *NameRender::GetToolMainFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%s_tool_main", prefix_, name); ToLower(dest); @@ -199,29 +207,30 @@ const char * NameRender::GetToolMainFileName(const char * name, char * dest, int return dest; } -void NameRender::GetCopyright(const char * tool_name, const char * proto_file, std::string * result, bool dont_edit, - const char * comment_prefix) { - std::ostringstream tmp; +void NameRender::GetCopyright(const char *tool_name, const char *proto_file, + string *result, bool dont_edit, + const char *comment_prefix) { + ostringstream tmp; - tmp << comment_prefix << std::endl; - tmp << comment_prefix << " Generated by " << tool_name << " from " << proto_file << std::endl; + tmp << comment_prefix << endl; + tmp << comment_prefix << " Generated by " << tool_name << " from " << proto_file << endl; if (dont_edit) { - tmp << comment_prefix << std::endl; + tmp << comment_prefix << endl; tmp << comment_prefix << " Please DO NOT edit unless you know exactly what you are doing.\n"; } - tmp << comment_prefix << std::endl; + tmp << comment_prefix << endl; *result = tmp.str(); } -const char * NameRender::GetServiceClasname(const char * name, char * dest, int size) { +const char *NameRender::GetServiceClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sService", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetServiceFileName(const char * name, char * dest, int size) { +const char *NameRender::GetServiceFileName(const char *name, char *dest, int size) { snprintf(dest, size, "phxrpc_%s%c%s_service", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -229,13 +238,13 @@ const char * NameRender::GetServiceFileName(const char * name, char * dest, int return dest; } -const char * NameRender::GetServiceImplClasname(const char * name, char * dest, int size) { +const char *NameRender::GetServiceImplClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sServiceImpl", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetServiceImplFileName(const char * name, char * dest, int size) { +const char *NameRender::GetServiceImplFileName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%s_service_impl", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -243,13 +252,13 @@ const char * NameRender::GetServiceImplFileName(const char * name, char * dest, return dest; } -const char * NameRender::GetDispatcherClasname(const char * name, char * dest, int size) { +const char *NameRender::GetDispatcherClassName(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sDispatcher", prefix_, toupper(*name), name + 1); return dest; } -const char * NameRender::GetDispatcherFileName(const char * name, char * dest, int size) { +const char *NameRender::GetDispatcherFileName(const char *name, char *dest, int size) { snprintf(dest, size, "phxrpc_%s%c%s_dispatcher", prefix_, toupper(*name), name + 1); ToLower(dest); diff --git a/codegen/name_render.h b/codegen/name_render.h index fbb21c7..83d3cc9 100644 --- a/codegen/name_render.h +++ b/codegen/name_render.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,80 +21,81 @@ See the AUTHORS file for names of contributors. #pragma once -#include -#include - +#include +#include #include + namespace phxrpc { + class SyntaxTree; class NameRender { - public: - NameRender(const char * prefix); + public: + NameRender(const char *prefix); virtual ~NameRender(); - virtual const char * GetPrefix(char * dest, int size); + virtual const char *GetPrefix(char *dest, int size); - virtual const char * GetMessageClasname(const char * type, char * name, int size); - virtual const char * GetMessageFileName(const char *name, char * dest, int size); + virtual const char *GetMessageClassName(const char *type, char *name, int size); + virtual const char *GetMessageFileName(const char *name, char *dest, int size); //================================================================ - virtual const char * GetStubClasname(const char * name, char *dest, int size); - virtual const char * GetStubFileName(const char *name, char * dest, int size); + virtual const char *GetStubClassName(const char *name, char *dest, int size); + virtual const char *GetCallerClassName(const char *name, char *dest, int size); + virtual const char *GetStubFileName(const char *name, char *dest, int size); - virtual const char * GetClientClasname(const char * name, char *dest, int size); + virtual const char *GetClientClassName(const char *name, char *dest, int size); - virtual const char * GetClientClasnameLower(const char * name, char *dest, int size); + virtual const char *GetClientClassNameLower(const char *name, char *dest, int size); - virtual const char * GetClientFileName(const char *name, char * dest, int size); + virtual const char *GetClientFileName(const char *name, char *dest, int size); - virtual const char * GetClientEtcFileName(const char *name, char * dest, int size); + virtual const char *GetClientEtcFileName(const char *name, char *dest, int size); //================================================================ - virtual const char * GetServiceClasname(const char * name, char * dest, int size); - virtual const char * GetServiceFileName(const char * name, char * dest, int size); + virtual const char *GetServiceClassName(const char *name, char *dest, int size); + virtual const char *GetServiceFileName(const char *name, char *dest, int size); - virtual const char * GetServiceImplClasname(const char * name, char * dest, int size); - virtual const char * GetServiceImplFileName(const char * name, char * dest, int size); + virtual const char *GetServiceImplClassName(const char *name, char *dest, int size); + virtual const char *GetServiceImplFileName(const char *name, char *dest, int size); - virtual const char * GetDispatcherClasname(const char * name, char * dest, int size); - virtual const char * GetDispatcherFileName(const char * name, char * dest, int size); + virtual const char *GetDispatcherClassName(const char *name, char *dest, int size); + virtual const char *GetDispatcherFileName(const char *name, char *dest, int size); //================================================================ - virtual const char * GetServerConfigClasname(const char *name, char * dest, int size); - virtual const char * GetServerConfigFileName(const char *name, char * dest, int size); + virtual const char *GetServerConfigClassName(const char *name, char *dest, int size); + virtual const char *GetServerConfigFileName(const char *name, char *dest, int size); - virtual const char * GetServerEtcFileName(const char *name, char * dest, int size); + virtual const char *GetServerEtcFileName(const char *name, char *dest, int size); - virtual const char * GetServerMainFileName(const char *name, char * dest, int size); + virtual const char *GetServerMainFileName(const char *name, char *dest, int size); //================================================================ - virtual const char * GetToolClasname(const char * name, char * dest, int size); - virtual const char * GetToolFileName(const char * name, char * dest, int size); + virtual const char *GetToolClassName(const char *name, char *dest, int size); + virtual const char *GetToolFileName(const char *name, char *dest, int size); - virtual const char * GetToolImplClasname(const char * name, char * dest, int size); - virtual const char * GetToolImplFileName(const char * name, char * dest, int size); + virtual const char *GetToolImplClassName(const char *name, char *dest, int size); + virtual const char *GetToolImplFileName(const char *name, char *dest, int size); - virtual const char * GetToolMainFileName(const char * name, char * dest, int size); + virtual const char *GetToolMainFileName(const char *name, char *dest, int size); - virtual void GetCopyright(const char * tool_name, const char * proto_file, std::string * result, bool dont_edit = - true, - const char * comment_prefix = ""); + virtual void GetCopyright(const char *tool_name, const char *proto_file, + std::string *result, bool dont_edit = true, + const char *comment_prefix = ""); - public: + static char *ToLower(register char *s); + static char *ToUpper(register char *s); - static char * ToLower(register char *s); - static char * ToUpper(register char *s); - - protected: + protected: char prefix_[128]; }; + } diff --git a/codegen/phxrpc_pb2client.cpp b/codegen/phxrpc_pb2client.cpp index c658a78..a09b891 100644 --- a/codegen/phxrpc_pb2client.cpp +++ b/codegen/phxrpc_pb2client.cpp @@ -1,30 +1,30 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include +#include +#include +#include #include #include +#include #include "syntax_tree.h" #include "name_render.h" @@ -32,46 +32,62 @@ See the AUTHORS file for names of contributors. #include "client_code_render.h" #include "proto_utils.h" + using namespace phxrpc; using namespace std; -void PrintHelp(const char * program) { + +void PrintHelp(const char *program) { printf("\n"); - printf("PHXRPC ProtoBuf tool\n"); + printf("PhxRPC ProtoBuf tool\n"); printf("\n"); - printf("%s <-f Profo file> <-d destination file dir> [-v]\n", program); - printf(" Usage: -f # Proto File\n"); + printf("%s <-f profo file> <-d destination file dir> [-v]\n", program); + printf(" Usage: -f # proto file\n"); printf(" -d # destination file dir\n"); printf(" -I # include path dir\n"); + printf(" -p # http or mqtt\n"); printf(" -v # print this screen\n"); printf("\n"); return; } -void Proto2Client(const char * program, const char * proto_file, const char * dir_path, - const std::vector & include_list) { +void Proto2Client(const char *program, const char *pb_file, + const char *dir_path, const vector &include_list, + const bool is_uthread_mode, const set &protocols) { SyntaxTree syntax_tree; - - int ret = ProtoUtils::Parse(proto_file, &syntax_tree, include_list); - + int ret{ProtoUtils::Parse(pb_file, &syntax_tree, include_list)}; if (0 != ret) { - printf("parse Proto file fail, please check error log\n"); + printf("parse proto file fail, please check error log\n"); return; } + map protocol2syntax_tree_map; + for_each(protocols.begin(), protocols.end(), + [&](const string &protocol) { + SyntaxTree protocol_syntax_tree; + string protocol_path("phxrpc/"); + protocol_path += protocol + "/" + protocol + ".proto"; + ret = ProtoUtils::Parse(protocol_path.c_str(), &protocol_syntax_tree, include_list); + if (0 != ret) { + printf("add protocol %s fail, please check error log\n", protocol.c_str()); + return; + } + protocol2syntax_tree_map.emplace(protocol, protocol_syntax_tree); + }); + NameRender name_render(syntax_tree.GetPrefix()); - ClientCodeRender clientCodeRender(name_render); + ClientCodeRender code_render(name_render); - char filename[256] = { 0 }, tmp[256] = { 0 }; + char filename[256]{0}, tmp[256]{0}; // [xx]stub.h { name_render.GetStubFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - clientCodeRender.GenerateStubHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateStubHpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -82,25 +98,50 @@ void Proto2Client(const char * program, const char * proto_file, const char * di name_render.GetStubFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - clientCodeRender.GenerateStubCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateStubCpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } + // [xx]client.h { name_render.GetClientFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); - char name4hpp[256] = { 0 }; + char name4hpp[256]{0}; snprintf(name4hpp, sizeof(name4hpp), "%s/%s.hpp", dir_path, tmp); if (0 != access(name4hpp, F_OK)) { if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - clientCodeRender.GenerateClientHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateClientHpp(&syntax_tree, protocol2syntax_tree_map, fp, false); + fclose(fp); + + printf("\n%s: Build %s file ... done\n", program, filename); + } else { + printf("\n%s: %s is exist, skip\n", program, filename); + } + } else { + printf("\n%s: %s is exist, skip\n", program, name4hpp); + } + } + + // [xx]client_uthread.h + if (is_uthread_mode) + { + name_render.GetClientFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); + snprintf(filename, sizeof(filename), "%s/%s_uthread.h", dir_path, tmp); + + char name4hpp[256]{0}; + snprintf(name4hpp, sizeof(name4hpp), "%s/%s_uthread.hpp", dir_path, tmp); + + if (0 != access(name4hpp, F_OK)) { + if (0 != access(filename, F_OK)) { + FILE *fp{fopen(filename, "w")}; + code_render.GenerateClientHpp(&syntax_tree, protocol2syntax_tree_map, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -118,8 +159,25 @@ void Proto2Client(const char * program, const char * proto_file, const char * di snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - clientCodeRender.GenerateClientCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateClientCpp(&syntax_tree, protocol2syntax_tree_map, fp, false); + fclose(fp); + + printf("\n%s: Build %s file ... done\n", program, filename); + } else { + printf("\n%s: %s is exist, skip\n", program, filename); + } + } + + // [xx]client_uthread.cpp + if (is_uthread_mode) + { + name_render.GetClientFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); + snprintf(filename, sizeof(filename), "%s/%s_uthread.cpp", dir_path, tmp); + + if (0 != access(filename, F_OK)) { + FILE *fp{fopen(filename, "w")}; + code_render.GenerateClientCpp(&syntax_tree, protocol2syntax_tree_map, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -134,31 +192,35 @@ void Proto2Client(const char * program, const char * proto_file, const char * di snprintf(filename, sizeof(filename), "%s/%s", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - clientCodeRender.GenerateClientEtc(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateClientEtc(&syntax_tree, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } } -int main(int argc, char * argv[]) { - const char * proto_file = NULL; - const char * dir_path = NULL; +int main(int argc, char **argv) { + const char *pb_file{nullptr}; + const char *dir_path{nullptr}; extern char *optarg; int c; - std::vector include_list; - char real_path[1024] = {0}; - char * rp = nullptr; - - while ((c = getopt(argc, argv, "f:d:I:v")) != EOF) { + vector include_list; + char real_path[1024]{0}; + char *rp{nullptr}; + bool is_uthread_mode{false}; + set protocols; + // always add http + protocols.emplace("http"); + + while (EOF != (c = getopt(argc, argv, "f:d:I:p:uv"))) { switch (c) { case 'f': - proto_file = optarg; + pb_file = optarg; break; case 'd': dir_path = optarg; @@ -169,6 +231,13 @@ int main(int argc, char * argv[]) { include_list.push_back(rp); } break; + case 'p': + if (0 != strcmp(optarg, "http")) + protocols.emplace(optarg); + break; + case 'u': + is_uthread_mode = true; + break; default: PrintHelp(argv[0]); exit(-1); @@ -176,7 +245,7 @@ int main(int argc, char * argv[]) { } } - if (NULL == proto_file || NULL == dir_path) { + if (nullptr == pb_file || nullptr == dir_path) { printf("Invalid arguments\n"); PrintHelp(argv[0]); @@ -189,13 +258,13 @@ int main(int argc, char * argv[]) { exit(0); } - char path[128] = { 0 }; + char path[128]{0}; strncpy(path, dir_path, sizeof(path)); if ('/' == path[strlen(path) - 1]) { path[strlen(path) - 1] = '\0'; } - Proto2Client(argv[0], proto_file, path, include_list); + Proto2Client(argv[0], pb_file, path, include_list, is_uthread_mode, protocols); printf("\n"); diff --git a/codegen/phxrpc_pb2server.cpp b/codegen/phxrpc_pb2server.cpp index 53430bf..dbb3958 100644 --- a/codegen/phxrpc_pb2server.cpp +++ b/codegen/phxrpc_pb2server.cpp @@ -1,33 +1,32 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include +#include +#include +#include #include #include #include -#include #include +#include #include "syntax_tree.h" @@ -35,14 +34,17 @@ See the AUTHORS file for names of contributors. #include "name_render.h" #include "server_code_render.h" + using namespace phxrpc; +using namespace std; + void PrintHelp(const char * program) { printf("\n"); - printf("PHXRPC ProtoBuf tool\n"); + printf("PhxRPC ProtoBuf tool\n"); printf("\n"); - printf("%s <-f Profo file> <-d destination file dir> [-v]\n", program); - printf(" Usage: -f # Proto File\n"); + printf("%s <-f profo file> <-d destination file dir> [-v]\n", program); + printf(" Usage: -f # proto file\n"); printf(" -d # destination file dir\n"); printf(" -I # include path dir\n"); printf(" -e # epoll server\n"); @@ -52,12 +54,13 @@ void PrintHelp(const char * program) { return; } -void Proto2Server(const char * program, const char * pb_file, const char * dir_path, - const std::vector & include_list, const std::string & mk_dir_path) { +void Proto2Server(const char *program, const char *pb_file, + const char *dir_path, const vector &include_list, + const string &mk_dir_path, const bool is_uthread_mode) { SyntaxTree syntax_tree; - std::map parsed_file_map; + map parsed_file_map; - int ret = ProtoUtils::Parse(pb_file, &syntax_tree, &parsed_file_map, include_list); + int ret{ProtoUtils::Parse(pb_file, &syntax_tree, &parsed_file_map, include_list)}; if (0 != ret) { printf("parse proto file fail, please check error log\n"); @@ -65,9 +68,9 @@ void Proto2Server(const char * program, const char * pb_file, const char * dir_p } NameRender name_render(syntax_tree.GetPrefix()); - ServerCodeRender codeRender(name_render); + ServerCodeRender code_render(name_render); - char filename[256] = { 0 }, tmp[256] = { 0 }; + char filename[256]{0}, tmp[256]{0}; // [xx]svrconfig.h { @@ -75,13 +78,13 @@ void Proto2Server(const char * program, const char * pb_file, const char * dir_p snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - codeRender.GenerateServerConfigHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateServerConfigHpp(&syntax_tree, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } @@ -91,13 +94,13 @@ void Proto2Server(const char * program, const char * pb_file, const char * dir_p snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - codeRender.GenerateServerConfigCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateServerConfigCpp(&syntax_tree, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } @@ -107,13 +110,13 @@ void Proto2Server(const char * program, const char * pb_file, const char * dir_p snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - codeRender.GenerateServerMainCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateServerMainCpp(&syntax_tree, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } @@ -123,13 +126,13 @@ void Proto2Server(const char * program, const char * pb_file, const char * dir_p snprintf(filename, sizeof(filename), "%s/%s", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - codeRender.GenerateServerEtc(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateServerEtc(&syntax_tree, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } @@ -138,28 +141,29 @@ void Proto2Server(const char * program, const char * pb_file, const char * dir_p snprintf(filename, sizeof(filename), "%s/Makefile", dir_path); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - codeRender.GenerateMakefile(&syntax_tree, mk_dir_path, fp); + FILE *fp{fopen(filename, "w")}; + code_render.GenerateMakefile(&syntax_tree, mk_dir_path, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } } -int main(int argc, char * argv[]) { - const char * pb_file = NULL; - const char * dir_path = NULL; +int main(int argc, char **argv) { + const char *pb_file{nullptr}; + const char *dir_path{nullptr}; extern char *optarg; int c; - std::vector include_list; - char real_path[1024] = {0}; - char * rp = nullptr; + vector include_list; + char real_path[1024]{0}; + char *rp{nullptr}; + bool is_uthread_mode{false}; - while ((c = getopt(argc, argv, "f:d:I:v")) != EOF) { + while (EOF != (c = getopt(argc, argv, "f:d:I:uv"))) { switch (c) { case 'f': pb_file = optarg; @@ -173,6 +177,9 @@ int main(int argc, char * argv[]) { include_list.push_back(rp); } break; + case 'u': + is_uthread_mode = true; + break; default: PrintHelp(argv[0]); exit(-1); @@ -180,7 +187,7 @@ int main(int argc, char * argv[]) { } } - if (NULL == pb_file || NULL == dir_path) { + if (nullptr == pb_file || nullptr == dir_path) { printf("Invalid arguments\n"); PrintHelp(argv[0]); @@ -193,23 +200,23 @@ int main(int argc, char * argv[]) { exit(0); } - char path[128] = { 0 }; + char path[128]{0}; strncpy(path, dir_path, sizeof(path)); if ('/' == path[strlen(path) - 1]) { path[strlen(path) - 1] = '\0'; } - std::string mk_dir_path; - char * real_p_path = realpath(argv[0], real_path); - if (real_p_path != nullptr) { - mk_dir_path = std::string(real_p_path); + string mk_dir_path; + char *real_p_path = realpath(argv[0], real_path); + if (nullptr != real_p_path) { + mk_dir_path = string(real_p_path); size_t pos = mk_dir_path.find("/codegen/phxrpc_pb2server"); - if (pos != std::string::npos) { + if (pos != string::npos) { mk_dir_path = mk_dir_path.substr(0, pos); } } - Proto2Server(argv[0], pb_file, path, include_list, mk_dir_path); + Proto2Server(argv[0], pb_file, path, include_list, mk_dir_path, is_uthread_mode); return 0; } diff --git a/codegen/phxrpc_pb2service.cpp b/codegen/phxrpc_pb2service.cpp index 7be1667..abf4ee2 100644 --- a/codegen/phxrpc_pb2service.cpp +++ b/codegen/phxrpc_pb2service.cpp @@ -1,32 +1,32 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include +#include +#include +#include +#include #include -#include #include #include +#include #include "syntax_tree.h" @@ -34,48 +34,65 @@ See the AUTHORS file for names of contributors. #include "service_code_render.h" #include "proto_utils.h" + using namespace phxrpc; using namespace std; -void PrintHelp(const char * program) { + +void PrintHelp(const char *program) { printf("\n"); - printf("PHXRPC ProtoBuf tool\n"); + printf("PhxRPC ProtoBuf tool\n"); printf("\n"); - printf("%s <-f Profo file> <-d destination file dir> [-v]\n", program); - printf(" Usage: -f # Proto File\n"); + printf("%s <-f profo file> <-d destination file dir> [-p] [-v]\n", program); + printf(" Usage: -f # proto file\n"); printf(" -d # destination file dir\n"); printf(" -I # include path dir\n"); + printf(" -p # http or mqtt\n"); printf(" -v # print this screen\n"); printf("\n"); + return; } -void Proto2Service(const char * program, const char * pb_file, const char * dir_path, - const std::vector & include_list) { - std::map parsed_file_map; +void Proto2Service(const char *program, const char *pb_file, + const char *dir_path, const vector &include_list, + const bool is_uthread_mode, const set &protocols) { SyntaxTree syntax_tree; - - int ret = ProtoUtils::Parse(pb_file, &syntax_tree, &parsed_file_map, include_list); + int ret{ProtoUtils::Parse(pb_file, &syntax_tree, include_list)}; if (0 != ret) { printf("parse proto file fail, please check error log\n"); return; } - // printf( "parse(%s) = %d\n", pb_file, ret ); + map protocol2syntax_tree_map; + for_each(protocols.begin(), protocols.end(), + [&](const string &protocol) { + SyntaxTree protocol_syntax_tree; + string protocol_path("phxrpc/"); + protocol_path += protocol + "/" + protocol + ".proto"; + ret = ProtoUtils::Parse(protocol_path.c_str(), &protocol_syntax_tree, include_list); + if (0 != ret) { + printf("add protocol %s fail, please check error log\n", protocol.c_str()); + return; + } + protocol2syntax_tree_map.emplace(protocol, protocol_syntax_tree); + }); NameRender name_render(syntax_tree.GetPrefix()); - ServiceCodeRender codeRender(name_render); + ServiceCodeRender code_render(name_render); + + // generate files - char filename[256] = { 0 }, tmp[256] = { 0 }; + char filename[256]{0}, tmp[256]{0}; // [xx]service.h { name_render.GetServiceFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateServiceHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateServiceHpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -85,9 +102,9 @@ void Proto2Service(const char * program, const char * pb_file, const char * dir_ { name_render.GetServiceFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateServiceCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateServiceCpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -99,9 +116,9 @@ void Proto2Service(const char * program, const char * pb_file, const char * dir_ snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateServiceImplHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateServiceImplHpp(&syntax_tree, protocol2syntax_tree_map, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -116,9 +133,9 @@ void Proto2Service(const char * program, const char * pb_file, const char * dir_ snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateServiceImplCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateServiceImplCpp(&syntax_tree, protocol2syntax_tree_map, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -132,9 +149,9 @@ void Proto2Service(const char * program, const char * pb_file, const char * dir_ name_render.GetDispatcherFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateDispatcherHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateDispatcherHpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -145,26 +162,30 @@ void Proto2Service(const char * program, const char * pb_file, const char * dir_ name_render.GetDispatcherFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateDispatcherCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateDispatcherCpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } } -int main(int argc, char * argv[]) { - const char * pb_file = NULL; - const char * dir_path = NULL; +int main(int argc, char **argv) { + const char *pb_file{nullptr}; + const char *dir_path{nullptr}; extern char *optarg; int c; - std::vector include_list; - char real_path[1024] = {0}; - char * rp = nullptr; - - while ((c = getopt(argc, argv, "f:d:I:v")) != EOF) { + vector include_list; + char real_path[1024]{0}; + char *rp{nullptr}; + bool is_uthread_mode{false}; + set protocols; + // always add http + protocols.emplace("http"); + + while (EOF != (c = getopt(argc, argv, "f:d:I:p:uv"))) { switch (c) { case 'f': pb_file = optarg; @@ -178,6 +199,13 @@ int main(int argc, char * argv[]) { include_list.push_back(rp); } break; + case 'p': + if (0 != strcmp(optarg, "http")) + protocols.emplace(optarg); + break; + case 'u': + is_uthread_mode = true; + break; default: PrintHelp(argv[0]); exit(-1); @@ -185,7 +213,7 @@ int main(int argc, char * argv[]) { } } - if (NULL == pb_file || NULL == dir_path) { + if (nullptr == pb_file || nullptr == dir_path) { printf("Invalid arguments\n"); PrintHelp(argv[0]); @@ -199,13 +227,13 @@ int main(int argc, char * argv[]) { exit(0); } - char path[128] = { 0 }; + char path[128]{0}; strncpy(path, dir_path, sizeof(path)); if ('/' == path[strlen(path) - 1]) { path[strlen(path) - 1] = '\0'; } - Proto2Service(argv[0], pb_file, path, include_list); + Proto2Service(argv[0], pb_file, path, include_list, is_uthread_mode, protocols); printf("\n"); diff --git a/codegen/phxrpc_pb2tool.cpp b/codegen/phxrpc_pb2tool.cpp index e6e8438..acded9d 100644 --- a/codegen/phxrpc_pb2tool.cpp +++ b/codegen/phxrpc_pb2tool.cpp @@ -1,31 +1,31 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include +#include +#include +#include +#include #include -#include #include +#include #include "syntax_tree.h" @@ -33,47 +33,61 @@ See the AUTHORS file for names of contributors. #include "proto_utils.h" #include "name_render.h" + using namespace phxrpc; +using namespace std; -void PrintHelp(const char * program) { + +void PrintHelp(const char *program) { printf("\n"); - printf("PHXRPC ProtoBuf tool\n"); + printf("PhxRPC ProtoBuf tool\n"); printf("\n"); - printf("%s <-f Profo file> <-d destination file dir> [-v]\n", program); - printf(" Usage: -f # Proto File\n"); + printf("%s <-f profo file> <-d destination file dir> [-p] [-v]\n", program); + printf(" Usage: -f # proto file\n"); printf(" -d # destination file dir\n"); printf(" -I # include path dir\n"); + printf(" -p # http or mqtt\n"); printf(" -v # print this screen\n"); printf("\n"); return; } -void Proto2Tool(const char * program, const char * pb_file, const char * dir_path, - const std::vector & include_list) { +void Proto2Tool(const char *program, const char *pb_file, const char *dir_path, + const vector &include_list, const set &protocols) { SyntaxTree syntax_tree; - - int ret = ProtoUtils::Parse(pb_file, &syntax_tree, include_list); - + int ret{ProtoUtils::Parse(pb_file, &syntax_tree, include_list)}; if (0 != ret) { printf("parse proto file fail, please check error log\n"); return; } - // printf( "parse(%s) = %d\n", pb_file, ret ); + map protocol2syntax_tree_map; + for_each(protocols.begin(), protocols.end(), + [&](const string &protocol) { + SyntaxTree protocol_syntax_tree; + string protocol_path("phxrpc/"); + protocol_path += protocol + "/" + protocol + ".proto"; + ret = ProtoUtils::Parse(protocol_path.c_str(), &protocol_syntax_tree, include_list); + if (0 != ret) { + printf("add protocol %s fail, please check error log\n", protocol.c_str()); + return; + } + protocol2syntax_tree_map.emplace(protocol, protocol_syntax_tree); + }); NameRender name_render(syntax_tree.GetPrefix()); - ToolCodeRender codeRender(name_render); + ToolCodeRender code_render(name_render); - char filename[256] = { 0 }, tmp[256] = { 0 }; + char filename[256]{0}, tmp[256]{0}; // [xx]tool.h { name_render.GetToolFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateToolHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateToolHpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -84,9 +98,9 @@ void Proto2Tool(const char * program, const char * pb_file, const char * dir_pat name_render.GetToolFileName(syntax_tree.GetName(), tmp, sizeof(tmp)); snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateToolCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateToolCpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -98,14 +112,14 @@ void Proto2Tool(const char * program, const char * pb_file, const char * dir_pat snprintf(filename, sizeof(filename), "%s/%s.h", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateToolImplHpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateToolImplHpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } @@ -115,14 +129,14 @@ void Proto2Tool(const char * program, const char * pb_file, const char * dir_pat snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateToolImplCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateToolImplCpp(&syntax_tree, protocol2syntax_tree_map, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } @@ -132,29 +146,32 @@ void Proto2Tool(const char * program, const char * pb_file, const char * dir_pat snprintf(filename, sizeof(filename), "%s/%s.cpp", dir_path, tmp); if (0 != access(filename, F_OK)) { - FILE * fp = fopen(filename, "w"); - assert(NULL != fp); - codeRender.GenerateToolMainCpp(&syntax_tree, fp); + FILE *fp{fopen(filename, "w")}; + assert(nullptr != fp); + code_render.GenerateToolMainCpp(&syntax_tree, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); } else { - printf("\n%s: %s is exist, ip\n", program, filename); + printf("\n%s: %s is exist, skip\n", program, filename); } } } -int main(int argc, char * argv[]) { - const char * pb_file = NULL; - const char * dir_path = NULL; +int main(int argc, char **argv) { + const char *pb_file{nullptr}; + const char *dir_path{nullptr}; extern char *optarg; int c; - std::vector include_list; - char real_path[1024] = {0}; - char * rp = nullptr; - - while ((c = getopt(argc, argv, "f:d:I:v")) != EOF) { + vector include_list; + char real_path[1024]{0}; + char *rp{nullptr}; + set protocols; + // always add http + protocols.emplace("http"); + + while (EOF != (c = getopt(argc, argv, "f:d:I:p:v"))) { switch (c) { case 'f': pb_file = optarg; @@ -168,6 +185,10 @@ int main(int argc, char * argv[]) { include_list.push_back(rp); } break; + case 'p': + if (0 != strcmp(optarg, "http")) + protocols.emplace(optarg); + break; default: PrintHelp(argv[0]); exit(-1); @@ -175,7 +196,7 @@ int main(int argc, char * argv[]) { } } - if (NULL == pb_file || NULL == dir_path) { + if (nullptr == pb_file || nullptr == dir_path) { printf("Invalid arguments\n"); PrintHelp(argv[0]); @@ -188,13 +209,13 @@ int main(int argc, char * argv[]) { exit(0); } - char path[128] = { 0 }; + char path[128]{0}; strncpy(path, dir_path, sizeof(path)); if ('/' == path[strlen(path) - 1]) { path[strlen(path) - 1] = '\0'; } - Proto2Tool(argv[0], pb_file, path, include_list); + Proto2Tool(argv[0], pb_file, path, include_list, protocols); printf("\n"); diff --git a/codegen/proto_utils.cpp b/codegen/proto_utils.cpp index 53fb379..dca8102 100644 --- a/codegen/proto_utils.cpp +++ b/codegen/proto_utils.cpp @@ -1,48 +1,50 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include +#include #include +#include #include - #include -#include + #include "proto_utils.h" + using namespace google::protobuf::compiler; using namespace google::protobuf; using namespace phxrpc; using namespace std; + class MyErrorPrinter : public MultiFileErrorCollector { - public: + public: MyErrorPrinter() { } - ~MyErrorPrinter() { + virtual ~MyErrorPrinter() override { } - void AddError(const std::string& filename, int line, int column, const std::string& message) { + void AddError(const std::string& file_name, int line, int column, const std::string& message) { - fprintf(stderr, "%s", filename.c_str()); + fprintf(stderr, "%s", file_name.c_str()); if (line != -1) fprintf(stderr, ":%d:%d", line + 1, column + 1); @@ -51,12 +53,12 @@ class MyErrorPrinter : public MultiFileErrorCollector { } }; -int ProtoUtils::Parse(const char * file, SyntaxTree * stree, const std::vector & include_list) { - return Parse(file, stree, NULL, include_list); +int ProtoUtils::Parse(const char *file, SyntaxTree *stree, const vector &include_list) { + return Parse(file, stree, nullptr, include_list); } -int ProtoUtils::Parse(const char * file, SyntaxTree * stree, std::map * parsed_file_map, - const std::vector & include_list) { +int ProtoUtils::Parse(const char *file, SyntaxTree *stree, map *parsed_file_map, + const vector &include_list) { DiskSourceTree tree; tree.MapPath("", "./"); @@ -64,35 +66,32 @@ int ProtoUtils::Parse(const char * file, SyntaxTree * stree, std::map * parsed_file_map, - DiskSourceTree & tree) { +int ProtoUtils::LoadNormal(const char *file_name, SyntaxTree *stree, map *parsed_file_map, + DiskSourceTree &tree) { MyErrorPrinter error; Importer importer(&tree, &error); - const FileDescriptor * fd = importer.Import(filename); + const FileDescriptor *fd{importer.Import(file_name)}; - stree->SetPackageName(fd->package().c_str()); + stree->SetCppPackageName(SyntaxTree::Pb2CppPackageName(fd->package()).c_str()); - stree->SetProtoFile(filename); + stree->SetProtoFile(file_name); - for (int i = 0; i < 1 && i < fd->service_count(); i++) { + for (int i{0}; 1 > i && fd->service_count() > i; ++i) { const ServiceDescriptor * iter = fd->service(i); stree->SetName(iter->name().c_str()); - for (int j = 0; j < iter->method_count(); j++) { - const MethodDescriptor * method = iter->method(j); + for (int j{0}; iter->method_count() > j; ++j) { + const MethodDescriptor *method{iter->method(j)}; SyntaxFunc func; func.SetName(method->name().c_str()); @@ -113,7 +112,7 @@ int ProtoUtils::LoadNormal(const char * filename, SyntaxTree * stree, std::map i && fd_proto.service_size() > i; ++i) { + const ServiceDescriptorProto &svc(fd_proto.service(i)); - for (int j = 0; j < svc.method_size(); j++) { - const MethodDescriptorProto & method = svc.method(j); + for (int j{0}; svc.method_size() > j; ++j) { + const MethodDescriptorProto &method(svc.method(j)); - SyntaxFunc * func = stree->FindFunc(method.name().c_str()); + SyntaxFunc *func{stree->FindFunc(method.name().c_str())}; - assert(NULL != func); + assert(nullptr != func); - const MethodOptions & options = method.options(); + const MethodOptions &options(method.options()); - for (int k = 0; k < options.uninterpreted_option_size(); k++) { - const UninterpretedOption & opt = options.uninterpreted_option(k); + for (int k{0}; options.uninterpreted_option_size() > k; ++k) { + const UninterpretedOption &opt(options.uninterpreted_option(k)); if (opt.name_size() > 0) { - if (NULL != strstr(opt.name(0).name_part().c_str(), "OptString")) { + if (nullptr != strstr(opt.name(0).name_part().c_str(), "OptString")) { func->SetOptString(opt.string_value().c_str()); } - if (NULL != strstr(opt.name(0).name_part().c_str(), "Usage")) { + if (nullptr != strstr(opt.name(0).name_part().c_str(), "Usage")) { func->SetUsage(opt.string_value().c_str()); } - if (NULL != strstr(opt.name(0).name_part().c_str(), "CmdID")) { + if (nullptr != strstr(opt.name(0).name_part().c_str(), "CmdID")) { func->SetCmdID(opt.positive_int_value()); } } @@ -158,25 +157,3 @@ int ProtoUtils::LoadExtension(const char * filename, SyntaxTree * stree, DiskSou return 0; } -int ProtoUtils::AddEcho(SyntaxTree * stree) { - char name[256] = { 0 }; - - snprintf(name, sizeof(name), "google.protobuf.StringValue"); - - // always add a echo function - { - SyntaxFunc echo_func; - echo_func.SetName("PHXEcho"); - echo_func.GetReq()->SetName("request"); - echo_func.GetReq()->SetType(name); - echo_func.GetResp()->SetName("response"); - echo_func.GetResp()->SetType(name); - echo_func.SetOptString("s:"); - echo_func.SetUsage("-s "); - - stree->GetFuncList()->insert(stree->GetFuncList()->begin(), echo_func); - } - - return 0; -} - diff --git a/codegen/proto_utils.h b/codegen/proto_utils.h index 8cc46d5..ea64a35 100644 --- a/codegen/proto_utils.h +++ b/codegen/proto_utils.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -24,34 +24,35 @@ See the AUTHORS file for names of contributors. #include #include #include -#include "syntax_tree.h" + #include #include +#include "syntax_tree.h" + + namespace phxrpc { -class ProtoUtils { - public: - static int Parse(const char * file, phxrpc::SyntaxTree * stree, - const std::vector & include_list); - static int Parse(const char * file, phxrpc::SyntaxTree * stree, std::map * parsed_file_map, - const std::vector & include_list); - private: +class ProtoUtils { + public: + static int Parse(const char *file, phxrpc::SyntaxTree *stree, + const std::vector &include_list); + static int Parse(const char *file, phxrpc::SyntaxTree *stree, std::map *parsed_file_map, + const std::vector & include_list); - static int LoadNormal(const char * file, phxrpc::SyntaxTree * stree, std::map * parsed_file_map, - google::protobuf::compiler::DiskSourceTree & tree); + private: - static int LoadExtension(const char * file, phxrpc::SyntaxTree * stree, - google::protobuf::compiler::DiskSourceTree & tree); + static int LoadNormal(const char *file_name, phxrpc::SyntaxTree *stree, std::map *parsed_file_map, + google::protobuf::compiler::DiskSourceTree & tree); - static int AddEcho(phxrpc::SyntaxTree * stree); + static int LoadExtension(const char *file_name, phxrpc::SyntaxTree *stree, + google::protobuf::compiler::DiskSourceTree & tree); - private: ProtoUtils(); - ~ProtoUtils(); + virtual ~ProtoUtils(); }; + } -; diff --git a/codegen/server_code_render.cpp b/codegen/server_code_render.cpp index af8523d..17fed0b 100644 --- a/codegen/server_code_render.cpp +++ b/codegen/server_code_render.cpp @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -27,20 +27,23 @@ See the AUTHORS file for names of contributors. #include "code_utils.h" #include + using namespace phxrpc; +using namespace std; + -ServerCodeRender::ServerCodeRender(NameRender & name_render) +ServerCodeRender::ServerCodeRender(NameRender &name_render) : name_render_(name_render) { } ServerCodeRender::~ServerCodeRender() { } -void ServerCodeRender::GenerateServerConfigHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServerCodeRender::GenerateServerConfigHpp(SyntaxTree *stree, FILE *write) { + char filename[128]{0}; name_render_.GetServerConfigFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2server", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.h\n", filename); @@ -53,9 +56,9 @@ void ServerCodeRender::GenerateServerConfigHpp(SyntaxTree * stree, FILE * write) fprintf(write, "\n"); char classname[128] = { 0 }; - name_render_.GetServerConfigClasname(stree->GetName(), classname, sizeof(classname)); + name_render_.GetServerConfigClassName(stree->GetName(), classname, sizeof(classname)); - std::string content = PHXRPC_EPOLL_SERVER_CONFIG_HPP_TEMPLATE; + string content = PHXRPC_EPOLL_SERVER_CONFIG_HPP_TEMPLATE; StrTrim(&content); StrReplaceAll(&content, "$ServerConfigClass$", classname); @@ -63,13 +66,14 @@ void ServerCodeRender::GenerateServerConfigHpp(SyntaxTree * stree, FILE * write) fprintf(write, "%s", content.c_str()); fprintf(write, "\n"); + fprintf(write, "\n"); } -void ServerCodeRender::GenerateServerConfigCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServerCodeRender::GenerateServerConfigCpp(SyntaxTree *stree, FILE *write) { + char filename[128]{0}; name_render_.GetServerConfigFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2server", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.cpp\n", filename); @@ -77,50 +81,52 @@ void ServerCodeRender::GenerateServerConfigCpp(SyntaxTree * stree, FILE * write) fprintf(write, "*/\n"); fprintf(write, "\n"); - char classname[128] = { 0 }; - char message_file[128] = {0}; - name_render_.GetServerConfigClasname(stree->GetName(), classname, sizeof(classname)); + char classname[128]{0}; + char message_file[128]{0}; + name_render_.GetServerConfigClassName(stree->GetName(), classname, sizeof(classname)); name_render_.GetMessageFileName(stree->GetProtoFile(), message_file, sizeof(message_file)); - std::string content = PHXRPC_EPOLL_SERVER_CONFIG_CPP_TEMPLATE; + string content = PHXRPC_EPOLL_SERVER_CONFIG_CPP_TEMPLATE; - std::string package_name = "\"" + std::string(stree->GetPackageName()) + "\""; + string package_name_expression = "\"" + string(SyntaxTree::Cpp2PbPackageName(stree->GetCppPackageName())) + "\""; { - std::string message_name = ""; - for( auto itr : *(stree->GetFuncList()) ) { - if ( std::string(itr.GetReq()->GetType()).find( stree->GetPackageName() ) != std::string::npos ) { + string message_name; + for (auto itr : *(stree->GetFuncList())) { + if (string(itr.GetReq()->GetType()).find(stree->GetCppPackageName()) != string::npos) { message_name = itr.GetReq()->GetType(); break; - } else if ( std::string(itr.GetResp()->GetType()).find( stree->GetPackageName() ) != std::string::npos ) { + } else if (string(itr.GetResp()->GetType()).find(stree->GetCppPackageName()) != string::npos) { message_name = itr.GetResp()->GetType(); break; } } - if( message_name != "" ) { - int package_name_len = strlen(stree->GetPackageName()); - message_name = message_name.substr( package_name_len + 1, message_name.size() - package_name_len - 1 ); - package_name = "\n" + std::string(stree->GetPackageName()) + "::" + message_name + if (message_name != "") { + int package_name_len = strlen(stree->GetCppPackageName()); + message_name = message_name.substr(package_name_len + 1, + message_name.size() - package_name_len - 1); + package_name_expression = "\n " + string(stree->GetCppPackageName()) + "::" + message_name + "::default_instance().GetDescriptor()->file()->package().c_str()"; } } StrTrim(&content); StrReplaceAll(&content, "$MessageFile$", message_file); - StrReplaceAll(&content, "$PackageName$", package_name); + StrReplaceAll(&content, "$PackageNameExpression$", package_name_expression); StrReplaceAll(&content, "$ServerConfigClass$", classname); StrReplaceAll(&content, "$ServerConfigFile$", filename); fprintf(write, "%s", content.c_str()); fprintf(write, "\n"); + fprintf(write, "\n"); } -void ServerCodeRender::GenerateServerMainCpp(SyntaxTree * stree, FILE * write) { - char svrfile[128] = { 0 }; +void ServerCodeRender::GenerateServerMainCpp(SyntaxTree *stree, FILE *write, const bool is_uthread_mode) { + char svrfile[128]{0}; name_render_.GetServerMainFileName(stree->GetName(), svrfile, sizeof(svrfile)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2server", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.cpp\n", svrfile); @@ -128,22 +134,27 @@ void ServerCodeRender::GenerateServerMainCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "*/\n"); fprintf(write, "\n"); - char dispatcher_calss[128] = { 0 }, dispatcher_file[128] = { 0 }; - char service_impl_class[128] = { 0 }, service_impl_file[128] = { 0 }; - char server_config_class[128] = { 0 }, server_config_file[128] = { 0 }; + char dispatcher_class[128]{0}, dispatcher_file[128]{0}; + char service_impl_class[128]{0}, service_impl_file[128]{0}; + char server_config_class[128]{0}, server_config_file[128]{0}; - name_render_.GetDispatcherClasname(stree->GetName(), dispatcher_calss, sizeof(dispatcher_calss)); + name_render_.GetDispatcherClassName(stree->GetName(), dispatcher_class, sizeof(dispatcher_class)); name_render_.GetDispatcherFileName(stree->GetName(), dispatcher_file, sizeof(dispatcher_file)); - name_render_.GetServiceImplClasname(stree->GetName(), service_impl_class, sizeof(service_impl_class)); + name_render_.GetServiceImplClassName(stree->GetName(), service_impl_class, sizeof(service_impl_class)); name_render_.GetServiceImplFileName(stree->GetName(), service_impl_file, sizeof(service_impl_file)); - name_render_.GetServerConfigClasname(stree->GetName(), server_config_class, sizeof(server_config_class)); + name_render_.GetServerConfigClassName(stree->GetName(), server_config_class, sizeof(server_config_class)); name_render_.GetServerConfigFileName(stree->GetName(), server_config_file, sizeof(server_config_file)); - std::string content = PHXRPC_EPOLL_SERVER_MAIN_TEMPLATE; + string content; + if (!is_uthread_mode) { + content = PHXRPC_EPOLL_SERVER_MAIN_TEMPLATE; + } else { + content = PHXRPC_EPOLL_UTHREAD_SERVER_MAIN_TEMPLATE; + } StrTrim(&content); StrReplaceAll(&content, "$DispatcherFile$", dispatcher_file); - StrReplaceAll(&content, "$DispatcherClass$", dispatcher_calss); + StrReplaceAll(&content, "$DispatcherClass$", dispatcher_class); StrReplaceAll(&content, "$ServiceImplFile$", service_impl_file); StrReplaceAll(&content, "$ServiceImplClass$", service_impl_class); StrReplaceAll(&content, "$ServerConfigFile$", server_config_file); @@ -152,13 +163,14 @@ void ServerCodeRender::GenerateServerMainCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "%s", content.c_str()); fprintf(write, "\n"); + fprintf(write, "\n"); } -void ServerCodeRender::GenerateServerEtc(SyntaxTree * stree, FILE * write) { - char etcfile[128] = { 0 }; +void ServerCodeRender::GenerateServerEtc(SyntaxTree *stree, FILE *write, const bool is_uthread_mode) { + char etcfile[128]{0}; name_render_.GetServerEtcFileName(stree->GetName(), etcfile, sizeof(etcfile)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2server", stree->GetProtoFile(), &buffer, false, "#"); fprintf(write, "# %s\n", etcfile); @@ -166,18 +178,26 @@ void ServerCodeRender::GenerateServerEtc(SyntaxTree * stree, FILE * write) { fprintf(write, "#\n"); fprintf(write, "\n"); - std::string content = PHXRPC_EPOLL_SERVER_ETC_TEMPLATE; + string content; + if (!is_uthread_mode) { + content = PHXRPC_EPOLL_SERVER_ETC_TEMPLATE; + } else { + content = PHXRPC_EPOLL_UTHREAD_SERVER_ETC_TEMPLATE; + } StrTrim(&content); - StrReplaceAll(&content, "$PackageName$", stree->GetPackageName() ); + StrReplaceAll(&content, "$PbPackageName$", + SyntaxTree::Cpp2PbPackageName(stree->GetCppPackageName())); fprintf(write, "%s", content.c_str()); fprintf(write, "\n"); + fprintf(write, "\n"); } -void ServerCodeRender::GenerateMakefile(SyntaxTree * stree, const std::string & mk_dir_path, FILE * write) { - std::string buffer; +void ServerCodeRender::GenerateMakefile(SyntaxTree *stree, + const string &mk_dir_path, FILE *write, const bool is_uthread_mode) { + string buffer; name_render_.GetCopyright("phxrpc_pb2server", stree->GetProtoFile(), &buffer, false, "#"); fprintf(write, "# Makefile\n"); @@ -185,10 +205,10 @@ void ServerCodeRender::GenerateMakefile(SyntaxTree * stree, const std::string & fprintf(write, "#\n"); fprintf(write, "\n"); - char dispatcher_file[128] = { 0 }, service_file[128] = { 0 }, service_impl_file[128] = { 0 }; - char server_config_file[128] = { 0 }, server_main_file[128] = { 0 }; - char message_file[128] = { 0 }, stub_file[128] = { 0 }, client_file[128] = { 0 }; - char tool_file[128] = { 0 }, tool_impl_file[128] = { 0 }, tool_main_file[128] = { 0 }; + char dispatcher_file[128]{0}, service_file[128]{0}, service_impl_file[128]{0}; + char server_config_file[128]{0}, server_main_file[128]{0}; + char message_file[128]{0}, stub_file[128]{0}, client_file[128]{0}; + char tool_file[128]{0}, tool_impl_file[128]{0}, tool_main_file[128]{0}; name_render_.GetDispatcherFileName(stree->GetName(), dispatcher_file, sizeof(dispatcher_file)); name_render_.GetServiceImplFileName(stree->GetName(), service_impl_file, sizeof(service_impl_file)); @@ -205,7 +225,13 @@ void ServerCodeRender::GenerateMakefile(SyntaxTree * stree, const std::string & name_render_.GetStubFileName(stree->GetName(), stub_file, sizeof(stub_file)); name_render_.GetMessageFileName(stree->GetProtoFile(), message_file, sizeof(message_file)); - std::string content(PHXRPC_SERVER_MAKEFILE_TEMPLATE); + string content; + if (!is_uthread_mode) { + content = PHXRPC_SERVER_MAKEFILE_TEMPLATE; + } else { + content = PHXRPC_UTHREAD_SERVER_MAKEFILE_TEMPLATE; + } + StrTrim(&content); StrReplaceAll(&content, "$PhxRPCMKDir$", mk_dir_path); StrReplaceAll(&content, "$DispatcherFile$", dispatcher_file); diff --git a/codegen/server_code_render.h b/codegen/server_code_render.h index 2b744f3..58a5542 100644 --- a/codegen/server_code_render.h +++ b/codegen/server_code_render.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -30,21 +30,22 @@ class NameRender; class SyntaxTree; class ServerCodeRender { - public: - ServerCodeRender(NameRender & name_render); - ~ServerCodeRender(); + public: + ServerCodeRender(NameRender &name_render); + virtual ~ServerCodeRender(); - void GenerateServerConfigHpp(SyntaxTree * stree, FILE * write); + void GenerateServerConfigHpp(SyntaxTree *stree, FILE *write); - void GenerateServerConfigCpp(SyntaxTree * stree, FILE * write); + void GenerateServerConfigCpp(SyntaxTree *stree, FILE *write); - void GenerateServerMainCpp(SyntaxTree * stree, FILE * write); + void GenerateServerMainCpp(SyntaxTree *stree, FILE *write, const bool is_uthread_mode); - void GenerateServerEtc(SyntaxTree * stree, FILE * write); + void GenerateServerEtc(SyntaxTree *stree, FILE *write, const bool is_uthread_mode); - void GenerateMakefile(SyntaxTree * stree, const std::string & mk_dir_path, FILE * write); + void GenerateMakefile(SyntaxTree *stree, const std::string &mk_dir_path, + FILE *write, const bool is_uthread_mode); - private: + private: NameRender & name_render_; }; diff --git a/codegen/server_template.cpp b/codegen/server_template.cpp index 0f694d1..5855c0c 100644 --- a/codegen/server_template.cpp +++ b/codegen/server_template.cpp @@ -1,96 +1,209 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -const char * PHXRPC_EPOLL_SERVER_MAIN_TEMPLATE = +const char *PHXRPC_EPOLL_SERVER_MAIN_TEMPLATE = R"( #include #include #include #include + #include "$DispatcherFile$.h" #include "$ServiceImplFile$.h" #include "$ServerConfigFile$.h" -#include "phxrpc/rpc.h" -#include "phxrpc/http.h" #include "phxrpc/file.h" +#include "phxrpc/msg.h" +#include "phxrpc/rpc.h" + using namespace std; -void HttpDispatch( const phxrpc::HttpRequest & request, phxrpc::HttpResponse * response, phxrpc::DispatcherArgs_t * args ) { - ServiceArgs_t * service_args = (ServiceArgs_t *)(args->service_args); +void Dispatch(const phxrpc::BaseRequest *request, + phxrpc::BaseResponse *response, + phxrpc::DispatcherArgs_t *args) { + ServiceArgs_t *service_args{(ServiceArgs_t *)(args->service_args)}; - $ServiceImplClass$ service( service_args ); - $DispatcherClass$ dispatcher( service, args ); + $ServiceImplClass$ service(*service_args, args->pool_idx, args->worker_idx, + args->notifier_pool, args->notifier_pool_router, + args->cross_unit_data_flow, (phxrpc::ServiceContext *)(args->context)); + $DispatcherClass$ dispatcher(service, args); - phxrpc::HttpDispatcher<$DispatcherClass$> http_dispatcher( - dispatcher, $DispatcherClass$::GetURIFuncMap() ); - if( ! http_dispatcher.Dispatch( request, response ) ) { - response->SetStatusCode( 404 ); - response->SetReasonPhrase( "Not Found" ); + phxrpc::BaseDispatcher<$DispatcherClass$> base_dispatcher( + dispatcher, $DispatcherClass$::GetURIFuncMap()); + if (!base_dispatcher.Dispatch(request, response)) { + response->DispatchErr(); } } -void showUsage( const char * program ) { - printf( "\n" ); - printf( "Usage: %s [-c ] [-v]\n", program ); - printf( "\n" ); +void ShowUsage(const char *program) { + printf("\n"); + printf("Usage: %s [-c ] [-d] [-l ] [-v]\n", program); + printf("\n"); + + exit(0); +} + +int main(int argc, char **argv) { + const char *config_file{nullptr}; + bool daemonize{false}; + int log_level{-1}; + extern char *optarg; + int c; + while (EOF != (c = getopt(argc, argv, "c:vl:d"))) { + switch (c) { + case 'c': config_file = optarg; break; + case 'd': daemonize = true; break; + case 'l': log_level = atoi(optarg); break; + + case 'v': + default: ShowUsage(argv[0]); break; + } + } + + if (daemonize) phxrpc::ServerUtils::Daemonize(); + + assert(signal(SIGPIPE, SIG_IGN) != SIG_ERR); + + //set customize log/monitor + //phxrpc::setlog(openlog, closelog, vlog); + //phxrpc::MonitorFactory::SetFactory(new YourSelfsMonitorFactory()); + + if (nullptr == config_file) ShowUsage(argv[0]); + + $ServerConfigClass$ config; + if (!config.Read(config_file)) ShowUsage(argv[0]); + + if (log_level > 0) config.GetHshaServerConfig().SetLogLevel(log_level); + + phxrpc::openlog(argv[0], config.GetHshaServerConfig().GetLogDir(), + config.GetHshaServerConfig().GetLogLevel()); + + ServiceArgs_t service_args; + service_args.config = &config; + + phxrpc::Server server(config.GetHshaServerConfig(), Dispatch, &service_args); + server.RunForever(); + + phxrpc::closelog(); - exit( 0 ); + return 0; } -void LogImpl(int priority, const char * format, va_list args) { - //or implement your logmode here +)"; + +////////////////////////////////////////////////////////////////////// + +const char *PHXRPC_EPOLL_UTHREAD_SERVER_MAIN_TEMPLATE = + R"( + +#include +#include +#include +#include + +#include "$DispatcherFile$.h" +#include "$ServiceImplFile$.h" +#include "$ServerConfigFile$.h" + +#include "phxrpc/file.h" +#include "phxrpc/msg.h" +#include "phxrpc/rpc.h" + + +using namespace std; + + +void Dispatch(const phxrpc::BaseRequest *request, + phxrpc::BaseResponse *response, + phxrpc::DispatcherArgs_t *args) { + ServiceArgs_t *service_args{(ServiceArgs_t *)(args->service_args)}; + + $ServiceImplClass$ service(*service_args, args->server_worker_uthread_scheduler, + args->pool_idx, args->worker_idx, + args->notifier_pool, args->notifier_pool_router, + args->cross_unit_data_flow, + (phxrpc::ServiceContext *)(args->context)); + $DispatcherClass$ dispatcher(service, args); + + phxrpc::BaseDispatcher<$DispatcherClass$> base_dispatcher( + dispatcher, $DispatcherClass$::GetURIFuncMap()); + if (!base_dispatcher.Dispatch(request, response)) { + response->DispatchErr(); + } } -int main( int argc, char * argv[] ) { - const char * config_file = NULL; - extern char *optarg ; - int c ; - while( ( c = getopt( argc, argv, "c:v" ) ) != EOF ) { - switch ( c ) { - case 'c' : config_file = optarg; break; +void ShowUsage(const char *program) { + printf("\n"); + printf("Usage: %s [-c ] [-d] [-l ] [-v]\n", program); + printf("\n"); - case 'v' : - default: showUsage( argv[ 0 ] ); break; + exit(0); +} + +int main(int argc, char **argv) { + const char *config_file{nullptr}; + bool daemonize{false}; + int log_level{-1}; + extern char *optarg; + int c; + while (EOF != (c = getopt( argc, argv, "c:vl:d"))) { + switch (c) { + case 'c': config_file = optarg; break; + case 'd': daemonize = true; break; + case 'l': log_level = atoi(optarg); break; + + case 'v': + default: ShowUsage(argv[0]); break; } } + if (daemonize) phxrpc::ServerUtils::Daemonize(); + assert(signal(SIGPIPE, SIG_IGN) != SIG_ERR); - //set your logfunc - //phxrpc::setvlog(LogImpl); - //phxrpc::MonitorFactory::SetFactory( new YourSelfsMonitorFactory() ); + //set customize log/monitor + //phxrpc::setlog(openlog, closelog, vlog); + //phxrpc::MonitorFactory::SetFactory(new YourSelfsMonitorFactory()); + + if (nullptr == config_file) ShowUsage(argv[0]); - if( NULL == config_file ) showUsage( argv[0] ); $ServerConfigClass$ config; - if( ! config.Read( config_file ) ) showUsage( argv[0] ); + if (!config.Read(config_file)) ShowUsage(argv[0]); + + if (log_level > 0) config.GetHshaServerConfig().SetLogLevel(log_level); + + phxrpc::openlog(argv[0], config.GetHshaServerConfig().GetLogDir(), + config.GetHshaServerConfig().GetLogLevel()); ServiceArgs_t service_args; service_args.config = &config; - phxrpc::HshaServer server( config.GetHshaServerConfig(), HttpDispatch, &service_args ); + phxrpc::Server server(config.GetHshaServerConfig(), Dispatch, &service_args); server.RunForever(); + + phxrpc::closelog(); + return 0; } @@ -98,23 +211,23 @@ int main( int argc, char * argv[] ) { ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_EPOLL_SERVER_CONFIG_HPP_TEMPLATE = +const char *PHXRPC_EPOLL_SERVER_CONFIG_HPP_TEMPLATE = R"( #include "phxrpc/rpc.h" -class $ServerConfigClass$ -{ -public: + +class $ServerConfigClass$ { + public: $ServerConfigClass$(); - ~$ServerConfigClass$(); + virtual ~$ServerConfigClass$(); - bool Read( const char * config_file ); + bool Read(const char *config_file); - const phxrpc::HshaServerConfig & GetHshaServerConfig(); + phxrpc::HshaServerConfig &GetHshaServerConfig(); -private: + private: phxrpc::HshaServerConfig ep_server_config_; }; @@ -122,33 +235,31 @@ class $ServerConfigClass$ ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_EPOLL_SERVER_CONFIG_CPP_TEMPLATE = +const char *PHXRPC_EPOLL_SERVER_CONFIG_CPP_TEMPLATE = R"( -#include "$MessageFile$.h" #include "$ServerConfigFile$.h" -$ServerConfigClass$ :: $ServerConfigClass$() -{ +#include "$MessageFile$.h" + + +$ServerConfigClass$::$ServerConfigClass$() { } -$ServerConfigClass$ :: ~$ServerConfigClass$() -{ +$ServerConfigClass$::~$ServerConfigClass$() { } -bool $ServerConfigClass$ :: Read( const char * config_file ) -{ - bool ret = ep_server_config_.Read( config_file ); +bool $ServerConfigClass$::Read(const char *config_file) { + bool ret{ep_server_config_.Read(config_file)}; - if ( strlen( ep_server_config_.GetPackageName() ) == 0 ) { - ep_server_config_.SetPackageName( $PackageName$ ); + if (0 == strlen(ep_server_config_.GetPackageName())) { + ep_server_config_.SetPackageName($PackageNameExpression$); } return ret; } -const phxrpc::HshaServerConfig & $ServerConfigClass$ :: GetHshaServerConfig() -{ +phxrpc::HshaServerConfig &$ServerConfigClass$::GetHshaServerConfig() { return ep_server_config_; } @@ -156,46 +267,166 @@ const phxrpc::HshaServerConfig & $ServerConfigClass$ :: GetHshaServerConfig() ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_EPOLL_SERVER_ETC_TEMPLATE = +const char *PHXRPC_EPOLL_SERVER_ETC_TEMPLATE = R"( [Server] BindIP = 127.0.0.1 -Port = 16161 +Port = 80 +MqttPort = 1883 MaxThreads = 16 IOThreadCount = 3 -PackageName = $PackageName$ +PackageName = $PbPackageName$ MaxConnections = 800000 MaxQueueLength = 20480 FastRejectThresholdMS = 20 +FastRejectAdjustRate = 5 + +[Log] +LogDir = ~/log +LogLevel = 3 [ServerTimeout] -SocketTimeoutMS = 5000 +SocketTimeoutMS = 30000 )"; ////////////////////////////////////////////////////////////////////// -const char * PHXRPC_SERVER_MAKEFILE_TEMPLATE = +const char *PHXRPC_EPOLL_UTHREAD_SERVER_ETC_TEMPLATE = + R"( + +[Server] +BindIP = 127.0.0.1 +Port = 80 +MqttPort = 1883 +MaxThreads = 16 +WorkerUThreadCount = 50 +WorkerUThreadStackSize = 65536 +IOThreadCount = 3 +PackageName = $PbPackageName$ +MaxConnections = 800000 +MaxQueueLength = 20480 +FastRejectThresholdMS = 20 +FastRejectAdjustRate = 5 + +[Log] +LogDir = ~/log +LogLevel = 3 + +[ServerTimeout] +SocketTimeoutMS = 30000 + +)"; + +////////////////////////////////////////////////////////////////////// + +const char *PHXRPC_SERVER_MAKEFILE_TEMPLATE = + R"( + +include $PhxRPCMKDir$/phxrpc.mk + +LDFLAGS := -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) + +# choose to use boost for network +#LDFLAGS := $(PLUGIN_BOOST_LDFLAGS) $(LDFLAGS) + +SVR_OBJS = $MessageFile$.o \ + $ServiceImplFile$.o \ + $ServiceFile$.o \ + $DispatcherFile$.o \ + $ServerConfigFile$.o \ + $ServerMainFile$.o + +CLI_OBJS = $MessageFile$.o \ + $ClientFile$.o \ + $StubFile$.o + +TARGETS = lib$ClientFile$.a $ServerMainFile$ $ToolMainFile$ + +all: $(TARGETS) + +$ServerMainFile$: $(SVR_OBJS) + $(LINKER) $^ $(LDFLAGS) -o $@ + +lib$ClientFile$.a: $(CLI_OBJS) + $(AR) $@ $^ + +$ToolMainFile$: $ToolFile$.o $ToolImplFile$.o $ToolMainFile$.o + $(LINKER) $^ -L. -l$ClientFile$ $(LDFLAGS) -o $@ + +########## message ########## + +$MessageFile$.cc: $MessageFile$.h + +$MessageFile$.h: $ProtoFile$ + $(PROTOBUF_ROOT)/bin/protoc -I$(PROTOBUF_ROOT)/include --cpp_out=. -I$(PHXRPC_ROOT) -I. $^ + +########## client ########## + +$StubFile$.cpp: $StubFile$.h +$StubFile$.o: $StubFile$.h +$ClientFile$.cpp: $StubFile$.h +$ClientFile$.o: $StubFile$.h + +$StubFile$.h: $ProtoFile$ + $(PHXRPC_ROOT)/codegen/phxrpc_pb2client $(PBFLAGS) -f $^ -d . -p mqtt + +########## service ########## + +$ServiceFile$.cpp: $ServiceFile$.h +$ServiceFile$.o: $ServiceFile$.h +$ServiceImplFile$.cpp: $ServiceFile$.h +$ServiceImplFile$.o: $ServiceFile$.h +$DispatcherFile$.cpp: $ServiceFile$.h +$DispatcherFile$.o: $ServiceFile$.h + +$ServiceFile$.h: $ProtoFile$ + $(PHXRPC_ROOT)/codegen/phxrpc_pb2service $(PBFLAGS) -f $^ -d . -p mqtt + +########## tool ########## + +$ToolFile$.cpp: $ToolFile$.h +$ToolFile$.o: $ToolFile$.h +$ToolImplFile$.cpp: $ToolFile$.h +$ToolImplFile$.o: $ToolFile$.h +$ToolMainFile$.cpp: $ToolFile$.h +$ToolMainFile$.o: $ToolFile$.h + +$ToolFile$.h: $ProtoFile$ + $(PHXRPC_ROOT)/codegen/phxrpc_pb2tool $(PBFLAGS) -f $^ -d . -p mqtt + +clean: + @($(RM) $(TARGETS)) + @($(RM) *.o) + @($(RM) phxrpc_*) + @($(RM) *.pb.*) + +)"; + +///////////////////////////////////////////////////////////////////// + +const char *PHXRPC_UTHREAD_SERVER_MAKEFILE_TEMPLATE = R"( include $PhxRPCMKDir$/phxrpc.mk LDFLAGS := -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -#choose to use boost for network +# choose to use boost for network #LDFLAGS := $(PLUGIN_BOOST_LDFLAGS) $(LDFLAGS) SVR_OBJS = $MessageFile$.o \ - $ServiceImplFile$.o \ - $ServiceFile$.o \ - $DispatcherFile$.o \ - $ServerConfigFile$.o \ - $ServerMainFile$.o + $ServiceImplFile$.o \ + $ServiceFile$.o \ + $DispatcherFile$.o \ + $ServerConfigFile$.o \ + $ServerMainFile$.o CLI_OBJS = $MessageFile$.o \ - $ClientFile$.o \ - $StubFile$.o + $ClientFile$.o \ + $ClientFile$_uthread.o \ + $StubFile$.o TARGETS = lib$ClientFile$.a $ServerMainFile$ $ToolMainFile$ @@ -215,7 +446,7 @@ lib$ClientFile$.a: $(CLI_OBJS) $MessageFile$.cc: $MessageFile$.h $MessageFile$.h: $ProtoFile$ - $(PROTOBUF_ROOT)/src/protoc -I$(PROTOBUF_ROOT)/src --cpp_out=. -I$(PHXRPC_ROOT) -I. $^ + $(PROTOBUF_ROOT)/bin/protoc -I$(PROTOBUF_ROOT)/include --cpp_out=. -I$(PHXRPC_ROOT) -I. $^ ########## client ########## @@ -223,9 +454,11 @@ lib$ClientFile$.a: $(CLI_OBJS) $StubFile$.o: $StubFile$.h $ClientFile$.cpp: $StubFile$.h $ClientFile$.o: $StubFile$.h +$ClientFile$_uthread.cpp: $StubFile$.h +$ClientFile$_uthread.o: $StubFile$.h $StubFile$.h: $ProtoFile$ - $(PHXRPC_ROOT)/codegen/phxrpc_pb2client $(PBFLAGS) -f $^ -d . + $(PHXRPC_ROOT)/codegen/phxrpc_pb2client $(PBFLAGS) -f $^ -d . -u -p mqtt ########## service ########## @@ -237,7 +470,7 @@ lib$ClientFile$.a: $(CLI_OBJS) $DispatcherFile$.o: $ServiceFile$.h $ServiceFile$.h: $ProtoFile$ - $(PHXRPC_ROOT)/codegen/phxrpc_pb2service $(PBFLAGS) -f $^ -d . + $(PHXRPC_ROOT)/codegen/phxrpc_pb2service $(PBFLAGS) -f $^ -d . -u -p mqtt ########## tool ########## @@ -249,12 +482,13 @@ lib$ClientFile$.a: $(CLI_OBJS) $ToolMainFile$.o: $ToolFile$.h $ToolFile$.h: $ProtoFile$ - $(PHXRPC_ROOT)/codegen/phxrpc_pb2tool $(PBFLAGS) -f $^ -d . + $(PHXRPC_ROOT)/codegen/phxrpc_pb2tool $(PBFLAGS) -f $^ -d . -p mqtt clean: @($(RM) $(TARGETS)) @($(RM) *.o) @($(RM) phxrpc_*) + @($(RM) *.pb.*) )"; diff --git a/codegen/server_template.h b/codegen/server_template.h index e5a896d..bafd54c 100644 --- a/codegen/server_template.h +++ b/codegen/server_template.h @@ -21,14 +21,16 @@ See the AUTHORS file for names of contributors. #pragma once -extern const char * PHXRPC_SERVER_MAIN_TEMPLATE; extern const char * PHXRPC_EPOLL_SERVER_MAIN_TEMPLATE; -extern const char * PHXRPC_SERVER_CONFIG_HPP_TEMPLATE; +extern const char * PHXRPC_EPOLL_UTHREAD_SERVER_MAIN_TEMPLATE; + extern const char * PHXRPC_EPOLL_SERVER_CONFIG_HPP_TEMPLATE; -extern const char * PHXRPC_SERVER_CONFIG_CPP_TEMPLATE; + extern const char * PHXRPC_EPOLL_SERVER_CONFIG_CPP_TEMPLATE; -extern const char * PHXRPC_SERVER_ETC_TEMPLATE; + extern const char * PHXRPC_EPOLL_SERVER_ETC_TEMPLATE; +extern const char * PHXRPC_EPOLL_UTHREAD_SERVER_ETC_TEMPLATE; extern const char * PHXRPC_SERVER_MAKEFILE_TEMPLATE; +extern const char * PHXRPC_UTHREAD_SERVER_MAKEFILE_TEMPLATE; diff --git a/codegen/service_code_render.cpp b/codegen/service_code_render.cpp index 6af64c2..167632f 100644 --- a/codegen/service_code_render.cpp +++ b/codegen/service_code_render.cpp @@ -1,25 +1,26 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include +#include +#include #include "service_code_render.h" @@ -28,20 +29,25 @@ See the AUTHORS file for names of contributors. #include "code_utils.h" + using namespace phxrpc; +using namespace std; + -ServiceCodeRender::ServiceCodeRender(NameRender & name_render) +ServiceCodeRender::ServiceCodeRender(NameRender &name_render) : name_render_(name_render) { } ServiceCodeRender::~ServiceCodeRender() { } -void ServiceCodeRender::GenerateServiceHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServiceCodeRender::GenerateServiceHpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetServiceFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2service", stree->GetProtoFile(), &buffer); fprintf(write, "/* %s.h\n", filename); @@ -53,28 +59,43 @@ void ServiceCodeRender::GenerateServiceHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); + fprintf(write, "#include \"phxrpc/msg/base_msg.h\"\n"); + + fprintf(write, "\n"); + name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetServiceClasname(stree->GetName(), clasname, sizeof(clasname)); + char service_name[128]{0}; + name_render_.GetServiceClassName(stree->GetName(), service_name, sizeof(service_name)); - fprintf(write, "class %s\n", clasname); - fprintf(write, "{\n"); - fprintf(write, "public:\n"); - fprintf(write, " %s();\n", clasname); - fprintf(write, " virtual ~%s();\n", clasname); + fprintf(write, "class %s {\n", service_name); + fprintf(write, " public:\n"); + fprintf(write, " %s();\n", service_name); + fprintf(write, " virtual ~%s();\n", service_name); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, " // %s protocol\n", kv.first.c_str()); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + string buffer; + GetServiceFuncDeclaration(stree, &func, 1, 0, 1, &buffer); + fprintf(write, " virtual %s;\n", buffer.c_str()); + } + fprintf(write, "\n"); + } + + fprintf(write, " // user custom\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; GetServiceFuncDeclaration(stree, &(*fit), 1, 0, 1, &buffer); fprintf(write, " virtual %s;\n", buffer.c_str()); - fprintf(write, "\n"); } fprintf(write, "};\n"); @@ -82,11 +103,13 @@ void ServiceCodeRender::GenerateServiceHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); } -void ServiceCodeRender::GenerateServiceCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServiceCodeRender::GenerateServiceCpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetServiceFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2service", stree->GetProtoFile(), &buffer); fprintf(write, "/* %s.cpp\n", filename); @@ -95,47 +118,64 @@ void ServiceCodeRender::GenerateServiceCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "\n"); name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); fprintf(write, "#include \"phxrpc/file.h\"\n"); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetServiceClasname(stree->GetName(), clasname, sizeof(clasname)); + char service_name[128]{0}; + name_render_.GetServiceClassName(stree->GetName(), service_name, sizeof(service_name)); - fprintf(write, "%s :: %s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::%s() {\n", service_name, service_name); fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "%s :: ~%s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::~%s() {\n", service_name, service_name); fprintf(write, "}\n"); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, "// %s protocol\n", kv.first.c_str()); + fprintf(write, "\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + string buffer; + GetServiceFuncDeclaration(stree, &func, 0, 0, 0, &buffer); + fprintf(write, "%s {\n", buffer.c_str()); + fprintf(write, " phxrpc::log(LOG_ERR, \"ERROR: %s unimplemented\");\n", func.GetName()); + fprintf(write, " return -1;\n"); + fprintf(write, "}\n"); + fprintf(write, "\n"); + } + } + + fprintf(write, "// user custom\n"); + fprintf(write, "\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; GetServiceFuncDeclaration(stree, &(*fit), 0, 0, 0, &buffer); - fprintf(write, "%s\n", buffer.c_str()); - fprintf(write, "{\n"); - fprintf(write, " phxrpc::log( LOG_ERR, \"ERROR: %s unimplemented\" );\n", fit->GetName()); + fprintf(write, "%s {\n", buffer.c_str()); + fprintf(write, " phxrpc::log(LOG_ERR, \"ERROR: %s unimplemented\");\n", fit->GetName()); fprintf(write, " return -1;\n"); fprintf(write, "}\n"); fprintf(write, "\n"); } - - fprintf(write, "\n"); } -void ServiceCodeRender::GenerateServiceImplHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServiceCodeRender::GenerateServiceImplHpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write, + const bool is_uthread_mode) { + char filename[128]{0}; name_render_.GetServiceImplFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2service", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.h\n", filename); @@ -146,6 +186,10 @@ void ServiceCodeRender::GenerateServiceImplHpp(SyntaxTree * stree, FILE * write) fprintf(write, "#pragma once\n"); fprintf(write, "\n"); + if (is_uthread_mode) { + fprintf(write, "#include \"phxrpc/network.h\"\n"); + fprintf(write, "\n"); + } name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); @@ -153,52 +197,101 @@ void ServiceCodeRender::GenerateServiceImplHpp(SyntaxTree * stree, FILE * write) name_render_.GetServiceFileName(stree->GetName(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }, base_name[128] = { 0 }, config_name[128] = { 0 }; - name_render_.GetServiceClasname(stree->GetName(), base_name, sizeof(base_name)); - name_render_.GetServiceImplClasname(stree->GetName(), clasname, sizeof(clasname)); - name_render_.GetServerConfigClasname(stree->GetName(), config_name, sizeof(config_name)); + char service_impl_name[128]{0}, base_name[128]{0}, config_name[128]{0}; + name_render_.GetServiceClassName(stree->GetName(), base_name, sizeof(base_name)); + name_render_.GetServiceImplClassName(stree->GetName(), service_impl_name, sizeof(service_impl_name)); + name_render_.GetServerConfigClassName(stree->GetName(), config_name, sizeof(config_name)); fprintf(write, "class %s;\n", config_name); fprintf(write, "\n"); - fprintf(write, "typedef struct tagServiceArgs {\n"); - fprintf(write, " %s * config;\n", config_name); - fprintf(write, " //You can add other arguments here and initiate in main().\n"); - fprintf(write, "}ServiceArgs_t;\n"); + fprintf(write, "namespace phxrpc {\n"); + fprintf(write, "\n"); + fprintf(write, "class DataFlow;\n"); + fprintf(write, "class NotifierPoolRouter;\n"); + fprintf(write, "struct ServiceContext;\n"); + fprintf(write, "\n"); + fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "class %s : public %s\n", clasname, base_name); - fprintf(write, "{\n"); - fprintf(write, "public:\n"); - fprintf(write, " %s( ServiceArgs_t * app_args );\n", clasname); - fprintf(write, " virtual ~%s();\n", clasname); + fprintf(write, "typedef struct tagServiceArgs {\n"); + fprintf(write, " %s *config;\n", config_name); + fprintf(write, " // you can add other arguments here and initiate in main().\n"); + fprintf(write, "} ServiceArgs_t;\n"); + fprintf(write, "\n"); + + fprintf(write, "class %s : public %s {\n", service_impl_name, base_name); + fprintf(write, " public:\n"); + if (!is_uthread_mode) { + fprintf(write, " %s(ServiceArgs_t &app_args,\n", service_impl_name); + fprintf(write, " const int pool_idx, const int worker_idx,\n"); + fprintf(write, " phxrpc::UThreadNotifierPool *const notifier_pool,\n"); + fprintf(write, " phxrpc::NotifierPoolRouter *const notifier_pool_router,\n"); + fprintf(write, " phxrpc::DataFlow *const cross_unit_data_flow,\n"); + fprintf(write, " phxrpc::ServiceContext *context);\n"); + } else { + fprintf(write, " %s(ServiceArgs_t &app_args,\n", service_impl_name); + fprintf(write, " phxrpc::UThreadEpollScheduler *worker_uthread_scheduler,\n"); + fprintf(write, " const int pool_idx, const int worker_idx,\n"); + fprintf(write, " phxrpc::UThreadNotifierPool *const notifier_pool,\n"); + fprintf(write, " phxrpc::NotifierPoolRouter *const notifier_pool_router,\n"); + fprintf(write, " phxrpc::DataFlow *const cross_unit_data_flow,\n"); + fprintf(write, " phxrpc::ServiceContext *context);\n"); + } + fprintf(write, " virtual ~%s() override;\n", service_impl_name); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; - GetServiceFuncDeclaration(stree, &(*fit), 1, 1, 1, &buffer); - fprintf(write, " virtual %s;\n", buffer.c_str()); + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, " // %s protocol\n", kv.first.c_str()); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + string buffer; + GetServiceFuncDeclaration(stree, &func, 1, 1, 1, &buffer); + fprintf(write, " virtual %s override;\n", buffer.c_str()); + } fprintf(write, "\n"); } - fprintf(write, "private:\n"); - fprintf(write, " const %s & config_;\n", config_name); + fprintf(write, " // user custom\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; + GetServiceFuncDeclaration(stree, &(*fit), 1, 1, 1, &buffer); + fprintf(write, " virtual %s override;\n", buffer.c_str()); + } + fprintf(write, "\n"); + + fprintf(write, " private:\n"); + fprintf(write, " ServiceArgs_t &args_;\n"); + if (is_uthread_mode) { + fprintf(write, " phxrpc::UThreadEpollScheduler *worker_uthread_scheduler_{nullptr};\n"); + } + fprintf(write, " int pool_idx_{-1};\n"); + fprintf(write, " int worker_idx_{-1};\n"); + fprintf(write, " phxrpc::UThreadNotifierPool *notifier_pool_{nullptr};\n"); + fprintf(write, " phxrpc::NotifierPoolRouter *notifier_pool_router_{nullptr};\n"); + fprintf(write, " phxrpc::DataFlow *data_flow_{nullptr};\n"); + fprintf(write, " phxrpc::DataFlow *cross_unit_data_flow_{nullptr};\n"); + fprintf(write, " phxrpc::ServiceContext *context_{nullptr};\n"); fprintf(write, "};\n"); fprintf(write, "\n"); } -void ServiceCodeRender::GenerateServiceImplCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }, config_file[128] = { 0 }; +void ServiceCodeRender::GenerateServiceImplCpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write, + const bool is_uthread_mode) { + char filename[128]{0}, config_file[128]{0}; name_render_.GetServiceImplFileName(stree->GetName(), filename, sizeof(filename)); name_render_.GetServerConfigFileName(stree->GetName(), config_file, sizeof(config_file)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2service", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.cpp\n", filename); @@ -207,80 +300,129 @@ void ServiceCodeRender::GenerateServiceImplCpp(SyntaxTree * stree, FILE * write) fprintf(write, "\n"); fprintf(write, "#include \"%s.h\"\n", filename); - fprintf(write, "#include \"%s.h\"\n", config_file); + fprintf(write, "\n"); - name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); - fprintf(write, "#include \"%s.h\"\n", filename); fprintf(write, "#include \"phxrpc/file.h\"\n"); - fprintf(write, "\n"); - char clasname[128] = { 0 }, config_name[128] = { 0 }; - name_render_.GetServiceImplClasname(stree->GetName(), clasname, sizeof(clasname)); - name_render_.GetServerConfigClasname(stree->GetName(), config_name, sizeof(config_name)); + fprintf(write, "#include \"%s.h\"\n", config_file); + + name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); + fprintf(write, "#include \"%s.h\"\n", filename); - fprintf(write, "%s :: %s( ServiceArgs_t * app_args )\n", clasname, clasname); - fprintf(write, " : config_( *(app_args->config) )\n"); - fprintf(write, "{\n"); + fprintf(write, "\n\n"); + fprintf(write, "using namespace std;\n"); + fprintf(write, "\n\n"); + + char service_impl_name[128]{0}, config_name[128]{0}; + name_render_.GetServiceImplClassName(stree->GetName(), service_impl_name, sizeof(service_impl_name)); + name_render_.GetServerConfigClassName(stree->GetName(), config_name, sizeof(config_name)); + + if (!is_uthread_mode) { + fprintf(write, "%s::%s(ServiceArgs_t &app_args,\n", service_impl_name, service_impl_name); + fprintf(write, " const int pool_idx, const int worker_idx,\n"); + fprintf(write, " phxrpc::UThreadNotifierPool *const notifier_pool,\n"); + fprintf(write, " phxrpc::NotifierPoolRouter *const notifier_pool_router,\n"); + fprintf(write, " phxrpc::DataFlow *const cross_unit_data_flow,\n"); + fprintf(write, " phxrpc::ServiceContext *context)\n"); + fprintf(write, " : args_(app_args), pool_idx_(pool_idx), worker_idx_(worker_idx),\n"); + fprintf(write, " notifier_pool_(notifier_pool), " + "notifier_pool_router_(notifier_pool_router),\n"); + fprintf(write, " cross_unit_data_flow_(cross_unit_data_flow), context_(context) {\n"); + } else { + fprintf(write, "%s::%s(ServiceArgs_t &app_args,\n", service_impl_name, service_impl_name); + fprintf(write, " phxrpc::UThreadEpollScheduler *const worker_uthread_scheduler,\n"); + fprintf(write, " const int pool_idx, const int worker_idx,\n"); + fprintf(write, " phxrpc::UThreadNotifierPool *const notifier_pool,\n"); + fprintf(write, " phxrpc::NotifierPoolRouter *const notifier_pool_router,\n"); + fprintf(write, " phxrpc::DataFlow *const cross_unit_data_flow,\n"); + fprintf(write, " phxrpc::ServiceContext *context)\n"); + fprintf(write, " : args_(app_args),\n"); + fprintf(write, " worker_uthread_scheduler_(worker_uthread_scheduler),\n"); + fprintf(write, " pool_idx_(pool_idx), worker_idx_(worker_idx),\n"); + fprintf(write, " notifier_pool_(notifier_pool), " + "notifier_pool_router_(notifier_pool_router),\n"); + fprintf(write, " cross_unit_data_flow_(cross_unit_data_flow), context_(context) {\n"); + } fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "%s :: ~%s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::~%s() {\n", service_impl_name, service_impl_name); fprintf(write, "}\n"); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, "// %s protocol\n", kv.first.c_str()); + fprintf(write, "\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + string buffer; + GetServiceFuncDeclaration(stree, &func, 0, 1, 1, &buffer); + fprintf(write, "%s {\n", buffer.c_str()); + fprintf(write, " return -1;\n"); + fprintf(write, "}\n"); + fprintf(write, "\n"); + } + } + + fprintf(write, "// user custom\n"); + fprintf(write, "\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; GetServiceFuncDeclaration(stree, &(*fit), 0, 1, 1, &buffer); - fprintf(write, "%s\n", buffer.c_str()); - fprintf(write, "{\n"); + fprintf(write, "%s {\n", buffer.c_str()); - if (0 == strcmp("PHXEcho", fit->GetName())) { - fprintf(write, " resp->set_value( req.value() );\n"); + if (0 == strcmp("PhxEcho", fit->GetName())) { + fprintf(write, " resp->set_value(req.value());\n"); + fprintf(write, "\n"); fprintf(write, " return 0;\n"); } else { fprintf(write, " return -1;\n"); } + fprintf(write, "}\n"); fprintf(write, "\n"); } - - fprintf(write, "\n"); } -void ServiceCodeRender::GetServiceFuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, int is_impl, - int need_param_name, std::string * result) { - char clasname[128] = { 0 }, type_name[128] = { 0 }; +void ServiceCodeRender::GetServiceFuncDeclaration(SyntaxTree *stree, + const SyntaxFunc *const func, int is_header, int is_impl, + int need_param_name, string *result) { + char service_impl_name[128]{0}, type_name[128]{0}; if (is_impl) { - name_render_.GetServiceImplClasname(stree->GetName(), clasname, sizeof(clasname)); + name_render_.GetServiceImplClassName(stree->GetName(), service_impl_name, sizeof(service_impl_name)); } else { - name_render_.GetServiceClasname(stree->GetName(), clasname, sizeof(clasname)); + name_render_.GetServiceClassName(stree->GetName(), service_impl_name, sizeof(service_impl_name)); } if (is_header) { - StrAppendFormat(result, "int %s( ", func->GetName()); + StrAppendFormat(result, "int %s(", func->GetName()); } else { - StrAppendFormat(result, "int %s :: %s( ", clasname, func->GetName()); + StrAppendFormat(result, "int %s::%s(", service_impl_name, func->GetName()); } - name_render_.GetMessageClasname(func->GetReq()->GetType(), type_name, sizeof(type_name)); - StrAppendFormat(result, "const %s & %s,\n", type_name, need_param_name ? "req" : "/* req */"); + name_render_.GetMessageClassName(func->GetReq()->GetType(), type_name, sizeof(type_name)); + StrAppendFormat(result, "const %s &%s", type_name, need_param_name ? "req" : "/* req */"); - name_render_.GetMessageClasname(func->GetResp()->GetType(), type_name, sizeof(type_name)); - StrAppendFormat(result, " %s * %s", type_name, need_param_name ? "resp" : "/* resp */"); + const char *const resp_type{func->GetResp()->GetType()}; + if (resp_type && 0 < strlen(resp_type)) { + name_render_.GetMessageClassName(func->GetResp()->GetType(), type_name, sizeof(type_name)); + StrAppendFormat(result, ", %s *%s", type_name, need_param_name ? "resp" : "/* resp */"); + } - result->append(" )"); + result->append(")"); } -void ServiceCodeRender::GenerateDispatcherHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServiceCodeRender::GenerateDispatcherHpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetDispatcherFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2service", stree->GetProtoFile(), &buffer); fprintf(write, "/* %s.h\n", filename); @@ -292,56 +434,65 @@ void ServiceCodeRender::GenerateDispatcherHpp(SyntaxTree * stree, FILE * write) fprintf(write, "\n"); - fprintf(write, "#include \"phxrpc/http.h\"\n"); fprintf(write, "#include \"phxrpc/rpc.h\"\n"); - + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }, service_name[128] = { 0 }; - name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); - name_render_.GetServiceClasname(stree->GetName(), service_name, sizeof(service_name)); + char dispatcher_name[128]{0}, service_name[128]{0}; + name_render_.GetDispatcherClassName(stree->GetName(), dispatcher_name, sizeof(dispatcher_name)); + name_render_.GetServiceClassName(stree->GetName(), service_name, sizeof(service_name)); fprintf(write, "class %s;\n", service_name); fprintf(write, "\n"); - fprintf(write, "class %s\n", clasname); - fprintf(write, "{\n"); - fprintf(write, "public:\n"); + fprintf(write, "class %s {\n", dispatcher_name); - fprintf(write, " %s( %s & service, phxrpc::DispatcherArgs_t * dispatcher_args );\n", clasname, service_name); + fprintf(write, " public:\n"); + fprintf(write, " static const phxrpc::BaseDispatcher<%s>::URIFuncMap &GetURIFuncMap();\n", dispatcher_name); fprintf(write, "\n"); - fprintf(write, " ~%s();\n", clasname); + fprintf(write, " %s(%s &service, phxrpc::DispatcherArgs_t *dispatcher_args);\n", dispatcher_name, service_name); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - fprintf(write, " int %s( const phxrpc::HttpRequest & request, " - "phxrpc::HttpResponse * response );\n", - fit->GetName()); + fprintf(write, " virtual ~%s();\n", dispatcher_name); + fprintf(write, "\n"); + + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, " // %s protocol\n", kv.first.c_str()); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + fprintf(write, " int %s(const phxrpc::BaseRequest *const req, " + "phxrpc::BaseResponse *const resp);\n", func.GetName()); + } fprintf(write, "\n"); } - fprintf(write, "private:\n"); - fprintf(write, " %s & service_;\n", service_name); - fprintf(write, " phxrpc::DispatcherArgs_t * dispatcher_args_;\n" ); + fprintf(write, " // user custom\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + fprintf(write, " int %s(const phxrpc::BaseRequest *const req, " + "phxrpc::BaseResponse *const resp);\n", + fit->GetName()); + } fprintf(write, "\n"); - fprintf(write, "public:\n"); - fprintf(write, " static const phxrpc::HttpDispatcher< %s >::URIFuncMap & GetURIFuncMap();\n", clasname); - fprintf(write, "\n"); + fprintf(write, " private:\n"); + fprintf(write, " %s &service_;\n", service_name); + fprintf(write, " phxrpc::DispatcherArgs_t *dispatcher_args_;\n" ); fprintf(write, "};\n"); fprintf(write, "\n"); } -void ServiceCodeRender::GenerateDispatcherCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServiceCodeRender::GenerateDispatcherCpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetDispatcherFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2service", stree->GetProtoFile(), &buffer); fprintf(write, "/* %s.h\n", filename); @@ -352,64 +503,93 @@ void ServiceCodeRender::GenerateDispatcherCpp(SyntaxTree * stree, FILE * write) fprintf(write, "#include \"%s.h\"\n", filename); fprintf(write, "\n"); + fprintf(write, "#include \n"); + fprintf(write, "\n"); + + fprintf(write, "#include \"phxrpc/mqtt.h\"\n"); + fprintf(write, "#include \"phxrpc/http.h\"\n"); + fprintf(write, "#include \"phxrpc/file.h\"\n"); + fprintf(write, "\n"); + name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); name_render_.GetServiceFileName(stree->GetName(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); - fprintf(write, "#include \"phxrpc/http.h\"\n"); - fprintf(write, "#include \"phxrpc/file.h\"\n"); - fprintf(write, "#include \n"); - + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }, service_name[128] = { 0 }; - name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); - name_render_.GetServiceClasname(stree->GetName(), service_name, sizeof(service_name)); - - fprintf(write, "%s :: %s( %s & service, phxrpc::DispatcherArgs_t * dispatcher_args )\n", clasname, clasname, service_name); - fprintf(write, " : service_( service ), dispatcher_args_(dispatcher_args)\n"); + char dispatcher_name[128]{0}, service_name[128]{0}; + name_render_.GetDispatcherClassName(stree->GetName(), dispatcher_name, sizeof(dispatcher_name)); + name_render_.GetServiceClassName(stree->GetName(), service_name, sizeof(service_name)); - fprintf(write, "{\n"); + fprintf(write, "%s::%s(%s &service, phxrpc::DispatcherArgs_t *dispatcher_args)\n", + dispatcher_name, dispatcher_name, service_name); + fprintf(write, " : service_(service), dispatcher_args_(dispatcher_args) {\n"); fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "%s :: ~%s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::~%s() {\n", dispatcher_name, dispatcher_name); fprintf(write, "}\n"); fprintf(write, "\n"); - GenerateURIFuncMap(stree, write); + GenerateURIFuncMap(stree, protocol2syntax_tree_map, write); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - GenerateDispatcherFunc(stree, &(*fit), write); + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, "// %s protocol\n", kv.first.c_str()); + fprintf(write, "\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + if (kv.first == "http") + GenerateDispatcherFunc(stree, &func, write, true); + else + GenerateDispatcherFunc(stree, &func, write, false); + } } + fprintf(write, "// user custom\n"); fprintf(write, "\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + GenerateDispatcherFunc(stree, &(*fit), write, true); + } } -void ServiceCodeRender::GenerateURIFuncMap(SyntaxTree * stree, FILE * write) { - char clasname[128] = { 0 }; - name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); +void ServiceCodeRender::GenerateURIFuncMap(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char dispatcher_name[128]{0}; + name_render_.GetDispatcherClassName(stree->GetName(), dispatcher_name, sizeof(dispatcher_name)); - fprintf(write, "const phxrpc::HttpDispatcher< %s >::URIFuncMap & %s :: GetURIFuncMap()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "const phxrpc::BaseDispatcher<%s>::URIFuncMap &%s::GetURIFuncMap() {\n", + dispatcher_name, dispatcher_name); - fprintf(write, " static phxrpc::HttpDispatcher< %s >::URIFuncMap uri_func_map = {\n", clasname); + fprintf(write, " static phxrpc::BaseDispatcher<%s>::URIFuncMap uri_func_map = {\n", + dispatcher_name); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - if (fit != flist->begin()) { + for (const auto &kv : protocol2syntax_tree_map) { + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + fprintf(write, " {\"/%s/%s\", &%s::%s}", + SyntaxTree::Cpp2UriPackageName(kv.second.GetCppPackageName()).c_str(), + func.GetName(), dispatcher_name, func.GetName()); fprintf(write, ",\n"); } - fprintf(write, " {\"/%s/%s\", &%s::%s}", stree->GetPackageName(), fit->GetName(), clasname, - fit->GetName()); + } + + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + if (fit != flist->cbegin()) { + fprintf(write, ",\n"); + } + fprintf(write, " {\"/%s/%s\", &%s::%s}", + SyntaxTree::Cpp2PbPackageName(stree->GetCppPackageName()).c_str(), + fit->GetName(), dispatcher_name, fit->GetName()); } fprintf(write, "};\n"); @@ -418,66 +598,78 @@ void ServiceCodeRender::GenerateURIFuncMap(SyntaxTree * stree, FILE * write) { fprintf(write, "}\n"); } -void ServiceCodeRender::GenerateDispatcherFunc(SyntaxTree * stree, SyntaxFunc * func, FILE * write) { - char clasname[128] = { 0 }, type_name[128] = { 0 }; +void ServiceCodeRender::GenerateDispatcherFunc(const SyntaxTree *const stree, + const SyntaxFunc *const func, + FILE *write, const bool use_content) { + char dispatcher_name[128]{0}, type_name[128]{0}; - name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); + name_render_.GetDispatcherClassName(stree->GetName(), dispatcher_name, sizeof(dispatcher_name)); - fprintf(write, "int %s :: %s( const phxrpc::HttpRequest & request, " - "phxrpc::HttpResponse * response )\n", - clasname, func->GetName()); + fprintf(write, "int %s::%s(const phxrpc::BaseRequest *const req, " + "phxrpc::BaseResponse *const resp) {\n", + dispatcher_name, func->GetName()); - fprintf(write, "{\n"); - fprintf(write, " dispatcher_args_->server_monitor->SvrCall(%d, \"%s\", 1);\n", func->GetCmdID(), func->GetName() ); + fprintf(write, " dispatcher_args_->server_monitor->SvrCall(%d, \"%s\", 1);\n", + func->GetCmdID(), func->GetName()); fprintf(write, "\n"); - fprintf(write, " int ret = 0;\n"); + fprintf(write, " int ret{0};\n"); fprintf(write, "\n"); - name_render_.GetMessageClasname(func->GetReq()->GetType(), type_name, sizeof(type_name)); - fprintf(write, " %s req;\n", type_name); + name_render_.GetMessageClassName(func->GetReq()->GetType(), type_name, sizeof(type_name)); + fprintf(write, " %s req_pb;\n", type_name); - name_render_.GetMessageClasname(func->GetResp()->GetType(), type_name, sizeof(type_name)); - fprintf(write, " %s resp;\n", type_name); + name_render_.GetMessageClassName(func->GetResp()->GetType(), type_name, sizeof(type_name)); + fprintf(write, " %s resp_pb;\n", type_name); fprintf(write, "\n"); - fprintf(write, " //unpack request\n"); + fprintf(write, " // unpack request\n"); fprintf(write, " {\n"); - fprintf(write, " if( ! req.ParseFromString( request.GetContent() ) )\n"); - fprintf(write, " {\n"); - - fprintf(write, " phxrpc::log( LOG_ERR, \"ERROR: FromBuffer fail size %%zu ip %%s\",\n" - " request.GetContent().size(), request.GetClientIP() );\n"); + if (use_content) { + fprintf(write, " if (!req_pb.ParseFromString(req->GetContent())) {\n"); + fprintf(write, " phxrpc::log(LOG_ERR, \"ERROR: FromBuffer fail size %%zu ip %%s\",\n"); + fprintf(write, " req->GetContent().size(), req->GetClientIP());\n"); + } else { + fprintf(write, " phxrpc::ReturnCode ret_code{req->ToPb(&req_pb)};\n"); + fprintf(write, " if (phxrpc::ReturnCode::OK != ret_code) {\n"); + fprintf(write, " phxrpc::log(LOG_ERR, \"ToPb ip %%s err %%d\", req->GetClientIP(), static_cast(ret_code));\n"); + } - fprintf(write, " return -1 * EINVAL;\n"); + fprintf(write, " return -EINVAL;\n"); fprintf(write, " }\n"); fprintf(write, " }\n"); fprintf(write, "\n"); - fprintf(write, " //logic process\n"); + fprintf(write, " // logic process\n"); fprintf(write, " {\n"); - fprintf(write, " if( 0 == ret ) ret = service_.%s( req, &resp );\n", func->GetName()); + fprintf(write, " if (0 == ret) ret = service_.%s(req_pb, &resp_pb);\n", func->GetName()); fprintf(write, " }\n\n"); - fprintf(write, " //pack response\n"); + fprintf(write, " // pack response\n"); fprintf(write, " {\n"); - fprintf(write, " if( ! resp.SerializeToString( &( response->GetContent() ) ) )\n"); - fprintf(write, " {\n"); - fprintf(write, " phxrpc::log( LOG_ERR, \"ERROR: ToBuffer fail ip %%s\", request.GetClientIP() );\n"); + if (use_content) { + fprintf(write, " if (!resp_pb.SerializeToString(&(resp->GetContent()))) {\n"); + + fprintf(write, " phxrpc::log(LOG_ERR, \"ERROR: ToBuffer fail ip %%s\", req->GetClientIP());\n"); + } else { + fprintf(write, " phxrpc::ReturnCode ret_code{resp->FromPb(resp_pb)};\n"); + fprintf(write, " if (phxrpc::ReturnCode::OK != ret_code) {\n"); + fprintf(write, " phxrpc::log(LOG_ERR, \"FromPb ip %%s err %%d\", req->GetClientIP(), static_cast(ret_code));\n"); + } - fprintf(write, " return -1 * ENOMEM;\n"); + fprintf(write, " return -ENOMEM;\n"); fprintf(write, " }\n"); fprintf(write, " }\n"); fprintf(write, "\n"); - fprintf(write, " phxrpc::log( LOG_DEBUG, \"RETN: %s = %%d\", ret );\n", func->GetName()); + fprintf(write, " phxrpc::log(LOG_DEBUG, \"RETN: %s = %%d\", ret);\n", func->GetName()); fprintf(write, "\n"); fprintf(write, " return ret;\n"); diff --git a/codegen/service_code_render.h b/codegen/service_code_render.h index b7a371b..76015df 100755 --- a/codegen/service_code_render.h +++ b/codegen/service_code_render.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,45 +21,70 @@ See the AUTHORS file for names of contributors. #pragma once -#include +#include #include #include +#include + namespace phxrpc { + class NameRender; class SyntaxTree; class SyntaxFunc; +typedef std::vector SyntaxFuncVector; class ServiceCodeRender { - public: - ServiceCodeRender(NameRender & name_render); + public: + ServiceCodeRender(NameRender &name_render); virtual ~ServiceCodeRender(); - virtual void GenerateServiceHpp(SyntaxTree * stree, FILE * write); + virtual void GenerateServiceHpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - virtual void GenerateServiceCpp(SyntaxTree * stree, FILE * write); + virtual void GenerateServiceCpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - virtual void GenerateServiceImplHpp(SyntaxTree * stree, FILE * write); + virtual void GenerateServiceImplHpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write, const bool is_uthread_mode); - virtual void GenerateServiceImplCpp(SyntaxTree * stree, FILE * write); + virtual void GenerateServiceImplCpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write, const bool is_uthread_mode); - virtual void GenerateDispatcherHpp(SyntaxTree * stree, FILE * write); + virtual void GenerateDispatcherHpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - virtual void GenerateDispatcherCpp(SyntaxTree * stree, FILE * write); + virtual void GenerateDispatcherCpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - protected: + protected: + struct FunctionItem { + std::string uri; + std::string function_name; + }; - virtual void GetServiceFuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, int is_impl, - int need_param_name, std::string * result); + virtual void GetServiceFuncDeclaration(SyntaxTree *stree, + const SyntaxFunc *const func, int is_header, int is_impl, + int need_param_name, std::string *result); - virtual void GenerateDispatcherFunc(SyntaxTree * stree, SyntaxFunc * func, FILE * write); + virtual void GenerateDispatcherFunc(const SyntaxTree *const stree, + const SyntaxFunc *const func, + FILE *write, const bool use_content); - virtual void GenerateURIFuncMap(SyntaxTree * stree, FILE * write); + virtual void GenerateURIFuncMap(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - protected: - NameRender & name_render_; + NameRender &name_render_; }; + } diff --git a/codegen/syntax_tree.cpp b/codegen/syntax_tree.cpp index 1f7fa0e..05e59a4 100644 --- a/codegen/syntax_tree.cpp +++ b/codegen/syntax_tree.cpp @@ -1,32 +1,36 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include +#include +#include +#include +#include +#include "code_utils.h" #include "syntax_tree.h" + using namespace phxrpc; +using namespace std; + SyntaxNode::SyntaxNode() { memset(name_, 0, sizeof(name_)); @@ -35,11 +39,11 @@ SyntaxNode::SyntaxNode() { SyntaxNode::~SyntaxNode() { } -void SyntaxNode::SetName(const char * name) { +void SyntaxNode::SetName(const char *name) { strncpy(name_, name, sizeof(name_) - 1); } -const char * SyntaxNode::GetName() const { +const char *SyntaxNode::GetName() const { return name_; } @@ -52,11 +56,11 @@ SyntaxParam::SyntaxParam() { SyntaxParam::~SyntaxParam() { } -void SyntaxParam::SetType(const char * type) { +void SyntaxParam::SetType(const char *type) { strncpy(type_, type, sizeof(type_) - 1); } -const char * SyntaxParam::GetType() const { +const char *SyntaxParam::GetType() const { return type_; } @@ -71,43 +75,43 @@ SyntaxFunc::SyntaxFunc() { SyntaxFunc::~SyntaxFunc() { } -const SyntaxParam * SyntaxFunc::GetReq() const { +const SyntaxParam *SyntaxFunc::GetReq() const { return &req_; } -const SyntaxParam * SyntaxFunc::GetResp() const { +const SyntaxParam *SyntaxFunc::GetResp() const { return &resp_; } -SyntaxParam * SyntaxFunc::GetReq() { +SyntaxParam *SyntaxFunc::GetReq() { return &req_; } -SyntaxParam * SyntaxFunc::GetResp() { +SyntaxParam *SyntaxFunc::GetResp() { return &resp_; } -void SyntaxFunc::SetOptString(const char * opt_string) { +void SyntaxFunc::SetOptString(const char *opt_string) { strncpy(opt_string_, opt_string, sizeof(opt_string_)); } -const char * SyntaxFunc::GetOptString() const { +const char *SyntaxFunc::GetOptString() const { return opt_string_; } -void SyntaxFunc::SetUsage(const char * usage) { +void SyntaxFunc::SetUsage(const char *usage) { strncpy(usage_, usage, sizeof(usage_)); } -const char * SyntaxFunc::GetUsage() const { +const char *SyntaxFunc::GetUsage() const { return usage_; } -void SyntaxFunc::SetCmdID(int32_t cmdid) { +void SyntaxFunc::SetCmdID(const int cmdid) { cmdid_ = cmdid; } -int32_t SyntaxFunc::GetCmdID() { +int SyntaxFunc::GetCmdID() const { return cmdid_; } @@ -116,52 +120,49 @@ int32_t SyntaxFunc::GetCmdID() { SyntaxTree::SyntaxTree() { memset(prefix_, 0, sizeof(prefix_)); memset(proto_file_, 0, sizeof(proto_file_)); - memset(package_name_, 0, sizeof(package_name_)); + memset(cpp_package_name_, 0, sizeof(cpp_package_name_)); } SyntaxTree::~SyntaxTree() { } -void SyntaxTree::Print() { -} - -void SyntaxTree::SetProtoFile(const char * proto_file) { +void SyntaxTree::SetProtoFile(const char *proto_file) { strncpy(proto_file_, proto_file, sizeof(proto_file_) - 1); } -const char * SyntaxTree::GetProtoFile() const { +const char *SyntaxTree::GetProtoFile() const { return proto_file_; } -const char * SyntaxTree::GetPackageName() const { - return package_name_; +const char *SyntaxTree::GetCppPackageName() const { + return cpp_package_name_; } -void SyntaxTree::SetPackageName(const char * package_name) { - strncpy(package_name_, package_name, sizeof(package_name_) - 1); +void SyntaxTree::SetCppPackageName(const char *cpp_package_name) { + strncpy(cpp_package_name_, cpp_package_name, sizeof(cpp_package_name_) - 1); } -void SyntaxTree::SetPrefix(const char * prefix) { +void SyntaxTree::SetPrefix(const char *prefix) { strncpy(prefix_, prefix, sizeof(prefix_) - 1); ToUpper(prefix_); } -const char * SyntaxTree::GetPrefix() const { +const char *SyntaxTree::GetPrefix() const { return prefix_; } -const SyntaxFuncVector * SyntaxTree::GetFuncList() const { +const SyntaxFuncVector *SyntaxTree::GetFuncList() const { return &func_list_; } -SyntaxFuncVector * SyntaxTree::GetFuncList() { +SyntaxFuncVector *SyntaxTree::GetFuncList() { return &func_list_; } -SyntaxFunc * SyntaxTree::FindFunc(const char * name) { - SyntaxFunc * ret = NULL; +SyntaxFunc *SyntaxTree::FindFunc(const char *name) { + SyntaxFunc *ret{nullptr}; - for (SyntaxFuncVector::iterator iter = func_list_.begin(); func_list_.end() != iter; ++iter) { + for (SyntaxFuncVector::iterator iter(func_list_.begin()); func_list_.end() != iter; ++iter) { if (0 == strcasecmp(name, iter->GetName())) { ret = &(*iter); break; @@ -171,8 +172,11 @@ SyntaxFunc * SyntaxTree::FindFunc(const char * name) { return ret; } -char * SyntaxTree::ToLower(register char *s) { - register char *ret = s; +void SyntaxTree::Print() { +} + +char *SyntaxTree::ToLower(char *s) { + char *ret = s; for (; *s != '\0'; ++s) *s = tolower(*s); @@ -180,8 +184,8 @@ char * SyntaxTree::ToLower(register char *s) { return ret; } -char * SyntaxTree::ToUpper(register char *s) { - register char * ret = s; +char *SyntaxTree::ToUpper(char *s) { + char *ret = s; for (; *s != '\0'; s++) *s = toupper(*s); @@ -189,3 +193,27 @@ char * SyntaxTree::ToUpper(register char *s) { return ret; } +string SyntaxTree::Cpp2PbPackageName(const string &cpp_package_name) { + string pb_package_name(cpp_package_name); + StrReplaceAll(&pb_package_name, "::", "."); + return pb_package_name; +} + +string SyntaxTree::Pb2CppPackageName(const string &pb_package_name) { + string cpp_package_name(pb_package_name); + StrReplaceAll(&cpp_package_name, ".", "::"); + return cpp_package_name; +} + +string SyntaxTree::Cpp2UriPackageName(const std::string &cpp_package_name) { + string uri_package_name(cpp_package_name); + StrReplaceAll(&uri_package_name, "::", "/"); + return uri_package_name; +} + +string SyntaxTree::Uri2CppPackageName(const std::string &uri_package_name) { + string cpp_package_name(uri_package_name); + StrReplaceAll(&cpp_package_name, "/", "::"); + return cpp_package_name; +} + diff --git a/codegen/syntax_tree.h b/codegen/syntax_tree.h index 0d2edbe..aed6223 100644 --- a/codegen/syntax_tree.h +++ b/codegen/syntax_tree.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -24,66 +24,69 @@ See the AUTHORS file for names of contributors. #include #include + namespace phxrpc { + enum { _SYNTAX_NAME_LEN = 512, _SYNTAX_DESC_LEN = 512, _SYNTAX_TYPE_LEN = 512 }; + class SyntaxNode { - public: + public: SyntaxNode(); virtual ~SyntaxNode(); - void SetName(const char * name); - const char * GetName() const; + void SetName(const char *name); + const char *GetName() const; - private: + private: char name_[_SYNTAX_NAME_LEN]; }; class SyntaxParam : public SyntaxNode { - public: + public: SyntaxParam(); - ~SyntaxParam(); + virtual ~SyntaxParam() override; - void SetType(const char * type); - const char * GetType() const; + void SetType(const char *type); + const char *GetType() const; - private: + private: char type_[_SYNTAX_TYPE_LEN]; }; class SyntaxFunc : public SyntaxNode { - public: + public: SyntaxFunc(); - ~SyntaxFunc(); + virtual ~SyntaxFunc() override; - const SyntaxParam * GetReq() const; + const SyntaxParam *GetReq() const; - const SyntaxParam * GetResp() const; + const SyntaxParam *GetResp() const; - SyntaxParam * GetReq(); + SyntaxParam *GetReq(); - SyntaxParam * GetResp(); + SyntaxParam *GetResp(); - void SetOptString(const char * opt_string); - const char * GetOptString() const; + void SetOptString(const char *opt_string); + const char *GetOptString() const; - void SetUsage(const char * usage); - const char * GetUsage() const; + void SetUsage(const char *usage); + const char *GetUsage() const; - void SetCmdID(int32_t cmdid ); - int32_t GetCmdID(); + void SetCmdID(const int cmdid); + int GetCmdID() const; - private: + private: SyntaxParam req_; SyntaxParam resp_; char opt_string_[_SYNTAX_DESC_LEN]; char usage_[_SYNTAX_DESC_LEN]; - int32_t cmdid_; + int cmdid_; }; //------------------------------------------------------------ @@ -95,37 +98,43 @@ class SyntaxTree; typedef std::vector SyntaxTreeVector; class SyntaxTree : public SyntaxNode { - public: + public: SyntaxTree(); - ~SyntaxTree(); + virtual ~SyntaxTree() override; - void SetProtoFile(const char * proto_file); - const char * GetProtoFile() const; + void SetProtoFile(const char *proto_file); + const char *GetProtoFile() const; - void SetPrefix(const char * prefix); - const char * GetPrefix() const; + void SetPrefix(const char *prefix); + const char *GetPrefix() const; - void SetPackageName(const char * sPBPackageName); - const char * GetPackageName() const; + void SetCppPackageName(const char *cpp_package_name); + const char *GetCppPackageName() const; - const SyntaxFuncVector * GetFuncList() const; - SyntaxFuncVector * GetFuncList(); + const SyntaxFuncVector *GetFuncList() const; + SyntaxFuncVector *GetFuncList(); - SyntaxFunc * FindFunc(const char * name); + SyntaxFunc *FindFunc(const char *name); void Print(); - public: - static char * ToLower(register char *s); - static char * ToUpper(register char *s); + static char *ToLower(register char *s); + static char *ToUpper(register char *s); - private: + static std::string Cpp2PbPackageName(const std::string &cpp_package_name); + static std::string Pb2CppPackageName(const std::string &pb_package_name); + + static std::string Cpp2UriPackageName(const std::string &cpp_package_name); + static std::string Uri2CppPackageName(const std::string &url_package_name); + + private: char proto_file_[128]; char prefix_[32]; - char package_name_[128]; + char cpp_package_name_[128]; SyntaxFuncVector func_list_; }; + } diff --git a/codegen/tool_code_render.cpp b/codegen/tool_code_render.cpp index 4d69952..0bfad03 100644 --- a/codegen/tool_code_render.cpp +++ b/codegen/tool_code_render.cpp @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -28,81 +28,107 @@ See the AUTHORS file for names of contributors. #include "name_render.h" #include "code_utils.h" + using namespace phxrpc; +using namespace std; + -ToolCodeRender::ToolCodeRender(NameRender & name_render) +ToolCodeRender::ToolCodeRender(NameRender &name_render) : name_render_(name_render) { } ToolCodeRender::~ToolCodeRender() { } -void ToolCodeRender::GenerateToolHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ToolCodeRender::GenerateToolHpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetToolFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2tool", stree->GetProtoFile(), &buffer); fprintf(write, "/* %s.h\n", filename); fprintf(write, "%s", buffer.c_str()); fprintf(write, "*/\n"); fprintf(write, "\n"); - fprintf(write, "#include \n"); fprintf(write, "#pragma once\n"); - fprintf(write, "\n"); - fprintf(write, "\n"); fprintf(write, "namespace phxrpc {\n"); - fprintf(write, " class OptMap;\n"); + fprintf(write, "\n"); + fprintf(write, "\n"); + fprintf(write, "class OptMap;\n"); + fprintf(write, "\n"); + fprintf(write, "\n"); fprintf(write, "}\n"); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetToolClasname(stree->GetName(), clasname, sizeof(clasname)); + char clasname[128]{0}; + name_render_.GetToolClassName(stree->GetName(), clasname, sizeof(clasname)); - fprintf(write, "class %s\n", clasname); - fprintf(write, "{\n"); - fprintf(write, "public:\n"); + fprintf(write, "class %s {\n", clasname); + fprintf(write, " public:\n"); fprintf(write, " %s();\n", clasname); fprintf(write, " virtual ~%s();\n", clasname); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - fprintf(write, " virtual int %s( phxrpc::OptMap & bigmap );\n", fit->GetName()); + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, " // %s protocol\n", kv.first.c_str()); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + fprintf(write, " virtual int %s(phxrpc::OptMap &bigmap);\n", func.GetName()); + } fprintf(write, "\n"); } - fprintf(write, "public:\n"); - fprintf(write, " typedef int (%s::*ToolFunc_t) ( phxrpc::OptMap & );\n", clasname); + fprintf(write, " // user custom\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + fprintf(write, " virtual int %s(phxrpc::OptMap &bigmap);\n", fit->GetName()); + } + fprintf(write, "\n"); + + fprintf(write, " typedef int (%s::*ToolFunc_t)(phxrpc::OptMap &);\n", clasname); fprintf(write, "\n"); fprintf(write, " typedef struct tagName2Func {\n"); - fprintf(write, " const char * name;\n"); + fprintf(write, " const char *name;\n"); fprintf(write, " %s::ToolFunc_t func;\n", clasname); - fprintf(write, " const char * opt_string;\n"); - fprintf(write, " const char * usage;\n"); + fprintf(write, " const char *opt_string;\n"); + fprintf(write, " const char *usage;\n"); fprintf(write, " } Name2Func_t;\n"); fprintf(write, "\n"); - fprintf(write, " static Name2Func_t * GetName2Func()\n"); - fprintf(write, " {\n"); - fprintf(write, " static Name2Func_t name2func [] = {\n"); + fprintf(write, " static Name2Func_t *GetName2Func() {\n"); + fprintf(write, " static Name2Func_t name2func[]{\n"); { - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - if (strlen(fit->GetOptString()) > 0) { - fprintf(write, " { \"%s\", &%s::%s, \"c:f:v%s\",\n \"%s\" },\n", fit->GetName(), clasname, + for (const auto &kv : protocol2syntax_tree_map) { + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + if (0 < strlen(func.GetOptString())) { + fprintf(write, " {\"%s\", &%s::%s, \"c:f:v%s\",\n \"%s\"},\n", + func.GetName(), clasname, + func.GetName(), func.GetOptString(), func.GetUsage()); + } + } + } + + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + if (0 < strlen(fit->GetOptString())) { + fprintf(write, " {\"%s\", &%s::%s, \"c:f:v%s\",\n \"%s\"},\n", + fit->GetName(), clasname, fit->GetName(), fit->GetOptString(), fit->GetUsage()); } } - fprintf(write, " { NULL, NULL }\n"); + fprintf(write, " {nullptr, nullptr}\n"); } fprintf(write, " };\n"); fprintf(write, "\n"); @@ -114,11 +140,13 @@ void ToolCodeRender::GenerateToolHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); } -void ToolCodeRender::GenerateToolCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ToolCodeRender::GenerateToolCpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetToolFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2tool", stree->GetProtoFile(), &buffer); fprintf(write, "/* %s.cpp\n", filename); @@ -132,44 +160,59 @@ void ToolCodeRender::GenerateToolCpp(SyntaxTree * stree, FILE * write) { name_render_.GetClientFileName(stree->GetName(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "\n"); fprintf(write, "\n"); fprintf(write, "using namespace phxrpc;\n"); fprintf(write, "\n"); + fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetToolClasname(stree->GetName(), clasname, sizeof(clasname)); + char clasname[128]{0}; + name_render_.GetToolClassName(stree->GetName(), clasname, sizeof(clasname)); - fprintf(write, "%s :: %s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::%s() {\n", clasname, clasname); fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "%s :: ~%s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::~%s() {\n", clasname, clasname); fprintf(write, "}\n"); fprintf(write, "\n"); - char client_class[128] = { 0 }; - name_render_.GetClientClasname(stree->GetName(), client_class, sizeof(client_class)); + char client_class[128]{0}; + name_render_.GetClientClassName(stree->GetName(), client_class, sizeof(client_class)); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - fprintf(write, "int %s :: %s( phxrpc::OptMap & /* opt_map */ )\n", clasname, fit->GetName()); - fprintf(write, "{\n"); - fprintf(write, " printf( \"\\n *** %s unimplement ***\\n\" );\n\n", fit->GetName()); + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, "// %s protocol\n", kv.first.c_str()); + fprintf(write, "\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + fprintf(write, "int %s::%s(phxrpc::OptMap &/* opt_map */) {\n", clasname, func.GetName()); + fprintf(write, " printf(\"\\n *** %s unimplement ***\\n\");\n\n", func.GetName()); + fprintf(write, " return -1;\n"); + fprintf(write, "}\n"); + fprintf(write, "\n"); + } + } + + fprintf(write, "// user custom\n"); + fprintf(write, "\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + fprintf(write, "int %s::%s(phxrpc::OptMap &/* opt_map */) {\n", clasname, fit->GetName()); + fprintf(write, " printf(\"\\n *** %s unimplement ***\\n\");\n\n", fit->GetName()); fprintf(write, " return -1;\n"); fprintf(write, "}\n"); fprintf(write, "\n"); } - fprintf(write, "\n"); } -void ToolCodeRender::GenerateToolImplHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ToolCodeRender::GenerateToolImplHpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetToolImplFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2tool", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.h\n", filename); @@ -180,50 +223,61 @@ void ToolCodeRender::GenerateToolImplHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); - fprintf(write, "#include \n"); - - fprintf(write, "\n"); - - char toolfile[128] = { 0 }; + char toolfile[128]{0}; name_render_.GetToolFileName(stree->GetName(), toolfile, sizeof(toolfile)); - fprintf(write, "#include \"%s.h\"", toolfile); - + fprintf(write, "#include \"%s.h\"\n", toolfile); + fprintf(write, "\n"); fprintf(write, "\n"); fprintf(write, "namespace phxrpc {\n"); - fprintf(write, " class OptMap;\n"); + fprintf(write, "\n"); + fprintf(write, "\n"); + fprintf(write, "class OptMap;\n"); + fprintf(write, "\n"); + fprintf(write, "\n"); fprintf(write, "}\n"); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetToolClasname(stree->GetName(), clasname, sizeof(clasname)); + char clasname[128]{0}; + name_render_.GetToolClassName(stree->GetName(), clasname, sizeof(clasname)); - fprintf(write, "class %sImpl : public %s\n", clasname, clasname); - fprintf(write, "{\n"); - fprintf(write, "public:\n"); + fprintf(write, "class %sImpl : public %s {\n", clasname, clasname); + fprintf(write, " public:\n"); fprintf(write, " %sImpl();\n", clasname); - fprintf(write, " virtual ~%sImpl();\n", clasname); + fprintf(write, " virtual ~%sImpl() override;\n", clasname); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - fprintf(write, " virtual int %s( phxrpc::OptMap & opt_map );\n", fit->GetName()); + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, " // %s protocol\n", kv.first.c_str()); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + fprintf(write, " virtual int %s(phxrpc::OptMap &opt_map) override;\n", func.GetName()); + } fprintf(write, "\n"); } + fprintf(write, " // user custom\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + fprintf(write, " virtual int %s(phxrpc::OptMap &opt_map) override;\n", fit->GetName()); + } + fprintf(write, "};\n"); fprintf(write, "\n"); } -void ToolCodeRender::GenerateToolImplCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ToolCodeRender::GenerateToolImplCpp(SyntaxTree *stree, + const map &protocol2syntax_tree_map, + FILE *write) { + char filename[128]{0}; name_render_.GetToolImplFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2tool", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.cpp\n", filename); @@ -232,6 +286,7 @@ void ToolCodeRender::GenerateToolImplCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "\n"); name_render_.GetClientFileName(stree->GetName(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); @@ -239,50 +294,77 @@ void ToolCodeRender::GenerateToolImplCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "#include \"phxrpc/file.h\"\n"); fprintf(write, "\n"); + fprintf(write, "\n"); + fprintf(write, "using namespace phxrpc;\n"); + + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }; - name_render_.GetToolImplClasname(stree->GetName(), clasname, sizeof(clasname)); + char clasname[128]{0}; + name_render_.GetToolImplClassName(stree->GetName(), clasname, sizeof(clasname)); - fprintf(write, "%s:: %s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::%s() {\n", clasname, clasname); fprintf(write, "}\n"); fprintf(write, "\n"); - fprintf(write, "%s:: ~%s()\n", clasname, clasname); - fprintf(write, "{\n"); + fprintf(write, "%s::~%s() {\n", clasname, clasname); fprintf(write, "}\n"); fprintf(write, "\n"); - char client_class[128] = { 0 }, req_class[128] = { 0 }, resp_class[128] = { 0 }; - name_render_.GetClientClasname(stree->GetName(), client_class, sizeof(client_class)); + char client_class[128]{0}, req_class[128]{0}, resp_class[128]{0}; + name_render_.GetClientClassName(stree->GetName(), client_class, sizeof(client_class)); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - name_render_.GetMessageClasname(fit->GetReq()->GetType(), req_class, sizeof(req_class)); - name_render_.GetMessageClasname(fit->GetResp()->GetType(), resp_class, sizeof(resp_class)); + for (const auto &kv : protocol2syntax_tree_map) { + fprintf(write, "// %s protocol\n", kv.first.c_str()); + fprintf(write, "\n"); + const auto &funcs{kv.second.GetFuncList()}; + for (const auto &func : *funcs) { + name_render_.GetMessageClassName(func.GetReq()->GetType(), req_class, sizeof(req_class)); + name_render_.GetMessageClassName(func.GetResp()->GetType(), resp_class, sizeof(resp_class)); + + fprintf(write, "int %s::%s(phxrpc::OptMap &opt_map) {\n", clasname, func.GetName()); + fprintf(write, " %s req;\n", req_class); + fprintf(write, " %s resp;\n", resp_class); + fprintf(write, "\n"); + fprintf(write, " // TODO: fill req from opt_map\n"); + fprintf(write, "\n"); + fprintf(write, " %s client;\n", client_class); + fprintf(write, " int ret{client.%s(req, &resp)};\n", func.GetName()); + fprintf(write, " printf(\"%%s return %%d\\n\", __func__, ret);\n"); + fprintf(write, " printf(\"resp: {\\n%%s}\\n\", resp.DebugString().c_str());\n"); + fprintf(write, "\n"); + fprintf(write, " return ret;\n"); + fprintf(write, "}\n"); + fprintf(write, "\n"); + } + } + + fprintf(write, "// user custom\n"); + fprintf(write, "\n"); + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + name_render_.GetMessageClassName(fit->GetReq()->GetType(), req_class, sizeof(req_class)); + name_render_.GetMessageClassName(fit->GetResp()->GetType(), resp_class, sizeof(resp_class)); - fprintf(write, "int %s :: %s( phxrpc::OptMap & opt_map )\n", clasname, fit->GetName()); - fprintf(write, "{\n"); + fprintf(write, "int %s::%s(phxrpc::OptMap &opt_map) {\n", clasname, fit->GetName()); fprintf(write, " %s req;\n", req_class); fprintf(write, " %s resp;\n", resp_class); fprintf(write, "\n"); - if (0 == strcmp("PHXEcho", fit->GetName())) { - fprintf(write, " if( NULL == opt_map.Get( 's' ) ) return -1;\n\n"); - fprintf(write, " req.set_value( opt_map.Get( 's' ) );\n"); + if (0 == strcmp("PhxEcho", fit->GetName())) { + fprintf(write, " if (nullptr == opt_map.Get('s')) return -1;\n\n"); + fprintf(write, " req.set_value(opt_map.Get('s'));\n"); } else { - fprintf(write, " //TODO: fill req from opt_map\n"); - fprintf(write, "\n"); + fprintf(write, " // TODO: fill req from opt_map\n"); } fprintf(write, "\n"); fprintf(write, " %s client;\n", client_class); - fprintf(write, " int ret = client.%s( req, &resp );\n", fit->GetName()); - fprintf(write, " printf( \"%%s return %%d\\n\", __func__, ret );\n"); - fprintf(write, " printf( \"resp: {\\n%%s}\\n\", resp.DebugString().c_str() );\n"); + fprintf(write, " int ret{client.%s(req, &resp)};\n", fit->GetName()); + fprintf(write, " printf(\"%%s return %%d\\n\", __func__, ret);\n"); + fprintf(write, " printf(\"resp: {\\n%%s}\\n\", resp.DebugString().c_str());\n"); fprintf(write, "\n"); fprintf(write, " return ret;\n"); fprintf(write, "}\n"); @@ -290,11 +372,11 @@ void ToolCodeRender::GenerateToolImplCpp(SyntaxTree * stree, FILE * write) { } } -void ToolCodeRender::GenerateToolMainCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ToolCodeRender::GenerateToolMainCpp(SyntaxTree *stree, FILE *write) { + char filename[128]{0}; name_render_.GetToolMainFileName(stree->GetName(), filename, sizeof(filename)); - std::string buffer; + string buffer; name_render_.GetCopyright("phxrpc_pb2tool", stree->GetProtoFile(), &buffer, false); fprintf(write, "/* %s.cpp\n", filename); @@ -302,18 +384,18 @@ void ToolCodeRender::GenerateToolMainCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "*/\n"); fprintf(write, "\n"); - char tool_class[128] = { 0 }, tool_file[128] = { 0 }; - char tool_impl_class[128] = { 0 }, tool_impl_file[128] = { 0 }; - char client_class[128] = { 0 }, client_file[128] = { 0 }; + char tool_class[128]{0}, tool_file[128]{0}; + char tool_impl_class[128]{0}, tool_impl_file[128]{0}; + char client_class[128]{0}, client_file[128]{0}; - name_render_.GetToolClasname(stree->GetName(), tool_class, sizeof(tool_class)); + name_render_.GetToolClassName(stree->GetName(), tool_class, sizeof(tool_class)); name_render_.GetToolFileName(stree->GetName(), tool_file, sizeof(tool_file)); - name_render_.GetToolImplClasname(stree->GetName(), tool_impl_class, sizeof(tool_impl_class)); + name_render_.GetToolImplClassName(stree->GetName(), tool_impl_class, sizeof(tool_impl_class)); name_render_.GetToolImplFileName(stree->GetName(), tool_impl_file, sizeof(tool_impl_file)); - name_render_.GetClientClasname(stree->GetName(), client_class, sizeof(client_class)); + name_render_.GetClientClassName(stree->GetName(), client_class, sizeof(client_class)); name_render_.GetClientFileName(stree->GetName(), client_file, sizeof(client_file)); - std::string content(PHXRPC_TOOL_MAIN_TEMPLATE); + string content(PHXRPC_TOOL_MAIN_TEMPLATE); StrTrim(&content); StrReplaceAll(&content, "$ClientFile$", client_file); StrReplaceAll(&content, "$ClientClass$", client_class); @@ -325,5 +407,6 @@ void ToolCodeRender::GenerateToolMainCpp(SyntaxTree * stree, FILE * write) { fprintf(write, "%s", content.c_str()); fprintf(write, "\n"); + fprintf(write, "\n"); } diff --git a/codegen/tool_code_render.h b/codegen/tool_code_render.h index 94286ab..15f4d02 100755 --- a/codegen/tool_code_render.h +++ b/codegen/tool_code_render.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,31 +21,46 @@ See the AUTHORS file for names of contributors. #pragma once -#include +#include +#include +#include + namespace phxrpc { + class NameRender; class SyntaxTree; +class SyntaxFunc; +typedef std::vector SyntaxFuncVector; class ToolCodeRender { - public: - ToolCodeRender(NameRender & name_render); - ~ToolCodeRender(); + public: + ToolCodeRender(NameRender &name_render); + virtual ~ToolCodeRender(); - void GenerateToolHpp(SyntaxTree * stree, FILE * write); + void GenerateToolHpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - void GenerateToolCpp(SyntaxTree * stree, FILE * write); + void GenerateToolCpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - void GenerateToolImplHpp(SyntaxTree * stree, FILE * write); + void GenerateToolImplHpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - void GenerateToolImplCpp(SyntaxTree * stree, FILE * write); + void GenerateToolImplCpp(SyntaxTree *stree, + const std::map &protocol2syntax_tree_map, + FILE *write); - void GenerateToolMainCpp(SyntaxTree * stree, FILE * write); + void GenerateToolMainCpp(SyntaxTree *stree, FILE *write); - private: - NameRender & name_render_; + private: + NameRender &name_render_; }; + } diff --git a/codegen/tool_template.cpp b/codegen/tool_template.cpp index 28320d9..9eacfa9 100644 --- a/codegen/tool_template.cpp +++ b/codegen/tool_template.cpp @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -22,10 +22,10 @@ See the AUTHORS file for names of contributors. const char * PHXRPC_TOOL_MAIN_TEMPLATE = R"( -#include +#include +#include +#include #include -#include -#include #include "$ToolFile$.h" #include "$ToolImplFile$.h" @@ -34,72 +34,72 @@ const char * PHXRPC_TOOL_MAIN_TEMPLATE = #include "phxrpc/file.h" + using namespace phxrpc; -void showUsage( const char * program ) -{ - printf( "\nUsage: %s [-c ] [-f ] [-v]\n", program ); - $ToolClass$::Name2Func_t * name2func = $ToolClass$::GetName2Func(); +void ShowUsage(const char *program) { + printf("\nUsage: %s [-c ] [-f ] [-v]\n", program); + + $ToolClass$::Name2Func_t *name2func = $ToolClass$::GetName2Func(); - for( int i = 0; ; i++ ) { - $ToolClass$::Name2Func_t * iter = &( name2func[i] ); + for (int i{0}; ; ++i) { + $ToolClass$::Name2Func_t *iter = &(name2func[i]); - if( NULL == iter->name ) break; + if (nullptr == iter->name) break; - printf( " -f %s %s\n", iter->name, iter->usage ); + printf(" -f %s %s\n", iter->name, iter->usage); } - printf( "\n" ); - exit( 0 ); + printf("\n"); + exit(0); } -int main( int argc, char * argv[] ) -{ - const char * func = NULL; - const char * config = NULL; +int main(int argc, char **argv) { + const char *func{nullptr}; + const char *config{nullptr}; - for( int i = 1; i < argc - 1; i++ ) { - if( 0 == strcmp( argv[i], "-c" ) ) { - config = argv[ ++i ]; + for (int i{1}; argc - 1 > i; ++i) { + if (0 == strcmp(argv[i], "-c")) { + config = argv[++i]; } - if( 0 == strcmp( argv[i], "-f" ) ) { - func = argv[ ++i ]; + if (0 == strcmp(argv[i], "-f")) { + func = argv[++i]; } - if( 0 == strcmp( argv[i], "-v" ) ) { - showUsage( argv[0] ); + if (0 == strcmp(argv[i], "-v")) { + ShowUsage(argv[0]); } } - if( NULL == func ) showUsage( argv[0] ); + if (nullptr == func) ShowUsage(argv[0]); - if( NULL != config ) $ClientClass$::Init( config ); + if (nullptr != config) $ClientClass$::Init(config); - $ToolClass$::Name2Func_t * target = NULL; + $ToolClass$::Name2Func_t *target{nullptr}; - $ToolClass$::Name2Func_t * name2func = $ToolClass$::GetName2Func(); + $ToolClass$::Name2Func_t *name2func{$ToolClass$::GetName2Func()}; - for( int i = 0; i < 100; i++ ) { - $ToolClass$::Name2Func_t * iter = &( name2func[i] ); + for (int i{0}; 100 > i; ++i) { + $ToolClass$::Name2Func_t *iter = &(name2func[i]); - if( NULL == iter->name ) break; + if (nullptr == iter->name) break; - if( 0 == strcasecmp( func, iter->name ) ) { + if (0 == strcasecmp(func, iter->name)) { target = iter; break; } } - if( NULL == target ) showUsage( argv[0] ); + if (nullptr == target) ShowUsage(argv[0]); - OptMap opt_map( target->opt_string ); + OptMap opt_map(target->opt_string); - if( ! opt_map.Parse( argc, argv ) ) showUsage( argv[0] ); + if (!opt_map.Parse(argc, argv)) ShowUsage(argv[0]); $ToolClass$::ToolFunc_t targefunc = target->func; $ToolImplClass$ tool; - if( 0 != ( tool.*targefunc ) ( opt_map ) ) showUsage( argv[0] ); + if (0 != (tool.*targefunc)(opt_map)) ShowUsage(argv[0]); return 0; } diff --git a/phxrpc.mk b/phxrpc.mk index d2486dd..43f3039 100644 --- a/phxrpc.mk +++ b/phxrpc.mk @@ -1,21 +1,24 @@ #-------------------------------------------------------------------- -where-am-i = $(abspath $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))) +#debug = y + +where-am-i = $(abspath $(word $(words $(MAKEFILE_LIST)), $(MAKEFILE_LIST))) #$(warning $(dir $(call where-am-i))) -PHXRPC_ROOT=$(dir $(call where-am-i)) +PHXRPC_ROOT = $(dir $(call where-am-i)) -PROTOBUF_ROOT=$(PHXRPC_ROOT)/third_party/protobuf -BOOST_ROOT=$(PHXRPC_ROOT)/third_party/boost +OS := $(shell uname) -PLUGIN_BOOST_LDFLAGS = -Wl,--whole-archive -L$(PHXRPC_ROOT)/lib/ -lphxrpc_plugin_boost \ - -Wl,--no-whole-archive -L$(BOOST_ROOT)/lib/ -lboost_context +PROTOBUF_ROOT = $(PHXRPC_ROOT)/third_party/protobuf +BOOST_ROOT = $(PHXRPC_ROOT)/third_party/boost +PLUGIN_BOOST_LDFLAGS = -Wl,--whole-archive -L$(PHXRPC_ROOT)/lib/ -lphxrpc_plugin_boost \ + -Wl,--no-whole-archive -L$(BOOST_ROOT)/lib/ -lboost_context #-------------------------------------------------------------------- -ifeq ($(debug),y) +ifeq ($(debug), y) # (1) Debug OPT = -g2 else @@ -31,12 +34,12 @@ LINKER = $(CC) LINT = lint -c RM = /bin/rm -f -CFLAGS = -std=c++11 -Wall -D_REENTRANT -D_GNU_SOURCE -fPIC -m64 $(OPT) \ - -I$(PROTOBUF_ROOT)/include \ - -I$(PHXRPC_ROOT) \ +CFLAGS = -std=c++11 -Wall -D_REENTRANT -D_GNU_SOURCE -D_XOPEN_SOURCE -fPIC -m64 $(OPT) \ + -I$(PROTOBUF_ROOT)/include \ + -I$(PHXRPC_ROOT) \ LDFLAGS = -L$(PROTOBUF_ROOT)/lib/ $(PROTOBUF_ROOT)/lib/libprotobuf.a \ - -lstdc++ -lpthread -lm + -lstdc++ -lpthread -lm PBFLAGS = -I $(PROTOBUF_ROOT)/include -I $(PHXRPC_ROOT) @@ -44,10 +47,11 @@ PBFLAGS = -I $(PROTOBUF_ROOT)/include -I $(PHXRPC_ROOT) # make rule %.o : %.c - $(CC) $(CFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) -c $< -o $@ %.o : %.cc - $(CC) $(CFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) -c $< -o $@ %.o : %.cpp - $(CC) $(CFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) -c $< -o $@ + diff --git a/phxrpc/Makefile b/phxrpc/Makefile index e8e9aa5..79cff6a 100644 --- a/phxrpc/Makefile +++ b/phxrpc/Makefile @@ -1,20 +1,32 @@ - include ../phxrpc.mk -LIB_HTTP_OBJS = http/http_client.o http/http_client.o http/http_msg.o http/http_proto.o +LIB_HTTP_OBJS = http/http_client.o http/http_msg.o http/http_protocol.o + +LIB_MQTT_OBJS = mqtt/mqtt_client.o mqtt/mqtt_msg.o mqtt/mqtt_protocol.o -LIB_NETWORK_OBJS = network/socket_stream_base.o network/uthread_runtime.o network/uthread_epoll.o \ - network/socket_stream_block.o network/socket_stream_uthread.o \ - network/uthread_context_util.o network/uthread_context_base.o \ - network/uthread_context_system.o network/timer.o \ +LIB_NETWORK_OBJS = network/socket_stream_base.o network/uthread_runtime.o \ + network/uthread_epoll.o network/socket_stream_block.o \ + network/socket_stream_uthread.o network/uthread_context_util.o \ + network/uthread_context_base.o network/uthread_context_system.o \ + network/timer.o LIB_FILE_OBJS = file/log_utils.o file/file_utils.o file/opt_map.o file/config.o -LIB_RPC_OBJS = rpc/phxrpc.pb.o rpc/http_caller.o rpc/server_config.o rpc/client_config.o \ - rpc/socket_stream_phxrpc.o rpc/uthread_caller.o rpc/client_monitor.o rpc/server_monitor.o \ - rpc/monitor_factory.o rpc/hsha_server.o \ +LIB_RPC_OBJS = rpc/phxrpc.pb.o rpc/http_caller.o rpc/mqtt_caller.o \ + rpc/server_config.o rpc/client_config.o rpc/socket_stream_phxrpc.o \ + rpc/uthread_caller.o rpc/client_monitor.o rpc/server_monitor.o \ + rpc/monitor_factory.o rpc/server.o rpc/fa_server.o rpc/hsha_server.o rpc/base_server.o rpc/server_base.o + +LIB_MSG_OBJS = msg/base_msg.o msg/base_protocol.o msg/protocol_factory.o -LIB_OBJS = $(LIB_RPC_OBJS) $(LIB_HTTP_OBJS) $(LIB_NETWORK_OBJS) $(LIB_FILE_OBJS) \ + +ifeq ($(OS),Darwin) + CFLAGS += -I$(PHXRPC_ROOT)/plugin_darwin/network + LIB_NETWORK_OBJS += ../plugin_darwin/network/epoll-darwin.o +endif + +LIB_OBJS = $(LIB_RPC_OBJS) $(LIB_MSG_OBJS) $(LIB_HTTP_OBJS) $(LIB_MQTT_OBJS) \ + $(LIB_NETWORK_OBJS) $(LIB_FILE_OBJS) TARGETS = libphxrpc.a @@ -27,9 +39,10 @@ libphxrpc.a: $(LIB_OBJS) rpc/phxrpc.pb.cc: rpc/phxrpc.pb.h rpc/phxrpc.pb.h: rpc/phxrpc.proto - cd ..; $(PROTOBUF_ROOT)/src/protoc -I$(PROTOBUF_ROOT)/src -I. --cpp_out=. phxrpc/$<; + cd ..; $(PROTOBUF_ROOT)/bin/protoc -I$(PROTOBUF_ROOT)/src -I. --cpp_out=. phxrpc/$<; clean: @( $(RM) $(TARGETS) $(TEST_TARGETS) ) @( $(RM) *.o core.* $(LIB_OBJS) ) @( cd rpc; $(RM) *.pb.* ) + diff --git a/phxrpc/file/config.cpp b/phxrpc/file/config.cpp index 12257da..7ef95d4 100644 --- a/phxrpc/file/config.cpp +++ b/phxrpc/file/config.cpp @@ -39,7 +39,14 @@ Config :: ~Config() { } bool Config::InitConfig(const char * path) { - return FileUtils::ReadFile(path, &content_); + bool ret = FileUtils::ReadFile(path, &content_); + if( ret ) content_.insert( 0, "\n" ); + return ret; +} + +void Config::SetContent(const std::string & content) { + content_.clear(); + content_.append( "\n" ).append( content ); } bool Config::ReadItem(const char * section, const char * key, int * value) { @@ -131,5 +138,59 @@ bool Config::ReadItem(const char * section, const char * key, char * value, size return ret; } +int Config::TrimCStr( char * src_str ) +{ + int len = 0; + char *pos = 0; + + len = strlen ( src_str ) ; + while ( len > 0 && isspace( src_str [len - 1] ) ) + len--; + src_str [len] = '\0' ; + for ( pos = src_str; isspace(*pos); pos ++ ) + len--; + if ( pos != src_str ) + memmove ( src_str, pos, len + 1 ) ; + return 0; +} + +bool Config::GetSection(const char * name, + std::vector * section) { + + char tmp_section[ 128 ] = { 0 }; + snprintf(tmp_section, sizeof( tmp_section ), "\n[%s]", name); + + char line[ 1024 ] = { 0 }; + + const char * pos = strstr( content_.c_str(), tmp_section ); + if(!pos) { + return false; + } else { + ++pos; + } + + for( ; NULL != pos; ) + { + pos = strchr( pos, '\n' ); + + if( NULL == pos ) break; + pos++; + + if( '[' == *pos ) break; + + if( ';' == *pos || '#' == *pos ) continue; + + strncpy( line, pos, sizeof( line ) - 1 ); + + char * tmp_pos = strchr( line, '\n' ); + if( NULL != tmp_pos ) *tmp_pos = '\0'; + + TrimCStr( line ); + + if( '\0' != line[0] ) section->push_back( line ); + } + return true; +} + } diff --git a/phxrpc/file/config.h b/phxrpc/file/config.h index ddf04db..9c27c0d 100644 --- a/phxrpc/file/config.h +++ b/phxrpc/file/config.h @@ -22,6 +22,7 @@ See the AUTHORS file for names of contributors. #pragma once #include +#include namespace phxrpc { @@ -31,13 +32,17 @@ class Config { ~Config(); bool InitConfig(const char * path); + void SetContent(const std::string & content); bool ReadItem(const char * section, const char * key, char * value, size_t size, const char * default_value); bool ReadItem(const char * section, const char * key, int * value, const int default_value); bool ReadItem(const char * section, const char * key, char * value, size_t size); bool ReadItem(const char * section, const char * key, int * value); + bool GetSection(const char * name, + std::vector * section); private: + int TrimCStr( char * src_str ); std::string content_; }; diff --git a/phxrpc/file/file_utils.cpp b/phxrpc/file/file_utils.cpp index cbc9c2b..8e251ba 100644 --- a/phxrpc/file/file_utils.cpp +++ b/phxrpc/file/file_utils.cpp @@ -19,45 +19,76 @@ permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include +#include "file_utils.h" + #include -#include -#include -#include +#include #include +#include #include -#include -#include "file_utils.h" +#include +#include +#include + #include "log_utils.h" + namespace phxrpc { -bool FileUtils::ReadFile(const char * path, std::string * content) { + +using namespace std; + + +bool FileUtils::ReadFile(const char *path, string *content) { + char newpath[1024]{0}; + if ('~' == path[0]) { + snprintf(newpath, sizeof(newpath), "%s%s", getenv("HOME"), path + 1); + } else { + snprintf(newpath, sizeof(newpath), "%s", path); + } + bool ret = false; - int fd = ::open(path, O_RDONLY); + int fd = ::open(newpath, O_RDONLY); if (fd >= 0) { struct stat file_stat; if (0 == fstat(fd, &file_stat)) { content->resize(file_stat.st_size); - if (read(fd, (char*) content->data(), file_stat.st_size) == file_stat.st_size) { + if (read(fd, (char *) content->data(), file_stat.st_size) == file_stat.st_size) { ret = true; } else { phxrpc::log(LOG_ERR, "WARN: read( ..., %llu ) fail, errno %d, %s", (unsigned long long) file_stat.st_size, errno, strerror(errno)); } } else { - phxrpc::log(LOG_ERR, "WARN: stat %s fail, errno %d, %s", path, errno, strerror(errno)); + phxrpc::log(LOG_ERR, "WARN: stat %s fail, errno %d, %s", newpath, errno, strerror(errno)); } close(fd); } else { - phxrpc::log(LOG_ERR, "WARN: open %s fail, errno %d, %s", path, errno, strerror(errno)); + phxrpc::log(LOG_ERR, "WARN: open %s fail, errno %d, %s", newpath, errno, strerror(errno)); } return ret; } +void FileUtils::StrSplitList(const string &str, const string &delimiters, + vector &results) { + results.clear(); + auto last(0); + auto found(str.find_first_of(delimiters)); + while (string::npos != found) { + auto r(str.substr(last, found - last)); + last = found + 1; + found = str.find_first_of(delimiters, last); + if (!r.empty()) results.push_back(r); + } + auto r(str.substr(last)); + if (!r.empty()) results.push_back(r); } + + +} + diff --git a/phxrpc/file/file_utils.h b/phxrpc/file/file_utils.h index 97227cd..8f94b0b 100644 --- a/phxrpc/file/file_utils.h +++ b/phxrpc/file/file_utils.h @@ -22,17 +22,24 @@ See the AUTHORS file for names of contributors. #pragma once #include +#include + namespace phxrpc { -class FileUtils { -public: - static bool ReadFile(const char * path, std::string * content); -private: +class FileUtils final { + public: + static bool ReadFile(const char *path, std::string *content); + + static void StrSplitList(const std::string &str, const std::string &delimiters, + std::vector &results); + + private: FileUtils(); ~FileUtils(); }; + } diff --git a/phxrpc/file/log_utils.cpp b/phxrpc/file/log_utils.cpp index 2da5336..9195980 100644 --- a/phxrpc/file/log_utils.cpp +++ b/phxrpc/file/log_utils.cpp @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,23 +21,59 @@ See the AUTHORS file for names of contributors. #include "log_utils.h" -#include +#include +#include + namespace phxrpc { -static vlog_t global_vlog = vsyslog; -void log(int priority, const char * format, ...) { +static openlog_t global_openlog_ = NULL; +static closelog_t global_closelog_ = ::closelog; +static vlog_t global_vlog_ = vsyslog; +static int global_priority_ = LOG_ERR; + +void openlog(const char *argv0, const char *log_dir, int priority) { + + char new_path[ 1024 ] = { 0 }; + if( '~' == log_dir[0] ) { + snprintf( new_path, sizeof( new_path ), "%s%s", getenv( "HOME" ), log_dir + 1 ); + } else { + snprintf( new_path, sizeof( new_path ), "%s", log_dir ); + } + + global_priority_ = priority; + if( NULL != global_openlog_ ) { + global_openlog_( argv0, new_path, priority ); + } else { + ::openlog( argv0, LOG_CONS | LOG_PID, 0 ); + } +} + +void closelog() { + global_closelog_(); +} + +void log(int priority, const char *format, ...) { + + if( priority > global_priority_ ) return; + va_list args; va_start(args, format); - global_vlog(priority, format, args); + global_vlog_(priority, format, args); va_end(args); } void setvlog(vlog_t vlog) { - global_vlog = vlog; + global_vlog_ = vlog; } +void setlog(openlog_t open_log, closelog_t close_log, vlog_t vlog) { + global_openlog_ = open_log; + global_closelog_ = close_log; + global_vlog_ = vlog; } -; + + +} // namespace phxrpc diff --git a/phxrpc/file/log_utils.h b/phxrpc/file/log_utils.h index d8fa426..2a9ff02 100644 --- a/phxrpc/file/log_utils.h +++ b/phxrpc/file/log_utils.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,16 +21,27 @@ See the AUTHORS file for names of contributors. #pragma once -#include #include +#include + + namespace phxrpc { -extern void log(int priority, const char * format, ...) __attribute__((format(printf, 2, 3))); + +extern void openlog(const char *argv0, const char *log_dir, int priority); +extern void closelog(); + +extern void log(int priority, const char *format, ...) __attribute__((format(printf, 2, 3))); + +typedef void (*openlog_t)(const char *, const char *, int); +typedef void (*closelog_t)(); typedef void (*vlog_t)(int, const char *, va_list); -extern void setvlog(vlog_t vlog); +extern void setvlog(vlog_t); + +extern void setlog(openlog_t, closelog_t, vlog_t); + -} -; +} // namespace phxrpc diff --git a/phxrpc/file/opt_map.cpp b/phxrpc/file/opt_map.cpp index e9b72e7..1618d2f 100644 --- a/phxrpc/file/opt_map.cpp +++ b/phxrpc/file/opt_map.cpp @@ -19,16 +19,18 @@ permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include +#include +#include +#include #include #include "opt_map.h" + namespace phxrpc { -OptMap::OptMap(const char * optstring) { + +OptMap::OptMap(const char *optstring) { opt_string_ = strdup(optstring); } @@ -61,8 +63,8 @@ size_t OptMap::GetNonOptCount() { return non_opt_.size(); } -const char * OptMap::GetNonOpt(size_t index) { - if (index >= 0 && index < non_opt_.size()) { +const char *OptMap::GetNonOpt(size_t index) { + if (index > 0 && index < non_opt_.size()) { return non_opt_[index].c_str(); } @@ -81,7 +83,7 @@ size_t OptMap::Count(char c) const { return (opt_.end() != iter) ? iter->second.size() : 0; } -const char * OptMap::Get(char c, size_t index) const { +const char *OptMap::Get(char c, size_t index) const { const option_map_::const_iterator iter = opt_.find(c); if (opt_.end() != iter) { @@ -95,22 +97,50 @@ const char * OptMap::Get(char c, size_t index) const { } } -bool OptMap::GetInt(char c, int * val, size_t index) const { - const char * tmp = Get(c, index); +bool OptMap::GetInt(char c, int *val, size_t index) const { + return GetInt32(c, val, index); +} + +bool OptMap::GetInt32(char c, int *val, size_t index) const { + const char *tmp = Get(c, index); + + if (tmp) + *val = strtol(tmp, nullptr, 10); + + return nullptr != tmp; +} + +bool OptMap::GetInt64(char c, int64_t *val, size_t index) const { + const char *tmp = Get(c, index); - if (NULL != tmp) - *val = atoi(tmp); + if (tmp) + *val = strtoll(tmp, nullptr, 10); - return NULL != tmp; + return nullptr != tmp; } -bool OptMap::GetUInt(char c, unsigned int * val, size_t index) const { - const char * tmp = Get(c, index); +bool OptMap::GetUInt(char c, uint32_t *val, size_t index) const { + return GetUInt32(c, val, index); +} + +bool OptMap::GetUInt32(char c, uint32_t *val, size_t index) const { + const char *tmp = Get(c, index); + + if (tmp) + *val = strtoul(tmp, nullptr, 10); + + return nullptr != tmp; +} + +bool OptMap::GetUInt64(char c, uint64_t *val, size_t index) const { + const char *tmp = Get(c, index); - if (NULL != tmp) - *val = strtoul(tmp, NULL, 10); + if (tmp) + *val = strtoull(tmp, nullptr, 10); - return NULL != tmp; + return nullptr != tmp; } + } + diff --git a/phxrpc/file/opt_map.h b/phxrpc/file/opt_map.h index 27c0842..49776a5 100644 --- a/phxrpc/file/opt_map.h +++ b/phxrpc/file/opt_map.h @@ -25,11 +25,13 @@ See the AUTHORS file for names of contributors. #include #include + namespace phxrpc { + class OptMap { public: - OptMap(const char * optstring); + OptMap(const char *optstring); virtual ~OptMap(); @@ -39,18 +41,26 @@ class OptMap { size_t Count(char c) const; - const char * Get(char c, size_t index = 0) const; + const char *Get(char c, size_t index = 0) const; + + bool GetInt(char c, int *val, size_t index = 0) const; + + bool GetInt32(char c, int *val, size_t index = 0) const; - bool GetInt(char c, int * val, size_t index = 0) const; + bool GetInt64(char c, int64_t *val, size_t index = 0) const; - bool GetUInt(char c, unsigned int * val, size_t index = 0) const; + bool GetUInt(char c, uint32_t *val, size_t index = 0) const; + + bool GetUInt32(char c, uint32_t *val, size_t index = 0) const; + + bool GetUInt64(char c, uint64_t *val, size_t index = 0) const; size_t GetNonOptCount(); - const char * GetNonOpt(size_t index); + const char *GetNonOpt(size_t index); private: - char * opt_string_; + char *opt_string_; typedef std::map, std::less > option_map_; option_map_ opt_; @@ -58,5 +68,6 @@ class OptMap { std::vector non_opt_; }; + } diff --git a/phxrpc/http.h b/phxrpc/http.h index f775833..46a26d7 100644 --- a/phxrpc/http.h +++ b/phxrpc/http.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -23,5 +23,5 @@ See the AUTHORS file for names of contributors. #include "http/http_client.h" #include "http/http_msg.h" -#include "http/http_proto.h" -#include "http/http_dispatcher.h" +#include "http/http_protocol.h" + diff --git a/phxrpc/http/Makefile b/phxrpc/http/Makefile index a69be84..b892ce2 100644 --- a/phxrpc/http/Makefile +++ b/phxrpc/http/Makefile @@ -1,4 +1,3 @@ - include ../../phxrpc.mk TEST_TARGETS = test_http_client @@ -11,3 +10,4 @@ test_http_client: test_http_client.o clean: @( $(RM) $(TEST_TARGETS) ) @( $(RM) *.o core.* $(LIB_OBJS) ) + diff --git a/phxrpc/http/http.proto b/phxrpc/http/http.proto new file mode 100644 index 0000000..75f6440 --- /dev/null +++ b/phxrpc/http/http.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package phxrpc.http; + +import "google/protobuf/wrappers.proto"; +import "google/protobuf/empty.proto"; + +import "phxrpc/rpc/phxrpc.proto"; + + +service Http { + + rpc PhxEcho(google.protobuf.StringValue) returns (google.protobuf.StringValue) { + option(phxrpc.CmdID) = 2000001; + option(phxrpc.OptString) = "s:"; + option(phxrpc.Usage) = "-s "; + } + + rpc PhxHttpPublish(HttpPublishPb) returns (HttpPubackPb) { + option(phxrpc.CmdID) = 2000031; + option(phxrpc.OptString) = "e:d:q:r:t:p:s:"; + option(phxrpc.Usage) = "-e -d -q -r -t -p -s "; + } + +} + diff --git a/phxrpc/http/http_client.cpp b/phxrpc/http/http_client.cpp index 7cc3ae8..87500db 100644 --- a/phxrpc/http/http_client.cpp +++ b/phxrpc/http/http_client.cpp @@ -1,106 +1,111 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "http_client.h" #include "http_msg.h" -#include "http_proto.h" +#include "http_protocol.h" #include "phxrpc/file/log_utils.h" #include "phxrpc/network/socket_stream_base.h" + namespace phxrpc { -int HttpClient::Get(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp ) { - int socket_ret = HttpProto::SendReqHeader(socket, "GET", req); - if (socket_ret == 0) { - socket_ret = HttpProto::RecvRespStartLine(socket, resp); - if (socket_ret == 0) - socket_ret = HttpProto::RecvHeaders(socket, resp); - if (socket_ret == 0 && SC_NOT_MODIFIED != resp->GetStatusCode()) { - socket_ret = HttpProto::RecvBody(socket, resp); +int HttpClient::Get(BaseTcpStream &socket, const HttpRequest &req, HttpResponse *resp) { + ReturnCode ret{HttpProtocol::SendReqHeader(socket, "GET", req)}; + + if (ReturnCode::OK == ret) { + ret = HttpProtocol::RecvRespStartLine(socket, resp); + if (ReturnCode::OK == ret) + ret = HttpProtocol::RecvHeaders(socket, resp); + if (ReturnCode::OK == ret && SC_NOT_MODIFIED != resp->GetStatusCode()) { + ret = HttpProtocol::RecvBody(socket, resp); } } - return socket_ret; + return static_cast(ret); } -int HttpClient::Post(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp) { +int HttpClient::Post(BaseTcpStream &socket, const HttpRequest &req, HttpResponse *resp) { PostStat stat; - int ret = Post( socket, req, resp, &stat ); - return ret; + int ret{Post(socket, req, resp, &stat)}; + return ret; } -int HttpClient::Post(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp, - PostStat * post_stat ) { - int socket_ret = HttpProto::SendReqHeader(socket, "POST", req); +int HttpClient::Post(BaseTcpStream &socket, const HttpRequest &req, HttpResponse *resp, + PostStat *post_stat) { + ReturnCode ret{HttpProtocol::SendReqHeader(socket, "POST", req)}; - if (socket_ret == 0) { + if (ReturnCode::OK == ret) { socket << req.GetContent(); - socket_ret = socket.flush().good() ? 0 : socket.LastError(); + if(!socket.flush().good()) + ret = static_cast(socket.LastError()); } else { - if (socket_ret != SocketStreamError_Normal_Closed) { + if (ReturnCode::ERROR_SOCKET_STREAM_NORMAL_CLOSED != ret) { post_stat->send_error_ = true; phxrpc::log(LOG_ERR, "ERR: sendReqHeader fail"); } - return socket_ret; + return static_cast(ret); } - if (socket_ret == 0) { - socket_ret = HttpProto::RecvRespStartLine(socket, resp); - if (socket_ret == 0) - socket_ret = HttpProto::RecvHeaders(socket, resp); + if (ReturnCode::OK == ret) { + ret = HttpProtocol::RecvRespStartLine(socket, resp); + if (ReturnCode::OK == ret) + ret = HttpProtocol::RecvHeaders(socket, resp); - if (socket_ret == 0 && SC_NOT_MODIFIED != resp->GetStatusCode()) { - socket_ret = HttpProto::RecvBody(socket, resp); + if (ReturnCode::OK == ret && SC_NOT_MODIFIED != resp->GetStatusCode()) { + ret = HttpProtocol::RecvBody(socket, resp); } - if (socket_ret != 0 && socket_ret != SocketStreamError_Normal_Closed) { + if (ReturnCode::OK != ret && ReturnCode::ERROR_SOCKET_STREAM_NORMAL_CLOSED != ret) { post_stat->recv_error_ = true; } } else { - if (socket_ret != SocketStreamError_Normal_Closed) { + if (ReturnCode::ERROR_SOCKET_STREAM_NORMAL_CLOSED != ret) { post_stat->send_error_ = true; phxrpc::log(LOG_ERR, "ERR: sendReqBody fail"); } } - return socket_ret; + return static_cast(ret); } -int HttpClient::Head(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp) { - int socket_ret = HttpProto::SendReqHeader(socket, "HEAD", req); +int HttpClient::Head(BaseTcpStream & socket, const HttpRequest &req, HttpResponse *resp) { + ReturnCode ret{HttpProtocol::SendReqHeader(socket, "HEAD", req)}; - if (socket_ret == 0) - socket_ret = HttpProto::RecvRespStartLine(socket, resp); + if (ReturnCode::OK == ret) + ret = HttpProtocol::RecvRespStartLine(socket, resp); - if (socket_ret == 0) - socket_ret = HttpProto::RecvHeaders(socket, resp); + if (ReturnCode::OK == ret) + ret = HttpProtocol::RecvHeaders(socket, resp); - return socket_ret; + return static_cast(ret); } -} + +} // namespace phxrpc + diff --git a/phxrpc/http/http_client.h b/phxrpc/http/http_client.h index 26339db..08eb903 100644 --- a/phxrpc/http/http_client.h +++ b/phxrpc/http/http_client.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,46 +21,47 @@ See the AUTHORS file for names of contributors. #pragma once + namespace phxrpc { + class BaseTcpStream; class HttpRequest; class HttpResponse; class ClientMonitor; class HttpClient { - public: - struct PostStat { - bool send_error_; - bool recv_error_; + public: + struct PostStat { + bool send_error_{false}; + bool recv_error_{false}; - PostStat(): send_error_(false), recv_error_(false) { - } + PostStat() = default; - PostStat( bool send_error, bool recv_error ) : - send_error_(send_error), recv_error_(recv_error) { - } - }; + PostStat(bool send_error, bool recv_error) + : send_error_(send_error), recv_error_(recv_error) { + } + }; - public: enum { SC_NOT_MODIFIED = 304 }; // @return true : socket ok, false : socket error - static int Get(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp); + static int Get(BaseTcpStream &socket, const HttpRequest &req, HttpResponse *resp); // @return true : socket ok, false : socket error - static int Post(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp, - PostStat * post_stat ); - static int Post(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp); + static int Post(BaseTcpStream &socket, const HttpRequest &req, HttpResponse *resp, + PostStat *post_stat); + static int Post(BaseTcpStream &socket, const HttpRequest &req, HttpResponse *resp); // @return true : socket ok, false : socket error - static int Head(BaseTcpStream & socket, const HttpRequest & req, HttpResponse * resp); + static int Head(BaseTcpStream &socket, const HttpRequest &req, HttpResponse *resp); - private: + private: HttpClient(); }; -} + +} // namespace phxrpc diff --git a/phxrpc/http/http_dispatcher.h b/phxrpc/http/http_dispatcher.h deleted file mode 100644 index 8698015..0000000 --- a/phxrpc/http/http_dispatcher.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -Tencent is pleased to support the open source community by making -PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. -All rights reserved. - -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may -obtain a copy of the License at - -https://opensource.org/licenses/BSD-3-Clause - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -See the AUTHORS file for names of contributors. -*/ - -#pragma once - -#include -#include - -#include "http_msg.h" - -namespace phxrpc { - -template -class HttpDispatcher { - public: - typedef int (Dispatcher::*URIFunc_t)(const HttpRequest & request, HttpResponse * response); - - typedef std::map URIFuncMap; - - public: - HttpDispatcher(Dispatcher & dispatcher, const URIFuncMap & uri_func_map) - : dispatcher_(dispatcher), - uri_func_map_(uri_func_map) { - } - - ~HttpDispatcher() { - } - - bool Dispatch(const HttpRequest & request, HttpResponse * response) { - int ret = -1; - - typename URIFuncMap::const_iterator iter = uri_func_map_.find(request.GetURI()); - - if (uri_func_map_.end() != iter) { - ret = (dispatcher_.*iter->second)(request, response); - } - - response->AddHeader(HttpMessage::HEADER_X_PHXRPC_RESULT, ret); - - return uri_func_map_.end() != iter;; - } - - private: - Dispatcher & dispatcher_; - const URIFuncMap & uri_func_map_; -}; - -} - diff --git a/phxrpc/http/http_msg.cpp b/phxrpc/http/http_msg.cpp index 7b3be5f..3217f54 100644 --- a/phxrpc/http/http_msg.cpp +++ b/phxrpc/http/http_msg.cpp @@ -1,103 +1,101 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include +#include +#include +#include + +#include "phxrpc/rpc/phxrpc.pb.h" #include "http_msg.h" +#include "http_protocol.h" -namespace phxrpc { -const char * HttpMessage::HEADER_CONTENT_LENGTH = "Content-Length"; -const char * HttpMessage::HEADER_CONTENT_TYPE = "Content-Type"; -const char * HttpMessage::HEADER_CONNECTION = "Connection"; -const char * HttpMessage::HEADER_PROXY_CONNECTION = "Proxy-Connection"; -const char * HttpMessage::HEADER_TRANSFER_ENCODING = "Transfer-Encoding"; -const char * HttpMessage::HEADER_DATE = "Date"; -const char * HttpMessage::HEADER_SERVER = "Server"; +namespace phxrpc { -const char * HttpMessage::HEADER_X_PHXRPC_RESULT = "X-PHXRPC-Result"; -HttpMessage::HttpMessage(int type) - : type_(type) { - snprintf(version_, sizeof(version_), "%s", "HTTP/1.0"); -} +using namespace std; -HttpMessage::~HttpMessage() { -} -int HttpMessage::GetType() const { - return type_; -} +const char *HttpMessage::HEADER_CONTENT_LENGTH = "Content-Length"; +const char *HttpMessage::HEADER_CONTENT_TYPE = "Content-Type"; +const char *HttpMessage::HEADER_CONNECTION = "Connection"; +const char *HttpMessage::HEADER_PROXY_CONNECTION = "Proxy-Connection"; +const char *HttpMessage::HEADER_TRANSFER_ENCODING = "Transfer-Encoding"; +const char *HttpMessage::HEADER_DATE = "Date"; +const char *HttpMessage::HEADER_SERVER = "Server"; -void HttpMessage::SetVersion(const char * version) { - snprintf(version_, sizeof(version_), "%s", version); -} +const char *HttpMessage::HEADER_X_PHXRPC_RESULT = "X-PHXRPC-Result"; -const char * HttpMessage::GetVersion() const { - return version_; +/* +HttpMessage::HttpMessage(int type) + : BaseMessage(type, BaseMessage::Protocol::HTTP) { + SetVersion("HTTP/1.0"); } +*/ -void HttpMessage::AppendContent(const void * content, int length, int max_length) { - if (length <= 0) - length = strlen((char*) content); +ReturnCode HttpMessage::ToPb(google::protobuf::Message *const message) const { + google::protobuf::StringValue string_value; - int total = content_.size() + length; - total = total > max_length ? total : max_length; + string_value.set_value(GetContent()); - content_.reserve(total); + try { + message->CopyFrom(string_value); + } catch (exception) { + return ReturnCode::ERROR; + } - content_.append((char*) content, length); + return ReturnCode::OK; } -void HttpMessage::SetContent(const void * content, int length) { - content_.clear(); - content_.append((char*) content, length); -} +ReturnCode HttpMessage::FromPb(const google::protobuf::Message &message) { + google::protobuf::StringValue string_value; -const std::string & HttpMessage::GetContent() const { - return content_; -} + try { + string_value.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + SetContent(string_value.value().data(), string_value.value().length()); -std::string & HttpMessage::GetContent() { - return content_; + return ReturnCode::OK; } -void HttpMessage::AddHeader(const char * name, const char * value) { +void HttpMessage::AddHeader(const char *name, const char *value) { header_name_list_.push_back(name); header_value_list_.push_back(value); } -void HttpMessage::AddHeader(const char * name, int value) { - char tmp[32] = { 0 }; +void HttpMessage::AddHeader(const char *name, int value) { + char tmp[32]{0}; snprintf(tmp, sizeof(tmp), "%d", value); AddHeader(name, tmp); } -bool HttpMessage::RemoveHeader(const char * name) { - bool ret = false; +bool HttpMessage::RemoveHeader(const char *name) { + bool ret{false}; - for (size_t i = 0; i < header_name_list_.size() && false == ret; i++) { + for (size_t i{0}; header_name_list_.size() > i && false == ret; ++i) { if (0 == strcasecmp(name, header_name_list_[i].c_str())) { header_name_list_.erase(header_name_list_.begin() + i); header_value_list_.erase(header_value_list_.begin() + i); @@ -112,18 +110,18 @@ size_t HttpMessage::GetHeaderCount() const { return header_name_list_.size(); } -const char * HttpMessage::GetHeaderName(size_t index) const { - return index < header_name_list_.size() ? header_name_list_[index].c_str() : NULL; +const char *HttpMessage::GetHeaderName(size_t index) const { + return index < header_name_list_.size() ? header_name_list_[index].c_str() : nullptr; } -const char * HttpMessage::GetHeaderValue(size_t index) const { - return index < header_value_list_.size() ? header_value_list_[index].c_str() : NULL; +const char *HttpMessage::GetHeaderValue(size_t index) const { + return index < header_value_list_.size() ? header_value_list_[index].c_str() : nullptr; } -const char * HttpMessage::GetHeaderValue(const char * name) const { - const char * value = NULL; +const char *HttpMessage::GetHeaderValue(const char *name) const { + const char *value{nullptr}; - for (size_t i = 0; i < header_name_list_.size() && NULL == value; i++) { + for (size_t i{0}; i < header_name_list_.size() && nullptr == value; i++) { if (0 == strcasecmp(name, header_name_list_[i].c_str())) { value = header_value_list_[i].c_str(); } @@ -132,22 +130,13 @@ const char * HttpMessage::GetHeaderValue(const char * name) const { return value; } -int HttpMessage::IsKeepAlive() const { - const char * proxy = GetHeaderValue(HEADER_PROXY_CONNECTION); - const char * local = GetHeaderValue(HEADER_CONNECTION); - if ((NULL != proxy && 0 == strcasecmp(proxy, "Keep-Alive")) - || (NULL != local && 0 == strcasecmp(local, "Keep-Alive"))) { - return 1; - } - - return 0; -} //--------------------------------------------------------- -HttpRequest::HttpRequest() - : HttpMessage(eRequest) { +HttpRequest::HttpRequest() { + set_protocol(Protocol::HTTP_POST); + SetVersion("HTTP/1.0"); memset(method_, 0, sizeof(method_)); memset(client_ip_, 0, sizeof(client_ip_)); } @@ -155,49 +144,29 @@ HttpRequest::HttpRequest() HttpRequest::~HttpRequest() { } -void HttpRequest::SetMethod(const char * method) { - if (method != nullptr) { +void HttpRequest::SetMethod(const char *method) { + if (nullptr != method) { snprintf(method_, sizeof(method_), "%s", method); } } -const char * HttpRequest::GetMethod() const { +const char *HttpRequest::GetMethod() const { return method_; } -int HttpRequest::IsMethod(const char * method) const { +int HttpRequest::IsMethod(const char *method) const { return 0 == strcasecmp(method, method_); } -void HttpRequest::SetURI(const char * uri) { - if (uri != nullptr) { - uri_ = std::string(uri); - } -} - -const char * HttpRequest::GetURI() const { - return uri_.c_str(); -} - -void HttpRequest::SetClientIP(const char * client_ip) { - if (client_ip != nullptr) { - snprintf(client_ip_, sizeof(client_ip_), "%s", client_ip); - } -} - -const char * HttpRequest::GetClientIP() const { - return client_ip_; -} - -void HttpRequest::AddParam(const char * name, const char * value) { +void HttpRequest::AddParam(const char *name, const char *value) { param_name_list_.push_back(name); param_value_list_.push_back(value); } -bool HttpRequest::RemoveParam(const char * name) { - bool ret = false; +bool HttpRequest::RemoveParam(const char *name) { + bool ret{false}; - for (size_t i = 0; i < param_name_list_.size() && false == ret; i++) { + for (size_t i{0}; param_name_list_.size() > i && false == ret; ++i) { if (0 == strcasecmp(name, param_name_list_[i].c_str())) { param_name_list_.erase(param_name_list_.begin() + i); param_value_list_.erase(param_value_list_.begin() + i); @@ -212,18 +181,18 @@ size_t HttpRequest::GetParamCount() const { return param_name_list_.size(); } -const char * HttpRequest::GetParamName(size_t index) const { - return index < param_name_list_.size() ? param_name_list_[index].c_str() : NULL; +const char *HttpRequest::GetParamName(size_t index) const { + return index < param_name_list_.size() ? param_name_list_[index].c_str() : nullptr; } -const char * HttpRequest::GetParamValue(size_t index) const { - return index < param_value_list_.size() ? param_value_list_[index].c_str() : NULL; +const char *HttpRequest::GetParamValue(size_t index) const { + return index < param_value_list_.size() ? param_value_list_[index].c_str() : nullptr; } -const char * HttpRequest::GetParamValue(const char * name) const { - const char * value = NULL; +const char *HttpRequest::GetParamValue(const char *name) const { + const char *value{nullptr}; - for (size_t i = 0; i < param_name_list_.size() && NULL == value; i++) { + for (size_t i{0}; param_name_list_.size() > i && nullptr == value; ++i) { if (0 == strcasecmp(name, param_name_list_[i].c_str())) { value = param_value_list_[i].c_str(); } @@ -232,10 +201,29 @@ const char * HttpRequest::GetParamValue(const char * name) const { return value; } +BaseResponse *HttpRequest::GenResponse() const { + return new HttpResponse; +} + +int HttpRequest::IsKeepAlive() const { + const char *proxy{GetHeaderValue(HEADER_PROXY_CONNECTION)}; + const char *local{GetHeaderValue(HEADER_CONNECTION)}; + + if ((nullptr != proxy && 0 == strcasecmp(proxy, "Keep-Alive")) + || (nullptr != local && 0 == strcasecmp(local, "Keep-Alive"))) { + return 1; + } + + return 0; +} + + + //--------------------------------------------------------- -HttpResponse::HttpResponse() - : HttpMessage(eResponse) { +HttpResponse::HttpResponse() { + set_protocol(Protocol::HTTP_POST); + SetVersion("HTTP/1.0"); status_code_ = 200; snprintf(reason_phrase_, sizeof(reason_phrase_), "%s", "OK"); } @@ -243,6 +231,46 @@ HttpResponse::HttpResponse() HttpResponse::~HttpResponse() { } +void HttpResponse::SetPhxRpcResult(const int result) { + AddHeader(HttpMessage::HEADER_X_PHXRPC_RESULT, result); +} + +void HttpResponse::DispatchErr() { + SetStatusCode(404); + SetReasonPhrase("Not Found"); +} + +ReturnCode HttpResponse::Send(BaseTcpStream &socket) const { + socket << GetVersion() << " " << GetStatusCode() << " " << GetReasonPhrase() << "\r\n"; + + for (size_t i{0}; GetHeaderCount() > i; ++i) { + socket << GetHeaderName(i) << ": " << GetHeaderValue(i) << "\r\n"; + } + + if (GetContent().size() > 0) { + if (nullptr == GetHeaderValue(HttpMessage::HEADER_CONTENT_LENGTH)) { + socket << HttpMessage::HEADER_CONTENT_LENGTH << ": " << GetContent().size() << "\r\n"; + } + } + + socket << "\r\n"; + + if (GetContent().size() > 0) + socket << GetContent(); + + if (socket.flush().good()) { + return ReturnCode::OK; + } else { + return static_cast(socket.LastError()); + } +} + +ReturnCode HttpResponse::ModifyResp(const bool keep_alive, const string &version) { + HttpProtocol::FixRespHeaders(keep_alive, version.c_str(), this); + + return ReturnCode::OK; +} + void HttpResponse::SetStatusCode(int status_code) { status_code_ = status_code; } @@ -251,13 +279,14 @@ int HttpResponse::GetStatusCode() const { return status_code_; } -void HttpResponse::SetReasonPhrase(const char * reason_phrase) { +void HttpResponse::SetReasonPhrase(const char *reason_phrase) { snprintf(reason_phrase_, sizeof(reason_phrase_), "%s", reason_phrase); } -const char * HttpResponse::GetReasonPhrase() const { +const char *HttpResponse::GetReasonPhrase() const { return reason_phrase_; } -} + +} // namespace phxrpc diff --git a/phxrpc/http/http_msg.h b/phxrpc/http/http_msg.h index 2575176..247aed7 100644 --- a/phxrpc/http/http_msg.h +++ b/phxrpc/http/http_msg.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -24,102 +24,95 @@ See the AUTHORS file for names of contributors. #include #include +#include "phxrpc/msg.h" + + namespace phxrpc { -class HttpMessage { - public: - static const char * HEADER_CONTENT_LENGTH; - static const char * HEADER_CONTENT_TYPE; - static const char * HEADER_CONNECTION; - static const char * HEADER_PROXY_CONNECTION; - static const char * HEADER_TRANSFER_ENCODING; - static const char * HEADER_DATE; - static const char * HEADER_SERVER; - - static const char * HEADER_X_PHXRPC_RESULT; - - public: - HttpMessage(int type); - virtual ~HttpMessage(); - - enum { - eRequest, - eResponse - }; - int GetType() const; - - void SetVersion(const char * version); - const char * GetVersion() const; - - void AppendContent(const void * content, int length = 0, int max_length = 0); - void SetContent(const void * content, int length = 0); - const std::string & GetContent() const; - std::string & GetContent(); - - void AddHeader(const char * name, const char * value); - void AddHeader(const char * name, int value); - bool RemoveHeader(const char * name); - size_t GetHeaderCount() const; - const char * GetHeaderName(size_t index) const; - const char * GetHeaderValue(size_t index) const; - const char * GetHeaderValue(const char * name) const; - int IsKeepAlive() const; +class HttpMessage : virtual public BaseMessage { + public: + static const char *HEADER_CONTENT_LENGTH; + static const char *HEADER_CONTENT_TYPE; + static const char *HEADER_CONNECTION; + static const char *HEADER_PROXY_CONNECTION; + static const char *HEADER_TRANSFER_ENCODING; + static const char *HEADER_DATE; + static const char *HEADER_SERVER; + + static const char *HEADER_X_PHXRPC_RESULT; + + HttpMessage() = default; + virtual ~HttpMessage() override = default; - protected: - const int type_; + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; - char version_[16]; - std::string content_; + void AddHeader(const char *name, const char *value); + void AddHeader(const char *name, int value); + bool RemoveHeader(const char *name); + size_t GetHeaderCount() const; + const char *GetHeaderName(size_t index) const; + const char *GetHeaderValue(size_t index) const; + const char *GetHeaderValue(const char *name) const; + protected: std::vector header_name_list_, header_value_list_; }; -class HttpRequest : public HttpMessage { - public: +class HttpRequest : public HttpMessage, public BaseRequest { + public: HttpRequest(); - virtual ~HttpRequest(); + virtual ~HttpRequest() override; - void SetMethod(const char * method); - const char * GetMethod() const; + virtual ReturnCode Send(BaseTcpStream &socket) const override { + return ReturnCode::ERROR_UNIMPLEMENT; + } - int IsMethod(const char * method) const; + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override; - void SetURI(const char * uri); - const char * GetURI() const; + void SetMethod(const char *method); + const char *GetMethod() const; - void SetClientIP(const char * client_ip); - const char * GetClientIP() const; + int IsMethod(const char *method) const; - void AddParam(const char * name, const char * value); - bool RemoveParam(const char * name); + void AddParam(const char *name, const char *value); + bool RemoveParam(const char *name); size_t GetParamCount() const; - const char * GetParamName(size_t index) const; - const char * GetParamValue(size_t index) const; - const char * GetParamValue(const char * name) const; + const char *GetParamName(size_t index) const; + const char *GetParamValue(size_t index) const; + const char *GetParamValue(const char *name) const; - private: - char method_[16], client_ip_[16]; - std::string uri_; + private: + char method_[16]; std::vector param_name_list_, param_value_list_; }; -class HttpResponse : public HttpMessage { - public: +class HttpResponse : public HttpMessage, public BaseResponse { + public: HttpResponse(); - virtual ~HttpResponse(); + virtual ~HttpResponse() override; + + virtual ReturnCode Send(BaseTcpStream &socket) const override; + + virtual void SetPhxRpcResult(const int result) override; + virtual void DispatchErr() override; + + virtual ReturnCode ModifyResp(const bool keep_alive, const std::string &version) override; void SetStatusCode(int status_code); int GetStatusCode() const; - void SetReasonPhrase(const char * reason_phrase); - const char * GetReasonPhrase() const; + void SetReasonPhrase(const char *reason_phrase); + const char *GetReasonPhrase() const; - private: + private: int status_code_; char reason_phrase_[128]; }; -} + +} // namespace phxrpc diff --git a/phxrpc/http/http_proto.h b/phxrpc/http/http_proto.h deleted file mode 100644 index d8df4f5..0000000 --- a/phxrpc/http/http_proto.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -Tencent is pleased to support the open source community by making -PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. -All rights reserved. - -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may -obtain a copy of the License at - -https://opensource.org/licenses/BSD-3-Clause - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -See the AUTHORS file for names of contributors. -*/ - -#pragma once - -namespace phxrpc { - -class BaseTcpStream; - -class HttpMessage; -class HttpRequest; -class HttpResponse; - -class HttpProto { - public: - enum { - MAX_RECV_LEN = 8192 - }; - - static void URLEncode(const char * source, char * dest, size_t length); - - static char * strsep(char ** s, const char * del); - - // @return 0: socket ok, !=0: socket error - static int SendResp(BaseTcpStream & socket, const HttpResponse & resp); - - // @return 0: socket ok, !=0: socket error - static int SendReqHeader(BaseTcpStream & socket, const char * method, const HttpRequest & req); - - public: - - static void FixRespHeaders(const HttpRequest & req, HttpResponse * resp); - - static void FixRespHeaders(bool is_keep_alive, const char * version, HttpResponse * resp); - - // @return 0: socket ok, !=0: socket error - static int RecvReq(BaseTcpStream & socket, HttpRequest * req); - - // @return 0: socket ok, !=0: socket error - static int RecvRespStartLine(BaseTcpStream & socket, HttpResponse * resp); - - // @return 0: socket ok, !=0: socket error - static int RecvReqStartLine(BaseTcpStream & socket, HttpRequest * req); - - // @return 0: socket ok, !=0: socket error - static int RecvHeaders(BaseTcpStream & socket, HttpMessage * msg); - - // @return 0: socket ok, !=0: socket error - static int RecvBody(BaseTcpStream & socket, HttpMessage * msg); - - private: - HttpProto(); -}; - -} - diff --git a/phxrpc/http/http_proto.cpp b/phxrpc/http/http_protocol.cpp similarity index 58% rename from phxrpc/http/http_proto.cpp rename to phxrpc/http/http_protocol.cpp index 6cf7748..e9c07ce 100644 --- a/phxrpc/http/http_proto.cpp +++ b/phxrpc/http/http_protocol.cpp @@ -1,44 +1,49 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#include "http_proto.h" +#include "http_protocol.h" #include "http_msg.h" #include "phxrpc/file/log_utils.h" #include "phxrpc/network/socket_stream_base.h" -namespace phxrpc { -char * HttpProto::strsep(char ** s, const char * del) { +namespace { + + +using namespace std; + + +char *SeparateStr(char **s, const char *del) { char *d, *tok; if (!s || !*s) - return NULL; + return nullptr; tok = *s; d = strstr(tok, del); @@ -46,13 +51,13 @@ char * HttpProto::strsep(char ** s, const char * del) { *s = d + strlen(del); *d = '\0'; } else { - *s = NULL; + *s = nullptr; } return tok; } -void HttpProto::URLEncode(const char * source, char * dest, size_t length) { +void URLEncode(const char *source, char *dest, size_t length) { const char urlencstring[] = "0123456789abcdef"; const char *p = source; @@ -82,66 +87,29 @@ void HttpProto::URLEncode(const char * source, char * dest, size_t length) { *q = 0; } -int HttpProto::SendReqHeader(BaseTcpStream & socket, const char * method, const HttpRequest & req) { - std::string url; - if (req.GetParamCount() > 0) { - url.append(req.GetURI()); - url.append("?"); +} // namespace - char tmp[1024] = { 0 }; - for (size_t i = 0; i < req.GetParamCount(); i++) { - if (i > 0) - url.append("&"); - URLEncode(req.GetParamName(i), tmp, sizeof(tmp) - 1); - url.append(tmp); - url.append("="); - URLEncode(req.GetParamValue(i), tmp, sizeof(tmp) - 1); - url.append(tmp); - } - } - - socket << method << " " << (url.size() > 0 ? url.c_str() : req.GetURI()) << " " << req.GetVersion() << "\r\n"; - - for (size_t i = 0; i < req.GetHeaderCount(); i++) { - const char * name = req.GetHeaderName(i); - const char * val = req.GetHeaderValue(i); - - socket << name << ": " << val << "\r\n"; - } - if (req.GetContent().size() >= 0) { - if (NULL == req.GetHeaderValue(HttpMessage::HEADER_CONTENT_LENGTH)) { - socket << HttpMessage::HEADER_CONTENT_LENGTH << ": " << req.GetContent().size() << "\r\n"; - } - } +namespace phxrpc { - socket << "\r\n"; - if (req.GetContent().size() == 0) { - if (socket.flush().good()) { - return 0; - } else { - return socket.LastError(); - } - } +using namespace std; - return 0; -} -void HttpProto :: FixRespHeaders(bool is_keep_alive, const char * version, HttpResponse * resp) { - char buffer[256] = { 0 }; +void HttpProtocol::FixRespHeaders(bool is_keep_alive, const char *version, HttpResponse *resp) { + char buffer[256]{0}; // check keep alive header if (is_keep_alive) { - if (NULL == resp->GetHeaderValue(HttpMessage::HEADER_CONNECTION)) { + if (nullptr == resp->GetHeaderValue(HttpMessage::HEADER_CONNECTION)) { resp->AddHeader(HttpMessage::HEADER_CONNECTION, "Keep-Alive"); } } // check date header resp->RemoveHeader(HttpMessage::HEADER_DATE); - time_t t_time = time(NULL); + time_t t_time = time(nullptr); struct tm tm_time; gmtime_r(&t_time, &tm_time); strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S %Z", &tm_time); @@ -155,62 +123,74 @@ void HttpProto :: FixRespHeaders(bool is_keep_alive, const char * version, HttpR resp->SetVersion(version); } -void HttpProto::FixRespHeaders(const HttpRequest & req, HttpResponse * resp) { +void HttpProtocol::FixRespHeaders(const HttpRequest &req, HttpResponse *resp) { FixRespHeaders(req.IsKeepAlive(), req.GetVersion(), resp); } -int HttpProto::SendResp(BaseTcpStream & socket, const HttpResponse & resp) { - socket << resp.GetVersion() << " " << resp.GetStatusCode() << " " << resp.GetReasonPhrase() << "\r\n"; +ReturnCode HttpProtocol::SendReqHeader(BaseTcpStream &socket, const char *method, const HttpRequest &req) { + string url; - for (size_t i = 0; i < resp.GetHeaderCount(); i++) { - socket << resp.GetHeaderName(i) << ": " << resp.GetHeaderValue(i) << "\r\n"; - } + if (req.GetParamCount() > 0) { + url.append(req.GetURI()); + url.append("?"); - if (resp.GetContent().size() >= 0) { - if (NULL == resp.GetHeaderValue(HttpMessage::HEADER_CONTENT_LENGTH)) { - socket << HttpMessage::HEADER_CONTENT_LENGTH << ": " << resp.GetContent().size() << "\r\n"; + char tmp[1024]{0}; + for (size_t i = 0; i < req.GetParamCount(); i++) { + if (i > 0) + url.append("&"); + URLEncode(req.GetParamName(i), tmp, sizeof(tmp) - 1); + url.append(tmp); + url.append("="); + URLEncode(req.GetParamValue(i), tmp, sizeof(tmp) - 1); + url.append(tmp); } } - socket << "\r\n"; + socket << method << " " << (url.size() > 0 ? url.c_str() : req.GetURI()) + << " " << req.GetVersion() << "\r\n"; - if (resp.GetContent().size() > 0) - socket << resp.GetContent(); + for (size_t i{0}; req.GetHeaderCount() > i; ++i) { + const char *name{req.GetHeaderName(i)}; + const char *val{req.GetHeaderValue(i)}; - if (socket.flush().good()) { - return 0; - } else { - return socket.LastError(); + socket << name << ": " << val << "\r\n"; } -} -int HttpProto::RecvReq(BaseTcpStream & socket, HttpRequest * req) { - int socket_ret = RecvReqStartLine(socket, req); + if (req.GetContent().size() > 0) { + if (nullptr == req.GetHeaderValue(HttpMessage::HEADER_CONTENT_LENGTH)) { + socket << HttpMessage::HEADER_CONTENT_LENGTH << ": " + << req.GetContent().size() << "\r\n"; + } + } - if (socket_ret == 0) - socket_ret = RecvHeaders(socket, req); + socket << "\r\n"; - if (socket_ret == 0) - socket_ret = RecvBody(socket, req); + if (req.GetContent().size() == 0) { + if (socket.flush().good()) { + return ReturnCode::OK; + } else { + return static_cast(socket.LastError()); + } + } - return socket_ret; + return ReturnCode::OK; } -int HttpProto::RecvRespStartLine(BaseTcpStream & socket, HttpResponse * resp) { - char line[1024] = {0}; +ReturnCode HttpProtocol::RecvRespStartLine(BaseTcpStream &socket, HttpResponse *resp) { + char line[1024]{0}; - bool is_good = socket.getlineWithTrimRight(line, sizeof(line)).good(); + bool is_good{socket.getlineWithTrimRight(line, sizeof(line)).good()}; if (is_good) { if (0 == strncasecmp(line, "HTTP", strlen("HTTP"))) { - char * pos = line; - char * first = strsep(&pos, " "); - char * second = strsep(&pos, " "); + char *pos = line; + char *first = SeparateStr(&pos, " "); + char *second = SeparateStr(&pos, " "); - if (NULL != first) + if (nullptr != first) resp->SetVersion(first); - if (NULL != second) + if (nullptr != second) resp->SetStatusCode(atoi(second)); - if (NULL != pos) + if (nullptr != pos) resp->SetReasonPhrase(pos); } else { is_good = false; @@ -219,27 +199,27 @@ int HttpProto::RecvRespStartLine(BaseTcpStream & socket, HttpResponse * resp) { } if (is_good) { - return 0; + return ReturnCode::OK; } else { phxrpc::log(LOG_WARNING, "%s, fail", __func__); - return socket.LastError(); + return static_cast(socket.LastError()); } } -int HttpProto::RecvReqStartLine(BaseTcpStream & socket, HttpRequest * req) { - char line[1024] = { 0 }; +ReturnCode HttpProtocol::RecvReqStartLine(BaseTcpStream &socket, HttpRequest *req) { + char line[1024]{0}; bool is_good = socket.getlineWithTrimRight(line, sizeof(line)).good(); if (is_good) { - char * pos = line; - char * first = strsep(&pos, " "); - char * second = strsep(&pos, " "); + char *pos = line; + char *first = SeparateStr(&pos, " "); + char *second = SeparateStr(&pos, " "); - if (NULL != first) + if (nullptr != first) req->SetMethod(first); - if (NULL != second) + if (nullptr != second) req->SetURI(second); - if (NULL != pos) + if (nullptr != pos) req->SetVersion(pos); char peer[128] = { 0 }; @@ -250,20 +230,20 @@ int HttpProto::RecvReqStartLine(BaseTcpStream & socket, HttpRequest * req) { } if (is_good) { - return 0; + return ReturnCode::OK; } else { - return socket.LastError(); + return static_cast(socket.LastError()); } } -int HttpProto::RecvHeaders(BaseTcpStream & socket, HttpMessage * msg) { - bool is_good = false; +ReturnCode HttpProtocol::RecvHeaders(BaseTcpStream &socket, HttpMessage *msg) { + bool is_good{false}; - char * line = (char*) malloc(MAX_RECV_LEN); - assert(NULL != line); + char *line = (char *)malloc(MAX_RECV_LEN); + assert(nullptr != line); - std::string multi_line; - char * pos = NULL; + string multi_line; + char *pos{nullptr}; do { is_good = socket.getlineWithTrimRight(line, MAX_RECV_LEN).good(); @@ -274,10 +254,10 @@ int HttpProto::RecvHeaders(BaseTcpStream & socket, HttpMessage * msg) { if (multi_line.size() > 0) { char * header = (char*) multi_line.c_str(); pos = header; - strsep(&pos, ":"); - for (; NULL != pos && '\0' != *pos && isspace(*pos);) + SeparateStr(&pos, ":"); + for (; nullptr != pos && '\0' != *pos && isspace(*pos);) pos++; - msg->AddHeader(header, NULL == pos ? "" : pos); + msg->AddHeader(header, nullptr == pos ? "" : pos); } multi_line.clear(); } @@ -289,24 +269,24 @@ int HttpProto::RecvHeaders(BaseTcpStream & socket, HttpMessage * msg) { } while (is_good && '\0' != *line); free(line); - line = NULL; + line = nullptr; if (is_good) { - return 0; + return ReturnCode::OK; } else { - return socket.LastError(); + return static_cast(socket.LastError()); } } -int HttpProto::RecvBody(BaseTcpStream & socket, HttpMessage * msg) { - bool is_good = true; +ReturnCode HttpProtocol::RecvBody(BaseTcpStream &socket, HttpMessage *msg) { + bool is_good{true}; - const char * encoding = msg->GetHeaderValue(HttpMessage::HEADER_TRANSFER_ENCODING); + const char *encoding{msg->GetHeaderValue(HttpMessage::HEADER_TRANSFER_ENCODING)}; - char * buff = (char*) malloc(MAX_RECV_LEN); - assert(NULL != buff); + char *buff{(char *)malloc(MAX_RECV_LEN)}; + assert(nullptr != buff); - if (NULL != encoding && 0 == strcasecmp(encoding, "chunked")) { + if (nullptr != encoding && 0 == strcasecmp(encoding, "chunked")) { // read chunked, refer to rfc2616 section[19.4.6] for (; is_good;) { @@ -314,7 +294,7 @@ int HttpProto::RecvBody(BaseTcpStream & socket, HttpMessage * msg) { if (!is_good) break; - int size = strtol(buff, NULL, 16); + int size{static_cast(strtol(buff, nullptr, 16))}; if (size > 0) { for (; size > 0;) { int read_len = size > MAX_RECV_LEN ? MAX_RECV_LEN : size; @@ -332,10 +312,10 @@ int HttpProto::RecvBody(BaseTcpStream & socket, HttpMessage * msg) { } } } else { - const char * content_length = msg->GetHeaderValue(HttpMessage::HEADER_CONTENT_LENGTH); + const char *content_length{msg->GetHeaderValue(HttpMessage::HEADER_CONTENT_LENGTH)}; - if (NULL != content_length) { - int size = atoi(content_length); + if (nullptr != content_length) { + int size{atoi(content_length)}; for (; size > 0 && is_good;) { int read_len = size > MAX_RECV_LEN ? MAX_RECV_LEN : size; @@ -347,7 +327,7 @@ int HttpProto::RecvBody(BaseTcpStream & socket, HttpMessage * msg) { break; } } - } else if (HttpMessage::eResponse == msg->GetType()) { + } else if (BaseMessage::Direction::RESPONSE == msg->direction()) { // hasn't Content-Length header, read until socket close for (; is_good;) { is_good = socket.read(buff, MAX_RECV_LEN).good(); @@ -363,11 +343,31 @@ int HttpProto::RecvBody(BaseTcpStream & socket, HttpMessage * msg) { free(buff); if (is_good) { - return 0; + return ReturnCode::OK; } else { - return socket.LastError(); + return static_cast(socket.LastError()); } } +ReturnCode HttpProtocol::RecvReq(BaseTcpStream &socket, HttpRequest *req) { + ReturnCode ret{RecvReqStartLine(socket, req)}; + + if (ReturnCode::OK == ret) + ret = RecvHeaders(socket, req); + + if (ReturnCode::OK == ret) + ret = RecvBody(socket, req); + + return ret; +} + +ReturnCode HttpProtocol::ServerRecv(BaseTcpStream &socket, BaseRequest *&req) { + HttpRequest *http_req{new HttpRequest}; + req = http_req; + + return RecvReq(socket, http_req); } + +} // namespace phxrpc + diff --git a/phxrpc/http/http_protocol.h b/phxrpc/http/http_protocol.h new file mode 100644 index 0000000..f8c2e0e --- /dev/null +++ b/phxrpc/http/http_protocol.h @@ -0,0 +1,67 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "phxrpc/msg/base_protocol.h" + + +namespace phxrpc { + + +class BaseTcpStream; + +class HttpMessage; +class HttpRequest; +class HttpResponse; + +class HttpProtocol : public BaseProtocol { + public: + enum { + MAX_RECV_LEN = 8192 + }; + + HttpProtocol() = default; + virtual ~HttpProtocol() override = default; + + static void FixRespHeaders(const HttpRequest &req, HttpResponse *resp); + + static void FixRespHeaders(bool is_keep_alive, const char *version, HttpResponse *resp); + + static ReturnCode SendReqHeader(BaseTcpStream &socket, const char *method, const HttpRequest &req); + + static ReturnCode RecvRespStartLine(BaseTcpStream &socket, HttpResponse *resp); + + static ReturnCode RecvReqStartLine(BaseTcpStream &socket, HttpRequest *req); + + static ReturnCode RecvHeaders(BaseTcpStream &socket, HttpMessage *msg); + + static ReturnCode RecvBody(BaseTcpStream &socket, HttpMessage *msg); + + static ReturnCode RecvReq(BaseTcpStream &socket, HttpRequest *req); + + virtual ReturnCode ServerRecv(BaseTcpStream &socket, + BaseRequest *&req) override; +}; + + +} // namespace phxrpc + diff --git a/phxrpc/http/test_http_client.cpp b/phxrpc/http/test_http_client.cpp index fd5412c..cda89f5 100644 --- a/phxrpc/http/test_http_client.cpp +++ b/phxrpc/http/test_http_client.cpp @@ -1,32 +1,31 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include - #include "http_msg.h" #include "http_client.h" @@ -36,7 +35,7 @@ See the AUTHORS file for names of contributors. using namespace phxrpc; -void showUsage(const char * program) { +void ShowUsage(const char *program) { printf("\n%s [-h host] [-p port] [-r POST|GET] [-u URI] [-f file] [-v]\n", program); printf("\t-h http host\n"); @@ -50,33 +49,33 @@ void showUsage(const char * program) { exit(0); } -int main(int argc, char * argv[]) { +int main(int argc, char *argv[]) { assert(sigset(SIGPIPE, SIG_IGN) != SIG_ERR); OptMap optMap("h:p:r:u:f:ov"); if ((!optMap.Parse(argc, argv)) || optMap.Has('v')) - showUsage(argv[0]); + ShowUsage(argv[0]); - int port = 0; - const char * host = optMap.Get('h'); - const char * method = optMap.Get('r'); - const char * uri = optMap.Get('u'); - const char * file = optMap.Get('f'); + int port{0}; + const char *host{optMap.Get('h')}; + const char *method{optMap.Get('r')}; + const char *uri{optMap.Get('u')}; + const char *file{optMap.Get('f')}; - if ((NULL == host) || (!optMap.GetInt('p', &port))) { + if ((nullptr == host) || (!optMap.GetInt('p', &port))) { printf("\nPlease specify host and port!\n"); - showUsage(argv[0]); + ShowUsage(argv[0]); } - if (NULL == method || NULL == uri) { + if (nullptr == method || nullptr == uri) { printf("\nPlease specify URI and method!\n"); - showUsage(argv[0]); + ShowUsage(argv[0]); } - if (0 == strcasecmp(method, "POST") && NULL == file) { + if (0 == strcasecmp(method, "POST") && nullptr == file) { printf("\nPlease specify the file for POST body!\n"); - showUsage(argv[0]); + ShowUsage(argv[0]); } HttpRequest request; @@ -94,40 +93,40 @@ int main(int argc, char * argv[]) { } BlockTcpStream socket; - if (!BlockTcpUtils::Open(&socket, host, port, 100, NULL, 0)) { + if (!BlockTcpUtils::Open(&socket, host, port, 100, nullptr, 0)) { printf("Connect %s:%d fail\n", host, port); exit(-1); } HttpResponse response; - bool socket_ret = false; + int ret{0}; if (request.IsMethod("GET")) { - socket_ret = HttpClient::Get(socket, request, &response); + ret = HttpClient::Get(socket, request, &response); } else if (request.IsMethod("POST")) { - socket_ret = HttpClient::Post(socket, request, &response); + ret = HttpClient::Post(socket, request, &response); } else if (request.IsMethod("HEAD")) { - socket_ret = HttpClient::Head(socket, request, &response); + ret = HttpClient::Head(socket, request, &response); } else { printf("unsupport method %s\n", request.GetMethod()); } - if (socket_ret) { + if (0 == ret) { printf("response:\n"); printf("%s %d %s\n", response.GetVersion(), response.GetStatusCode(), response.GetReasonPhrase()); printf("%zu headers\n", response.GetHeaderCount()); - for (size_t i = 0; i < response.GetHeaderCount(); i++) { - const char * name = response.GetHeaderName(i); - const char * val = response.GetHeaderValue(i); + for (size_t i{0}; response.GetHeaderCount() > i; ++i) { + const char *name{response.GetHeaderName(i)}; + const char *val{response.GetHeaderValue(i)}; printf("%s: %s\r\n", name, val); } printf("%zu bytes body\n", response.GetContent().size()); if (response.GetContent().size() > 0) { - //printf( "%s\n", (char*)response.getContent() ); + //printf("%s\n", (char*)response.getContent()); } } else { printf("http request fail\n"); diff --git a/phxrpc/mqtt.h b/phxrpc/mqtt.h new file mode 100644 index 0000000..9dabfc5 --- /dev/null +++ b/phxrpc/mqtt.h @@ -0,0 +1,27 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "mqtt/mqtt_client.h" +#include "mqtt/mqtt_msg.h" +#include "mqtt/mqtt_protocol.h" + diff --git a/phxrpc/mqtt/Makefile b/phxrpc/mqtt/Makefile new file mode 100644 index 0000000..a8d802f --- /dev/null +++ b/phxrpc/mqtt/Makefile @@ -0,0 +1,16 @@ +include ../../phxrpc.mk + +TEST_TARGETS = test_mqtt_protocol test_mqtt_client + +all: $(TEST_TARGETS) + +test_mqtt_protocol: test_mqtt_protocol.o + $(LINKER) $^ -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -o $@ + +test_mqtt_client: test_mqtt_client.o + $(LINKER) $^ -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -o $@ + +clean: + @( $(RM) $(TEST_TARGETS) ) + @( $(RM) *.o core.* $(LIB_OBJS) ) + diff --git a/phxrpc/mqtt/mqtt.proto b/phxrpc/mqtt/mqtt.proto new file mode 100644 index 0000000..a743fd4 --- /dev/null +++ b/phxrpc/mqtt/mqtt.proto @@ -0,0 +1,74 @@ +syntax = "proto3"; + +package phxrpc.mqtt; + +import "google/protobuf/wrappers.proto"; +import "google/protobuf/empty.proto"; + +import "phxrpc/rpc/phxrpc.proto"; + + +service Mqtt { + + rpc PhxMqttConnect(MqttConnectPb) returns (MqttConnackPb) { + option(phxrpc.CmdID) = 2000011; + option(phxrpc.OptString) = "l:"; + option(phxrpc.Usage) = "-l "; + } + + rpc PhxMqttPublish(MqttPublishPb) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2000012; + option(phxrpc.OptString) = "l:d:q:r:t:p:s:"; + option(phxrpc.Usage) = "-l -d -q -r -t -p -s "; + } + + rpc PhxMqttPuback(MqttPubackPb) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2000013; + option(phxrpc.OptString) = "l:p:"; + option(phxrpc.Usage) = "-l -p "; + } + + rpc PhxMqttPubrec(MqttPubrecPb) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2000014; + option(phxrpc.OptString) = ""; + option(phxrpc.Usage) = ""; + } + + rpc PhxMqttPubrel(MqttPubrelPb) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2000015; + option(phxrpc.OptString) = ""; + option(phxrpc.Usage) = ""; + } + + rpc PhxMqttPubcomp(MqttPubcompPb) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2000016; + option(phxrpc.OptString) = ""; + option(phxrpc.Usage) = ""; + } + + rpc PhxMqttSubscribe(MqttSubscribePb) returns (MqttSubackPb) { + option(phxrpc.CmdID) = 2000017; + option(phxrpc.OptString) = "l:p:t:q:"; + option(phxrpc.Usage) = "-l -p -t -q "; + } + + rpc PhxMqttUnsubscribe(MqttUnsubscribePb) returns (MqttUnsubackPb) { + option(phxrpc.CmdID) = 2000018; + option(phxrpc.OptString) = "l:p:t:"; + option(phxrpc.Usage) = "-l -p -t "; + } + + rpc PhxMqttPing(MqttPingreqPb) returns (MqttPingrespPb) { + option(phxrpc.CmdID) = 2000019; + option(phxrpc.OptString) = "l:"; + option(phxrpc.Usage) = "-l "; + } + + rpc PhxMqttDisconnect(MqttDisconnectPb) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2000020; + option(phxrpc.OptString) = "l:"; + option(phxrpc.Usage) = "-l "; + } + +} + diff --git a/phxrpc/mqtt/mqtt_client.cpp b/phxrpc/mqtt/mqtt_client.cpp new file mode 100644 index 0000000..c555169 --- /dev/null +++ b/phxrpc/mqtt/mqtt_client.cpp @@ -0,0 +1,197 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "mqtt_client.h" + +#include +#include +#include +#include +#include + +#include "phxrpc/file/log_utils.h" +#include "phxrpc/network/socket_stream_base.h" + +#include "mqtt_msg.h" +#include "mqtt_protocol.h" + + +namespace { + + +phxrpc::ReturnCode DoMethod(phxrpc::BaseTcpStream &socket, const phxrpc::MqttMessage *const req, + phxrpc::MqttMessage *const resp, + phxrpc::MqttClient::MqttStat &mqtt_stat) { + phxrpc::ReturnCode ret{phxrpc::MqttProtocol::SendMessage(socket, req)}; + if (phxrpc::ReturnCode::OK != ret) { + if (phxrpc::ReturnCode::ERROR_SOCKET_STREAM_NORMAL_CLOSED != ret) { + mqtt_stat.send_error_ = true; + phxrpc::log(LOG_ERR, "SendMessage err %d", ret); + } + + return ret; + } + + if (!socket.flush().good()) { + phxrpc::log(LOG_ERR, "socket err %d", socket.LastError()); + + return static_cast(socket.LastError()); + } + + if (!resp->fake()) { + ret = phxrpc::MqttProtocol::RecvMessage(socket, resp); + if (phxrpc::ReturnCode::OK != ret) { + if (phxrpc::ReturnCode::ERROR_SOCKET_STREAM_NORMAL_CLOSED != ret) { + mqtt_stat.recv_error_ = true; + phxrpc::log(LOG_ERR, "RecvMessage err %d", ret); + } + + return ret; + } + } + + return ret; +} + +phxrpc::ReturnCode DoMethod(phxrpc::BaseTcpStream &socket, const phxrpc::MqttMessage *const req, + phxrpc::MqttMessage *const resp) { + phxrpc::MqttClient::MqttStat mqtt_stat; + return DoMethod(socket, req, resp, mqtt_stat); +} + + +} // namespace + + +namespace phxrpc { + + +int MqttClient::Connect(BaseTcpStream &socket, const MqttConnect &req, + MqttConnack &resp, MqttStat &mqtt_stat) { + // TODO: remove + printf("%s client_identifier %s\n", __func__, req.client_identifier().c_str()); + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Connect(BaseTcpStream &socket, const MqttConnect &req, + MqttConnack &resp) { + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Publish(BaseTcpStream &socket, const MqttPublish &req, + MqttStat &mqtt_stat) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Publish(BaseTcpStream &socket, const MqttPublish &req) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Puback(BaseTcpStream &socket, const MqttPuback &req, + MqttStat &mqtt_stat) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Puback(BaseTcpStream &socket, const MqttPuback &req) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Pubrec(BaseTcpStream &socket, const MqttPubrec &req, + MqttStat &mqtt_stat) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Pubrec(BaseTcpStream &socket, const MqttPubrec &req) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Pubrel(BaseTcpStream &socket, const MqttPubrel &req, + MqttStat &mqtt_stat) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Pubrel(BaseTcpStream &socket, const MqttPubrel &req) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Pubcomp(BaseTcpStream &socket, const MqttPubcomp &req, + MqttStat &mqtt_stat) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Pubcomp(BaseTcpStream &socket, const MqttPubcomp &req) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Subscribe(BaseTcpStream &socket, const MqttSubscribe &req, + MqttSuback &resp, MqttStat &mqtt_stat) { + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Subscribe(BaseTcpStream &socket, const MqttSubscribe &req, + MqttSuback &resp) { + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Unsubscribe(BaseTcpStream &socket, const MqttUnsubscribe &req, + MqttUnsuback &resp, MqttStat &mqtt_stat) { + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Unsubscribe(BaseTcpStream &socket, const MqttUnsubscribe &req, + MqttUnsuback &resp) { + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Ping(BaseTcpStream &socket, const MqttPingreq &req, + MqttPingresp &resp, MqttStat &mqtt_stat) { + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Ping(BaseTcpStream &socket, const MqttPingreq &req, + MqttPingresp &resp) { + return static_cast(DoMethod(socket, &req, &resp)); +} + +int MqttClient::Disconnect(BaseTcpStream &socket, const MqttDisconnect &req, + MqttStat &mqtt_stat) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Disconnect(BaseTcpStream &socket, const MqttDisconnect &req) { + MqttFakeResponse resp; + return static_cast(DoMethod(socket, &req, &resp)); +} + + +} // namespace phxrpc + diff --git a/phxrpc/mqtt/mqtt_client.h b/phxrpc/mqtt/mqtt_client.h new file mode 100644 index 0000000..2bfe77c --- /dev/null +++ b/phxrpc/mqtt/mqtt_client.h @@ -0,0 +1,119 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + + +namespace phxrpc { + + +class BaseTcpStream; +class ClientMonitor; + +class MqttConnect; +class MqttConnack; +class MqttPublish; +class MqttPuback; +class MqttPubrec; +class MqttPubrel; +class MqttPubcomp; +class MqttSubscribe; +class MqttSuback; +class MqttUnsubscribe; +class MqttUnsuback; +class MqttPingreq; +class MqttPingresp; +class MqttDisconnect; + +class MqttClient { + public: + struct MqttStat { + bool send_error_{false}; + bool recv_error_{false}; + + MqttStat() = default; + + MqttStat(bool send_error, bool recv_error) + : send_error_(send_error), recv_error_(recv_error) { + } + }; + + // @return true: socket ok; false: socket error + static int Connect(BaseTcpStream &socket, const MqttConnect &req, + MqttConnack &resp, MqttStat &mqtt_stat); + static int Connect(BaseTcpStream &socket, const MqttConnect &req, + MqttConnack &resp); + + // @return true: socket ok; false: socket error + static int Publish(BaseTcpStream &socket, const MqttPublish &req, + MqttStat &mqtt_stat); + static int Publish(BaseTcpStream &socket, const MqttPublish &req); + + // @return true: socket ok; false: socket error + static int Puback(BaseTcpStream &socket, const MqttPuback &req, + MqttStat &mqtt_stat); + static int Puback(BaseTcpStream &socket, const MqttPuback &req); + + // @return true: socket ok; false: socket error + static int Pubrec(BaseTcpStream &socket, const MqttPubrec &req, + MqttStat &mqtt_stat); + static int Pubrec(BaseTcpStream &socket, const MqttPubrec &req); + + // @return true: socket ok; false: socket error + static int Pubrel(BaseTcpStream &socket, const MqttPubrel &req, + MqttStat &mqtt_stat); + static int Pubrel(BaseTcpStream &socket, const MqttPubrel &req); + + // @return true: socket ok; false: socket error + static int Pubcomp(BaseTcpStream &socket, const MqttPubcomp &req, + MqttStat &mqtt_stat); + static int Pubcomp(BaseTcpStream &socket, const MqttPubcomp &req); + + // @return true: socket ok; false: socket error + static int Subscribe(BaseTcpStream &socket, const MqttSubscribe &req, + MqttSuback &resp, MqttStat &mqtt_stat); + static int Subscribe(BaseTcpStream &socket, const MqttSubscribe &req, + MqttSuback &resp); + + // @return true: socket ok; false: socket error + static int Unsubscribe(BaseTcpStream &socket, const MqttUnsubscribe &req, + MqttUnsuback &resp, MqttStat &mqtt_stat); + static int Unsubscribe(BaseTcpStream &socket, const MqttUnsubscribe &req, + MqttUnsuback &resp); + + // @return true: socket ok; false: socket error + static int Ping(BaseTcpStream &socket, const MqttPingreq &req, + MqttPingresp &resp, MqttStat &mqtt_stat); + static int Ping(BaseTcpStream &socket, const MqttPingreq &req, + MqttPingresp &resp); + + // @return true: socket ok; false: socket error + static int Disconnect(BaseTcpStream &socket, const MqttDisconnect &req, + MqttStat &mqtt_stat); + static int Disconnect(BaseTcpStream &socket, const MqttDisconnect &req); + + private: + MqttClient(); +}; + + +} // namespace phxrpc + diff --git a/phxrpc/mqtt/mqtt_msg.cpp b/phxrpc/mqtt/mqtt_msg.cpp new file mode 100644 index 0000000..d4ad3fa --- /dev/null +++ b/phxrpc/mqtt/mqtt_msg.cpp @@ -0,0 +1,1602 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "mqtt_msg.h" + +#include +#include +#include +#include + +#include "phxrpc/file/log_utils.h" +#include "phxrpc/network/socket_stream_base.h" +#include "phxrpc/rpc/phxrpc.pb.h" + +#include "mqtt_protocol.h" + + +namespace phxrpc { + + +using namespace std; + + +const char MqttMessage::SampleFixedHeader[]{ + '\x00', // FAKE_NONE + '\x10', // CONNECT + '\x20', // CONNACK + '\x32', // PUBLISH QoS 1 + '\x40', // PUBACK + '\x50', // PUBREC + '\x62', // PUBREL + '\x70', // PUBCOMP + '\x82', // SUBSCRIBE + '\x90', // SUBACK + '\xa2', // UNSUBSCRIBE + '\xb0', // UNSUBACK + '\xc0', // PINGREQ + '\xd0', // PINGRESP + '\xe0', // DISCONNECT + '\xf0', // FAKE_DISCONNACK +}; + +int MqttMessage::EncodeUint16(string &dest, const uint16_t src) { + dest.clear(); + dest.resize(2); + dest[0] = static_cast(src >> 8); + dest[1] = static_cast(src); + + return 0; +} + +int MqttMessage::EncodeUint16(char *const dest, const size_t dest_size, + const uint16_t src) { + if (2 != dest_size) + return -1; + + dest[0] = static_cast(src >> 8); + dest[1] = static_cast(src); + + return 0; +} + +int MqttMessage::EncodeUnicode(string &dest, const string &src) { + dest.clear(); + dest.resize(2 + src.size()); + uint16_t src_size{static_cast(src.size())}; + dest[0] = static_cast(src_size >> 8); + dest[1] = static_cast(src_size); + for (int i{0}; src_size > i; ++i) { + dest[i + 2] = src.at(i); + } + + return 0; +} + +int MqttMessage::EncodeUnicode(char *const dest, const size_t dest_size, + const string &src) { + if (2 + src.size() != dest_size) + return -1; + + uint16_t src_size{static_cast(src.size())}; + dest[0] = static_cast(src_size >> 8); + dest[1] = static_cast(src_size); + for (int i{0}; src_size > i; ++i) { + dest[i + 2] = src.at(i); + } + + return 0; +} + + +ReturnCode MqttMessage::SendChar(ostringstream &out_stream, + const char &content) { + out_stream.put(content); + + // TODO: check stream + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvChar(istringstream &in_stream, char &content) { + in_stream.get(content); + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::SendUint16(ostringstream &out_stream, + const uint16_t content) { + out_stream.put(static_cast(content >> 8)); + out_stream.put(static_cast(content)); + + // TODO: check stream + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvUint16(istringstream &in_stream, + uint16_t &content) { + char temp; + in_stream.get(temp); + content = (static_cast(temp) << 8); + temp = '\0'; + in_stream.get(temp); + content |= static_cast(temp); + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::SendChars(ostringstream &out_stream, + const char *const content, + const int content_length) { + out_stream.write(content, content_length); + + // TODO: check stream + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvChars(istringstream &in_stream, + char *const content, + const int content_length) { + in_stream.read(content, content_length); + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::SendUnicode(ostringstream &out_stream, + const string &content) { + uint16_t content_size{static_cast(content.size())}; + ReturnCode ret{SendUint16(out_stream, content_size)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUint16 err %d", ret); + + return ret; + } + + out_stream.write(content.data(), content.size()); + + // TODO: check stream + return ret; +} + +ReturnCode MqttMessage::RecvUnicode(istringstream &in_stream, string &content) { + uint16_t content_size{0}; + ReturnCode ret{RecvUint16(in_stream, content_size)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUint16 err %d", ret); + + return ret; + } + + content.resize(content_size); + in_stream.read(&content[0], content_size); + + return ret; +} + + +ReturnCode MqttMessage::SendChar(BaseTcpStream &out_stream, + const char &content) { + out_stream.put(content); + + // TODO: check stream + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvChar(BaseTcpStream &in_stream, char &content) { + in_stream.get(content); + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::SendUint16(BaseTcpStream &out_stream, + const uint16_t content) { + out_stream.put(static_cast(content >> 8)); + out_stream.put(static_cast(content)); + + // TODO: check stream + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvUint16(BaseTcpStream &in_stream, uint16_t &content) { + char temp; + in_stream.get(temp); + content = (static_cast(temp) << 8); + temp = '\0'; + in_stream.get(temp); + content |= static_cast(temp); + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::SendChars(BaseTcpStream &out_stream, + const char *const content, + const int content_length) { + out_stream.write(content, content_length); + + // TODO: check stream + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvChars(BaseTcpStream &in_stream, + char *const content, + const int content_length) { + in_stream.read(content, content_length); + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::SendUnicode(BaseTcpStream &out_stream, + const string &content) { + uint16_t content_size{static_cast(content.size())}; + ReturnCode ret{SendUint16(out_stream, content_size)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUint16 err %d", ret); + + return ret; + } + + out_stream.write(content.data(), content.size()); + + // TODO: check stream + return ret; +} + +ReturnCode MqttMessage::RecvUnicode(BaseTcpStream &in_stream, string &content) { + uint16_t content_size{0}; + ReturnCode ret{RecvUint16(in_stream, content_size)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUint16 err %d", ret); + + return ret; + } + + content.resize(content_size); + in_stream.read(&content[0], content_size); + + return ret; +} + + +MqttMessage::MqttMessage() { + SetVersion("MQTT/3.1.1"); + memset(client_ip_, 0, sizeof(client_ip_)); +} + +MqttMessage::~MqttMessage() {} + +uint8_t MqttMessage::EncodeFixedHeader(const FixedHeader &fixed_header) { + const int control_packet_type_int{static_cast(fixed_header.control_packet_type)}; + const char fixed_header_char{SampleFixedHeader[control_packet_type_int]}; + uint8_t fixed_header_byte{static_cast(fixed_header_char)}; + if (ControlPacketType::PUBLISH == fixed_header.control_packet_type) { + fixed_header.dup ? (fixed_header_byte |= 0x8) : (fixed_header_byte &= ~0x8); + fixed_header_byte &= ~0x6; + fixed_header_byte |= (static_cast(fixed_header.qos) << 1); + fixed_header.retain ? (fixed_header_byte |= 0x1) : (fixed_header_byte &= ~0x1); + } + + return fixed_header_byte; +} + +MqttMessage::FixedHeader MqttMessage::DecodeFixedHeader(const uint8_t fixed_header_byte) { + FixedHeader fixed_header; + + fixed_header.dup = static_cast((fixed_header_byte >> 3) & 0x01); + fixed_header.qos = static_cast((fixed_header_byte >> 1) & 0x03); + fixed_header.retain = static_cast(fixed_header_byte & 0x01); + + uint8_t temp{fixed_header_byte}; + temp >>= 4; + temp &= 0x0f; + // must convert to unsigned first + fixed_header.control_packet_type = static_cast(temp); + + return fixed_header; +} + +ReturnCode MqttMessage::SendFixedHeaderAndRemainingBuffer( + BaseTcpStream &out_stream, const FixedHeader &fixed_header, + const string &remaining_buffer) { + uint8_t fixed_header_byte{EncodeFixedHeader(fixed_header)}; + ReturnCode ret{SendChar(out_stream, static_cast(fixed_header_byte))}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } else { + phxrpc::log(LOG_DEBUG, "SendChar type %d fixed_header_byte %u", + static_cast(fixed_header.control_packet_type), + static_cast(fixed_header_byte)); + } + + const int remaining_length{static_cast(remaining_buffer.size())}; + ret = SendRemainingLength(out_stream, remaining_length); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendRemainingLength err %d", ret); + + return ret; + } + + ret = SendChars(out_stream, remaining_buffer.data(), + remaining_buffer.size()); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChars err %d", ret); + + return ret; + } + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvFixedHeaderAndRemainingBuffer( + BaseTcpStream &in_stream, FixedHeader &fixed_header, + string &remaining_buffer) { + char fixed_header_char{0x0}; + ReturnCode ret{RecvChar(in_stream, fixed_header_char)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + + fixed_header = DecodeFixedHeader(static_cast(fixed_header_char)); + + phxrpc::log(LOG_DEBUG, "RecvChar type %d fixed_header %x", + static_cast(fixed_header.control_packet_type), + static_cast(fixed_header_char)); + + int remaining_length{0}; + ret = RecvRemainingLength(in_stream, remaining_length); + + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvRemainingLength err %d", ret); + + return ret; + } + + remaining_buffer.resize(remaining_length); + ret = RecvChars(in_stream, &remaining_buffer[0], remaining_length); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChars err %d", ret); + + return ret; + } + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::SendRemainingLength(BaseTcpStream &out_stream, + const int remaining_length) { + char temp{0x0}; + char continue_bit{0x0}; + uint32_t temp_remaining_length{static_cast(remaining_length)}; + + for (int i{0}; 4 > i; ++i) { + temp = (temp_remaining_length & 0x7f); + temp_remaining_length >>= 8; + continue_bit = (temp_remaining_length > 0) ? 0x80 : 0x0; + out_stream.put(temp | continue_bit); + if (0x0 == continue_bit) { + return ReturnCode::OK; + } + } + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvRemainingLength(BaseTcpStream &in_stream, + int &remaining_length) { + uint32_t temp_remaining_length{0}; + + char temp{0x0}; + in_stream.get(temp); + temp_remaining_length = (static_cast(temp) & 0x7f); + + if (!(static_cast(temp) & 0x80)) { + remaining_length = temp_remaining_length; + + return ReturnCode::OK; + } + + in_stream.get(temp); + temp_remaining_length |= (static_cast(temp) & 0x7f) << 7; + if (!(static_cast(temp) & 0x80)) { + remaining_length = temp_remaining_length; + + return ReturnCode::OK; + } + + in_stream.get(temp); + temp_remaining_length |= (static_cast(temp) & 0x7f) << 14; + if (!(static_cast(temp) & 0x80)) { + remaining_length = temp_remaining_length; + + return ReturnCode::OK; + } + + in_stream.get(temp); + temp_remaining_length |= (static_cast(temp) & 0x7f) << 21; + + remaining_length = temp_remaining_length; + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::Send(BaseTcpStream &socket) const { + ostringstream ss; + ReturnCode ret{SendRemaining(ss)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendRemaining err %d", ret); + + return ret; + } + + ret = SendFixedHeaderAndRemainingBuffer(socket, fixed_header(), ss.str()); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendFixedHeaderAndRemainingBuffer err %d", ret); + + return ret; + } + + if (!socket.flush().good()) { + phxrpc::log(LOG_ERR, "socket err %d", socket.LastError()); + + return static_cast(socket.LastError()); + } + + return ret; +} + +ReturnCode MqttMessage::SendRemaining(ostringstream &out_stream) const { + ReturnCode ret{SendVariableHeader(out_stream)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendVariableHeader err %d", ret); + + return ret; + } + // TODO: remove + //string remaining_buffer(out_stream.str()); + //printf("remaining_buffer %zu\n", remaining_buffer.size()); + //for (int i{0}; remaining_buffer.size() > i; ++i) { + //printf("%d\t", remaining_buffer.at(i)); + //} + //printf("\n"); + //for (int i{0}; remaining_buffer.size() > i; ++i) { + //printf("%c\t", remaining_buffer.at(i)); + //} + //printf("\n"); + + ret = SendPayload(out_stream); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendPayload err %d", ret); + + return ret; + } + // TODO: remove + //remaining_buffer = out_stream.str(); + //printf("remaining_buffer %zu\n", remaining_buffer.size()); + //for (int i{0}; remaining_buffer.size() > i; ++i) { + //printf("%d\t", remaining_buffer.at(i)); + //} + //printf("\n"); + //for (int i{0}; remaining_buffer.size() > i; ++i) { + //printf("%c\t", remaining_buffer.at(i)); + //} + //printf("\n"); + + return ret; +} + +ReturnCode MqttMessage::RecvRemaining(istringstream &in_stream) { + ReturnCode ret{RecvVariableHeader(in_stream)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvVariableHeader err %d", ret); + + return ret; + } + + ret = RecvPayload(in_stream); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvPayload err %d", ret); + + return ret; + } + //phxrpc::log(LOG_DEBUG, "RecvPayload \"%s\"", GetContent().c_str()); + + return ret; +} + +ReturnCode MqttMessage::SendPacketIdentifier(ostringstream &out_stream) const { + ReturnCode ret{SendUint16(out_stream, packet_identifier_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUint16 err %d", ret); + + return ret; + } + + return ReturnCode::OK; +} + +ReturnCode MqttMessage::RecvPacketIdentifier(istringstream &in_stream) { + ReturnCode ret{RecvUint16(in_stream, packet_identifier_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUint16 err %d", ret); + + return ret; + } + + return ReturnCode::OK; +} + +ReturnCode MqttResponse::ModifyResp(const bool keep_alive, const string &version) { + return ReturnCode::OK; +} + + +MqttFakeResponse::MqttFakeResponse() { + set_protocol(Protocol::MQTT_FAKE_NONE); + mutable_fixed_header().control_packet_type = ControlPacketType::FAKE_NONE; + set_fake(true); +} + + +MqttConnect::MqttConnect() { + set_protocol(Protocol::MQTT_CONNECT); + SetURI("/phxrpc/mqtt/PhxMqttConnect"); + mutable_fixed_header().control_packet_type = ControlPacketType::CONNECT; +} + +ReturnCode MqttConnect::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttConnectPb connect; + + connect.set_client_identifier(client_identifier_); + connect.set_proto_name(proto_name_); + connect.set_proto_level(proto_level_); + connect.set_clean_session(clean_session_); + connect.set_keep_alive(keep_alive_); + connect.set_user_name(user_name_); + connect.set_password(password_); + connect.set_will_flag(will_flag_); + connect.set_will_qos(will_qos_); + connect.set_will_retain(will_retain_); + connect.set_will_topic(will_topic_); + connect.set_will_message(will_message_); + + try { + message->CopyFrom(connect); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttConnect::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttConnectPb connect; + + try { + connect.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + client_identifier_ = connect.client_identifier(); + proto_name_ = connect.proto_name(); + proto_level_ = connect.proto_level(); + clean_session_ = connect.clean_session(); + keep_alive_ = connect.keep_alive(); + user_name_ = connect.user_name(); + password_ = connect.password(); + will_flag_ = connect.will_flag(); + will_qos_ = connect.will_qos(); + will_retain_ = connect.will_retain(); + will_topic_ = connect.will_topic(); + will_message_ = connect.will_message(); + + return ReturnCode::OK; +} + +BaseResponse *MqttConnect::GenResponse() const { return new MqttConnack; } + +ReturnCode MqttConnect::SendVariableHeader(ostringstream &out_stream) const { + ReturnCode ret{SendUnicode(out_stream, proto_name_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + + ret = SendChar(out_stream, proto_level_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } + + uint8_t connect_flags{0x0}; + connect_flags |= ((clean_session_ ? 0x1 : 0x0) << 1); + connect_flags |= ((will_flag_ ? 0x1 : 0x0) << 2); + connect_flags |= (will_qos_ << 3); + connect_flags |= ((will_retain_ ? 0x1 : 0x0) << 5); + connect_flags |= ((user_name_flag_ ? 0x0 : 0x1) << 6); + connect_flags |= ((password_flag_ ? 0x0 : 0x1) << 7); + ret = SendChar(out_stream, static_cast(connect_flags)); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } + + ret = SendUint16(out_stream, keep_alive_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUint16 err %d", ret); + + return ret; + } + + return ret; +} + +ReturnCode MqttConnect::RecvVariableHeader(istringstream &in_stream) { + ReturnCode ret{RecvUnicode(in_stream, proto_name_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + + if ("MQTT" != proto_name_) { + phxrpc::log(LOG_ERR, "violate mqtt protocol"); + + return ReturnCode::ERROR_VIOLATE_PROTOCOL; + } + + char proto_level{'\0'}; + ret = RecvChar(in_stream, proto_level); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + proto_level_ = proto_level; + + char connect_flags{0x0}; + ret = RecvChar(in_stream, connect_flags); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + clean_session_ = (0x0 != (connect_flags & 0x2)); + will_flag_ = (0x0 != (connect_flags & 0x4)); + will_qos_ = ((connect_flags & 0x8) >> 3); + will_qos_ |= ((connect_flags & 0x10) >> 3); + will_retain_ = (0x0 != (connect_flags & 0x20)); + user_name_flag_ = (0x0 != (connect_flags & 0x40)); + password_flag_ = (0x0 != (connect_flags & 0x80)); + + ret = RecvUint16(in_stream, keep_alive_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUint16 err %d", ret); + + return ret; + } + + return ret; +} + +ReturnCode MqttConnect::SendPayload(ostringstream &out_stream) const { + ReturnCode ret{SendUnicode(out_stream, client_identifier_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + + if (will_flag_) { + ret = SendUnicode(out_stream, will_topic_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + + ret = SendUnicode(out_stream, will_message_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + } + + if (user_name_flag_) { + ret = SendUnicode(out_stream, user_name_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + } + + if (password_flag_) { + ret = SendUnicode(out_stream, password_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + } + + return ret; +} + +ReturnCode MqttConnect::RecvPayload(istringstream &in_stream) { + ReturnCode ret{RecvUnicode(in_stream, client_identifier_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + + if (will_flag_) { + ret = RecvUnicode(in_stream, will_topic_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + + ret = RecvUnicode(in_stream, will_message_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + } + + if (user_name_flag_) { + ret = RecvUnicode(in_stream, user_name_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + } + + if (password_flag_) { + ret = RecvUnicode(in_stream, password_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + } + + return ret; +} + + +MqttConnack::MqttConnack() { + set_protocol(Protocol::MQTT_CONNECT); + mutable_fixed_header().control_packet_type = ControlPacketType::CONNACK; +} + +ReturnCode MqttConnack::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttConnackPb connack; + + connack.set_session_present(session_present_); + connack.set_connect_return_code(connect_return_code_); + + try { + message->CopyFrom(connack); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttConnack::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttConnackPb connack; + + try { + connack.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + session_present_ = connack.session_present(); + connect_return_code_ = connack.connect_return_code(); + + return ReturnCode::OK; +} + +ReturnCode MqttConnack::SendVariableHeader(ostringstream &out_stream) const { + ReturnCode ret{SendChar(out_stream, session_present_ ? 0x1 : 0x0)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } + + ret = SendChar(out_stream, connect_return_code_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } + + return ReturnCode::OK; +} + +ReturnCode MqttConnack::RecvVariableHeader(istringstream &in_stream) { + char connect_acknowledge_flags{0x0}; + ReturnCode ret{RecvChar(in_stream, connect_acknowledge_flags)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + session_present_ = (0x1 == (connect_acknowledge_flags & 0x1)); + + ret = RecvChar(in_stream, connect_return_code_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + + return ReturnCode::OK; +} + + +MqttPublish::MqttPublish() { + set_protocol(Protocol::MQTT_PUBLISH); + SetURI("/phxrpc/mqtt/PhxMqttPublish"); + mutable_fixed_header().control_packet_type = ControlPacketType::PUBLISH; +} + +ReturnCode MqttPublish::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPublishPb publish; + + publish.set_dup(fixed_header().dup); + publish.set_qos(fixed_header().qos); + publish.set_retain(fixed_header().retain); + + publish.set_topic_name(topic_name_); + publish.set_content(GetContent()); + publish.set_packet_identifier(packet_identifier()); + + try { + message->CopyFrom(publish); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttPublish::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttPublishPb publish; + + try { + publish.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + FixedHeader &fixed_header(mutable_fixed_header()); + fixed_header.dup = publish.dup(); + fixed_header.qos = publish.qos(); + fixed_header.retain = publish.retain(); + + topic_name_ = publish.topic_name(); + SetContent(publish.content().data(), publish.content().length()); + set_packet_identifier(publish.packet_identifier()); + + return ReturnCode::OK; +} + +BaseResponse *MqttPublish::GenResponse() const { return new MqttFakeResponse; } + +ReturnCode MqttPublish::SendVariableHeader(ostringstream &out_stream) const { + ReturnCode ret{SendUnicode(out_stream, topic_name_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + + if (0 < fixed_header().qos) { + ret = SendPacketIdentifier(out_stream); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendPacketIdentifier err %d", ret); + + return ret; + } + } + + return ret; +} + +ReturnCode MqttPublish::RecvVariableHeader(istringstream &in_stream) { + ReturnCode ret{RecvUnicode(in_stream, topic_name_)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + + if (0 < fixed_header().qos) { + ret = RecvPacketIdentifier(in_stream); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvPacketIdentifier err %d", ret); + + return ret; + } + } + + return ret; +} + +ReturnCode MqttPublish::SendPayload(ostringstream &out_stream) const { + return SendChars(out_stream, GetContent().data(), GetContent().size()); +} + +ReturnCode MqttPublish::RecvPayload(istringstream &in_stream) { + int variable_header_length{static_cast(topic_name_.length()) + 2}; + if (0 < fixed_header().qos) { + variable_header_length += 2; + } + const int payload_length{remaining_length() - variable_header_length}; + if (0 == payload_length) + return ReturnCode::OK; + if (0 > payload_length) + return ReturnCode::ERROR_LENGTH_UNDERFLOW; + + string &payload_buffer(GetContent()); + payload_buffer.resize(payload_length); + return RecvChars(in_stream, &payload_buffer[0], payload_length); +} + + +MqttPuback::MqttPuback() { + set_protocol(Protocol::MQTT_PUBACK); + SetURI("/phxrpc/mqtt/PhxMqttPuback"); + mutable_fixed_header().control_packet_type = ControlPacketType::PUBACK; +} + +ReturnCode MqttPuback::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPubackPb puback; + + puback.set_packet_identifier(packet_identifier()); + + try { + message->CopyFrom(puback); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttPuback::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttPubackPb puback; + + try { + puback.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + set_packet_identifier(puback.packet_identifier()); + + return ReturnCode::OK; +} + +BaseResponse *MqttPuback::GenResponse() const { return new MqttFakeResponse; } + +ReturnCode MqttPuback::SendVariableHeader(ostringstream &out_stream) const { + return SendPacketIdentifier(out_stream); +} + +ReturnCode MqttPuback::RecvVariableHeader(istringstream &in_stream) { + return RecvPacketIdentifier(in_stream); +} + + +MqttPubrec::MqttPubrec() { + set_protocol(Protocol::MQTT_PUBREC); + SetURI("/phxrpc/mqtt/PhxMqttPubrec"); + mutable_fixed_header().control_packet_type = ControlPacketType::PUBREC; +} + +ReturnCode MqttPubrec::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPubrecPb pubrec; + + try { + message->CopyFrom(pubrec); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttPubrec::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttPubrecPb pubrec; + + try { + pubrec.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +BaseResponse *MqttPubrec::GenResponse() const { return new MqttFakeResponse; } + +ReturnCode MqttPubrec::SendVariableHeader(ostringstream &out_stream) const { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubrec::RecvVariableHeader(istringstream &in_stream) { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubrec::SendPayload(ostringstream &out_stream) const { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubrec::RecvPayload(istringstream &in_stream) { + return ReturnCode::ERROR_UNIMPLEMENT; +} + + +MqttPubrel::MqttPubrel() { + set_protocol(Protocol::MQTT_PUBREL); + SetURI("/phxrpc/mqtt/PhxMqttPubrel"); + mutable_fixed_header().control_packet_type = ControlPacketType::PUBREL; +} + +ReturnCode MqttPubrel::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPubrelPb pubrel; + + try { + message->CopyFrom(pubrel); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttPubrel::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttPubrelPb pubrel; + + try { + pubrel.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +BaseResponse *MqttPubrel::GenResponse() const { return new MqttFakeResponse; } + +ReturnCode MqttPubrel::SendVariableHeader(ostringstream &out_stream) const { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubrel::RecvVariableHeader(istringstream &in_stream) { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubrel::SendPayload(ostringstream &out_stream) const { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubrel::RecvPayload(istringstream &in_stream) { + return ReturnCode::ERROR_UNIMPLEMENT; +} + + +MqttPubcomp::MqttPubcomp() { + set_protocol(Protocol::MQTT_PUBCOMP); + SetURI("/phxrpc/mqtt/PhxMqttPubcomp"); + mutable_fixed_header().control_packet_type = ControlPacketType::PUBCOMP; +} + +ReturnCode MqttPubcomp::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPubcompPb pubcomp; + + try { + message->CopyFrom(pubcomp); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttPubcomp::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttPubcompPb pubcomp; + + try { + pubcomp.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +BaseResponse *MqttPubcomp::GenResponse() const { return new MqttFakeResponse; } + +ReturnCode MqttPubcomp::SendVariableHeader(ostringstream &out_stream) const { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubcomp::RecvVariableHeader(istringstream &in_stream) { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubcomp::SendPayload(ostringstream &out_stream) const { + return ReturnCode::ERROR_UNIMPLEMENT; +} + +ReturnCode MqttPubcomp::RecvPayload(istringstream &in_stream) { + return ReturnCode::ERROR_UNIMPLEMENT; +} + + +MqttSubscribe::MqttSubscribe() { + set_protocol(Protocol::MQTT_SUBSCRIBE); + SetURI("/phxrpc/mqtt/PhxMqttSubscribe"); + mutable_fixed_header().control_packet_type = ControlPacketType::SUBSCRIBE; +} + +ReturnCode MqttSubscribe::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttSubscribePb subscribe; + + subscribe.set_packet_identifier(packet_identifier()); + google::protobuf::RepeatedPtrField temp_topic_filters( + topic_filters_.begin(), topic_filters_.end()); + subscribe.mutable_topic_filters()->Swap(&temp_topic_filters); + google::protobuf::RepeatedField temp_qoss( + qoss_.begin(), qoss_.end()); + subscribe.mutable_qoss()->Swap(&temp_qoss); + + try { + message->CopyFrom(subscribe); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttSubscribe::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttSubscribePb subscribe; + + try { + subscribe.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + set_packet_identifier(subscribe.packet_identifier()); + copy(subscribe.topic_filters().begin(), subscribe.topic_filters().end(), + back_inserter(topic_filters_)); + copy(subscribe.qoss().begin(), subscribe.qoss().end(), + back_inserter(qoss_)); + + return ReturnCode::OK; +} + +BaseResponse *MqttSubscribe::GenResponse() const { return new MqttSuback; } + +ReturnCode MqttSubscribe::SendVariableHeader(ostringstream &out_stream) const { + return SendPacketIdentifier(out_stream); +} + +ReturnCode MqttSubscribe::RecvVariableHeader(istringstream &in_stream) { + return RecvPacketIdentifier(in_stream); +} + +ReturnCode MqttSubscribe::SendPayload(ostringstream &out_stream) const { + for (int i{0}; topic_filters_.size() > i; ++i) { + ReturnCode ret{SendUnicode(out_stream, topic_filters_.at(i))}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + + ret = SendChar(out_stream, 0x0); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } + } + + return ReturnCode::OK; +} + +ReturnCode MqttSubscribe::RecvPayload(istringstream &in_stream) { + const int variable_header_length{2}; + const int payload_length{remaining_length() - variable_header_length}; + if (0 == payload_length) + return ReturnCode::OK; + if (0 > payload_length) + return ReturnCode::ERROR_LENGTH_UNDERFLOW; + + int used_length{0}; + while (used_length < payload_length && EOF != in_stream.peek()) { + string topic_filter; + ReturnCode ret{RecvUnicode(in_stream, topic_filter)}; + if (ReturnCode::ERROR_LENGTH_OVERFLOW == ret) { + return ReturnCode::OK; + } + + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + + char requested_qos{0x0}; + ret = RecvChar(in_stream, requested_qos); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + + topic_filters_.emplace_back(topic_filter); + + used_length += topic_filter.length() + 3; + } + + return ReturnCode::OK; +} + + +MqttSuback::MqttSuback() { + set_protocol(Protocol::MQTT_SUBSCRIBE); + mutable_fixed_header().control_packet_type = ControlPacketType::SUBACK; +} + +ReturnCode MqttSuback::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttSubackPb suback; + + suback.set_packet_identifier(packet_identifier()); + google::protobuf::RepeatedField temp_return_codes( + return_codes_.begin(), return_codes_.end()); + suback.mutable_return_codes()->Swap(&temp_return_codes); + + try { + message->CopyFrom(suback); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttSuback::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttSubackPb suback; + + try { + suback.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + set_packet_identifier(suback.packet_identifier()); + copy(suback.return_codes().begin(), suback.return_codes().end(), + back_inserter(return_codes_)); + + return ReturnCode::OK; +} + +ReturnCode MqttSuback::SendVariableHeader(ostringstream &out_stream) const { + return SendPacketIdentifier(out_stream); +} + +ReturnCode MqttSuback::RecvVariableHeader(istringstream &in_stream) { + return RecvPacketIdentifier(in_stream); +} + +ReturnCode MqttSuback::SendPayload(ostringstream &out_stream) const { + for (int i{0}; return_codes_.size() > i; ++i) { + ReturnCode ret{SendChar(out_stream, return_codes_.at(i))}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } + } + + return ReturnCode::OK; +} + +ReturnCode MqttSuback::RecvPayload(istringstream &in_stream) { + while (EOF != in_stream.peek()) { + char return_code{0x0}; + ReturnCode ret{RecvChar(in_stream, return_code)}; + if (ReturnCode::ERROR_LENGTH_OVERFLOW == ret) { + return ReturnCode::OK; + } + + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + + return_codes_.resize(return_codes_.size() + 1); + return_codes_[return_codes_.size()] = return_code; + } + + return ReturnCode::OK; +} + + +MqttUnsubscribe::MqttUnsubscribe() { + set_protocol(Protocol::MQTT_UNSUBSCRIBE); + SetURI("/phxrpc/mqtt/PhxMqttUnsubscribe"); + mutable_fixed_header().control_packet_type = ControlPacketType::UNSUBSCRIBE; +} + +ReturnCode MqttUnsubscribe::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttUnsubscribePb unsubscribe; + + unsubscribe.set_packet_identifier(packet_identifier()); + google::protobuf::RepeatedPtrField temp_topic_filters( + topic_filters_.begin(), topic_filters_.end()); + unsubscribe.mutable_topic_filters()->Swap(&temp_topic_filters); + + try { + message->CopyFrom(unsubscribe); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttUnsubscribe::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttUnsubscribePb unsubscribe; + + try { + unsubscribe.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + set_packet_identifier(unsubscribe.packet_identifier()); + copy(unsubscribe.topic_filters().begin(), unsubscribe.topic_filters().end(), + back_inserter(topic_filters_)); + + return ReturnCode::OK; +} + +BaseResponse *MqttUnsubscribe::GenResponse() const { return new MqttUnsuback; } + +ReturnCode +MqttUnsubscribe::SendVariableHeader(ostringstream &out_stream) const { + return SendPacketIdentifier(out_stream); +} + +ReturnCode +MqttUnsubscribe::RecvVariableHeader(istringstream &in_stream) { + return RecvPacketIdentifier(in_stream); +} + +ReturnCode +MqttUnsubscribe::SendPayload(ostringstream &out_stream) const { + for (int i{0}; topic_filters_.size() > i; ++i) { + ReturnCode ret{SendUnicode(out_stream, topic_filters_.at(i))}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendUnicode err %d", ret); + + return ret; + } + } + + return ReturnCode::OK; +} + +ReturnCode +MqttUnsubscribe::RecvPayload(istringstream &in_stream) { + const int variable_header_length{2}; + const int payload_length{remaining_length() - variable_header_length}; + if (0 == payload_length) + return ReturnCode::OK; + if (0 > payload_length) + return ReturnCode::ERROR_LENGTH_UNDERFLOW; + + int used_length{0}; + while (used_length < payload_length && EOF != in_stream.peek()){ + string topic_filter; + ReturnCode ret{RecvUnicode(in_stream, topic_filter)}; + if (ReturnCode::ERROR_LENGTH_OVERFLOW == ret) { + return ReturnCode::OK; + } + + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvUnicode err %d", ret); + + return ret; + } + + topic_filters_.emplace_back(topic_filter); + + used_length += topic_filter.length() + 2; + } + + return ReturnCode::OK; +} + + +MqttUnsuback::MqttUnsuback() { + set_protocol(Protocol::MQTT_UNSUBSCRIBE); + mutable_fixed_header().control_packet_type = ControlPacketType::UNSUBACK; +} + +ReturnCode MqttUnsuback::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttUnsubackPb unsuback; + + unsuback.set_packet_identifier(packet_identifier()); + + try { + message->CopyFrom(unsuback); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttUnsuback::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttUnsubackPb unsuback; + + try { + unsuback.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + set_packet_identifier(unsuback.packet_identifier()); + + return ReturnCode::OK; +} + +ReturnCode MqttUnsuback::SendVariableHeader(ostringstream &out_stream) const { + return SendPacketIdentifier(out_stream); +} + +ReturnCode MqttUnsuback::RecvVariableHeader(istringstream &in_stream) { + return RecvPacketIdentifier(in_stream); +} + + +MqttPingreq::MqttPingreq() { + set_protocol(Protocol::MQTT_PING); + SetURI("/phxrpc/mqtt/PhxMqttPing"); + mutable_fixed_header().control_packet_type = ControlPacketType::PINGREQ; +} + +ReturnCode MqttPingreq::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPingreqPb pingreq; + + try { + message->CopyFrom(pingreq); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttPingreq::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttPingreqPb pingreq; + + try { + pingreq.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +BaseResponse *MqttPingreq::GenResponse() const { return new MqttPingresp; } + + +MqttPingresp::MqttPingresp() { + set_protocol(Protocol::MQTT_PING); + mutable_fixed_header().control_packet_type = ControlPacketType::PINGRESP; +} + +ReturnCode MqttPingresp::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPingrespPb pingresp; + + try { + message->CopyFrom(pingresp); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttPingresp::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttPingrespPb pingresp; + + try { + pingresp.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + + +MqttDisconnect::MqttDisconnect() { + set_protocol(Protocol::MQTT_DISCONNECT); + SetURI("/phxrpc/mqtt/PhxMqttDisconnect"); + mutable_fixed_header().control_packet_type = ControlPacketType::DISCONNECT; +} + +ReturnCode MqttDisconnect::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttDisconnectPb disconnect; + + try { + message->CopyFrom(disconnect); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +ReturnCode MqttDisconnect::FromPb(const google::protobuf::Message &message) { + phxrpc::MqttDisconnectPb disconnect; + + try { + disconnect.CopyFrom(message); + } catch (exception) { + return ReturnCode::ERROR; + } + + return ReturnCode::OK; +} + +BaseResponse *MqttDisconnect::GenResponse() const { return new MqttFakeResponse; } + + +} // namespace phxrpc + diff --git a/phxrpc/mqtt/mqtt_msg.h b/phxrpc/mqtt/mqtt_msg.h new file mode 100644 index 0000000..acd2242 --- /dev/null +++ b/phxrpc/mqtt/mqtt_msg.h @@ -0,0 +1,596 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include +#include + +#include "phxrpc/msg.h" + + +namespace phxrpc { + + +class MqttMessage : virtual public BaseMessage { + public: + enum class ControlPacketType { + FAKE_NONE = 0, + CONNECT = 1, + CONNACK, + PUBLISH, + PUBACK, + PUBREC, + PUBREL, + PUBCOMP, + SUBSCRIBE, + SUBACK, + UNSUBSCRIBE, + UNSUBACK, + PINGREQ, + PINGRESP, + DISCONNECT, + FAKE_MAX, + }; + + struct FixedHeader { + ControlPacketType control_packet_type{ControlPacketType::FAKE_NONE}; + bool dup{0}; + uint32_t qos{0}; + bool retain{0}; + }; + + static const char SampleFixedHeader[]; + + static int EncodeUint16(std::string &dest, const uint16_t src); + static int EncodeUint16(char *const dest, const size_t dest_size, + const uint16_t src); + static int EncodeUnicode(std::string &dest, const std::string &src); + static int EncodeUnicode(char *const dest, const size_t dest_size, + const std::string &src); + + static ReturnCode SendChar(std::ostringstream &out_stream, const char &content); + static ReturnCode RecvChar(std::istringstream &in_stream, char &content); + static ReturnCode SendUint16(std::ostringstream &out_stream, + const uint16_t content); + static ReturnCode RecvUint16(std::istringstream &in_stream, + uint16_t &content); + static ReturnCode SendChars(std::ostringstream &out_stream, + const char *const content, + const int content_length); + static ReturnCode RecvChars(std::istringstream &in_stream, + char *const content, + const int content_length); + static ReturnCode SendUnicode(std::ostringstream &out_stream, + const std::string &content); + static ReturnCode RecvUnicode(std::istringstream &in_stream, + std::string &content); + + static ReturnCode SendChar(BaseTcpStream &out_stream, const char &content); + static ReturnCode RecvChar(BaseTcpStream &in_stream, char &content); + static ReturnCode SendUint16(BaseTcpStream &out_stream, + const uint16_t content); + static ReturnCode RecvUint16(BaseTcpStream &in_stream, uint16_t &content); + static ReturnCode SendChars(BaseTcpStream &out_stream, + const char *const content, + const int content_length); + static ReturnCode RecvChars(BaseTcpStream &in_stream, + char *const content, + const int content_length); + static ReturnCode SendUnicode(BaseTcpStream &out_stream, + const std::string &content); + static ReturnCode RecvUnicode(BaseTcpStream &in_stream, + std::string &content); + + static uint8_t EncodeFixedHeader(const FixedHeader &fixed_header); + static FixedHeader DecodeFixedHeader(const uint8_t fixed_header_byte); + + // control packet type and flags + static ReturnCode SendFixedHeaderAndRemainingBuffer( + BaseTcpStream &out_stream, + const FixedHeader &fixed_header, + const std::string &remaining_buffer); + static ReturnCode RecvFixedHeaderAndRemainingBuffer( + BaseTcpStream &in_stream, + FixedHeader &fixed_header, + std::string &remaining_buffer); + + // remaining length + static ReturnCode SendRemainingLength(BaseTcpStream &out_stream, + const int remaining_length); + static ReturnCode RecvRemainingLength(BaseTcpStream &in_stream, + int &remaining_length); + + MqttMessage(); + virtual ~MqttMessage() override; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const = 0; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) = 0; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const = 0; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) = 0; + + virtual ReturnCode Send(BaseTcpStream &socket) const override; + + ReturnCode SendRemaining(std::ostringstream &out_stream) const; + ReturnCode RecvRemaining(std::istringstream &in_stream); + + // packet identifier + ReturnCode SendPacketIdentifier(std::ostringstream &out_stream) const; + ReturnCode RecvPacketIdentifier(std::istringstream &in_stream); + + FixedHeader fixed_header() const { return fixed_header_; } + + void set_fixed_header(const FixedHeader fixed_header) { + fixed_header_ = fixed_header; + } + + FixedHeader &mutable_fixed_header() { + return fixed_header_; + } + + uint16_t packet_identifier() const { return packet_identifier_; } + + void set_packet_identifier(const uint16_t packet_identifier) { + packet_identifier_ = packet_identifier; + } + + int remaining_length() const { return remaining_length_; } + + void set_remaining_length(const int remaining_length) { + remaining_length_ = remaining_length; + } + + private: + FixedHeader fixed_header_; + uint16_t packet_identifier_{0x0}; + int remaining_length_{0}; +}; + + +class MqttRequest : public virtual MqttMessage, public BaseRequest { + public: + MqttRequest() = default; + virtual ~MqttRequest() = default; + + private: +}; + + +class MqttResponse : public virtual MqttMessage, public BaseResponse { + public: + MqttResponse() = default; + virtual ~MqttResponse() = default; + + virtual void SetPhxRpcResult(const int result) override {} + virtual void DispatchErr() override {} + + virtual ReturnCode ModifyResp(const bool keep_alive, const std::string &version) override; + + private: +}; + + +class MqttFakeResponse final : public MqttResponse { + public: + MqttFakeResponse(); + virtual ~MqttFakeResponse() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override { + return ReturnCode::ERROR_UNIMPLEMENT; + } + + virtual ReturnCode FromPb(const google::protobuf::Message &message) override { + return ReturnCode::ERROR_UNIMPLEMENT; + } + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override { + return ReturnCode::OK; + } + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override { + return ReturnCode::OK; + } +}; + + +class MqttConnect final : public MqttRequest { + public: + MqttConnect(); + virtual ~MqttConnect() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; + + bool clean_session() const { return clean_session_; } + void set_clean_session(const bool clean_session) { + clean_session_ = clean_session; + } + + uint16_t keep_alive() const { return keep_alive_; } + void set_keep_alive(const uint16_t keep_alive) { + keep_alive_ = keep_alive; + } + + const std::string &client_identifier() const { return client_identifier_; } + void set_client_identifier(const std::string &client_identifier) { + client_identifier_ = client_identifier; + } + + // read only + const std::string &proto_name() const { return proto_name_; } + + // read only + uint8_t proto_level() const { return proto_level_; } + + private: + std::string client_identifier_; + std::string proto_name_{"MQTT"}; + uint8_t proto_level_{4}; + bool clean_session_{false}; + uint16_t keep_alive_{0}; + bool user_name_flag_{false}; + bool password_flag_{false}; + std::string user_name_; + std::string password_; + bool will_flag_{false}; + uint32_t will_qos_{0}; + bool will_retain_{false}; + std::string will_topic_; + std::string will_message_; +}; + + +class MqttConnack final : public MqttResponse { + public: + MqttConnack(); + virtual ~MqttConnack() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override { + return ReturnCode::OK; + } + + bool session_present() const { return session_present_; } + void set_session_present(const bool session_present) { + session_present_ = session_present; + } + + char connect_return_code() const { return connect_return_code_; } + void set_connect_return_code(const char connect_return_code) { + connect_return_code_ = connect_return_code; + } + + private: + bool session_present_{0}; + char connect_return_code_{0}; +}; + + +class MqttPublish final : public virtual MqttRequest, public virtual MqttResponse { + public: + MqttPublish(); + virtual ~MqttPublish() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; + + const std::string &topic_name() const { return topic_name_; } + void set_topic_name(const std::string &topic_name) { + topic_name_ = topic_name; + } + + private: + std::string topic_name_; +}; + + +class MqttPuback final : public virtual MqttRequest, public virtual MqttResponse { + public: + MqttPuback(); + virtual ~MqttPuback() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override { + return ReturnCode::OK; + } +}; + + +class MqttPubrec final : public virtual MqttRequest, public virtual MqttResponse { + public: + MqttPubrec(); + virtual ~MqttPubrec() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; +}; + + +class MqttPubrel final : public virtual MqttRequest, public virtual MqttResponse { + public: + MqttPubrel(); + virtual ~MqttPubrel() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; +}; + + +class MqttPubcomp final : public virtual MqttRequest, public virtual MqttResponse { + public: + MqttPubcomp(); + virtual ~MqttPubcomp() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; +}; + + +class MqttSubscribe final : public MqttRequest { + public: + MqttSubscribe(); + virtual ~MqttSubscribe() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; + + const std::vector &topic_filters() const { + return topic_filters_; + } + void set_topic_filters(const std::vector &topic_filters) { + topic_filters_ = topic_filters; + } + + private: + std::vector topic_filters_; + std::vector qoss_; +}; + + +class MqttSuback final : public MqttResponse { + public: + MqttSuback(); + virtual ~MqttSuback() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; + + const std::string &return_codes() const { return return_codes_; } + void set_return_codes(const std::string &return_codes) { + return_codes_ = return_codes; + } + + private: + std::string return_codes_; +}; + + +class MqttUnsubscribe final : public MqttRequest { + public: + MqttUnsubscribe(); + virtual ~MqttUnsubscribe() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override; + + const std::vector &topic_filters() const { + return topic_filters_; + } + void set_topic_filters(const std::vector &topic_filters) { + topic_filters_ = topic_filters; + } + + private: + std::vector topic_filters_; +}; + + +class MqttUnsuback final : public MqttResponse { + public: + MqttUnsuback(); + virtual ~MqttUnsuback() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override; + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override; + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override { + return ReturnCode::OK; + } +}; + + +class MqttPingreq final : public MqttRequest { + public: + MqttPingreq(); + virtual ~MqttPingreq() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override { + return ReturnCode::OK; + } + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override { + return ReturnCode::OK; + } +}; + + +class MqttPingresp final : public MqttResponse { + public: + MqttPingresp(); + virtual ~MqttPingresp() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override { + return ReturnCode::OK; + } + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override { + return ReturnCode::OK; + } +}; + + +class MqttDisconnect final : public MqttRequest { + public: + MqttDisconnect(); + virtual ~MqttDisconnect() = default; + + virtual ReturnCode ToPb(google::protobuf::Message *const message) const override; + virtual ReturnCode FromPb(const google::protobuf::Message &message) override; + + virtual BaseResponse *GenResponse() const override; + virtual int IsKeepAlive() const override { return 1; }; + + virtual ReturnCode SendVariableHeader(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvVariableHeader(std::istringstream &in_stream) override { + return ReturnCode::OK; + } + + virtual ReturnCode SendPayload(std::ostringstream &out_stream) const override { + return ReturnCode::OK; + } + virtual ReturnCode RecvPayload(std::istringstream &in_stream) override { + return ReturnCode::OK; + } +}; + + +} // namespace phxrpc + diff --git a/phxrpc/mqtt/mqtt_protocol.cpp b/phxrpc/mqtt/mqtt_protocol.cpp new file mode 100644 index 0000000..9ca478e --- /dev/null +++ b/phxrpc/mqtt/mqtt_protocol.cpp @@ -0,0 +1,174 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "mqtt_protocol.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "mqtt_msg.h" + +#include "phxrpc/file/log_utils.h" +#include "phxrpc/network/socket_stream_base.h" + + +namespace phxrpc { + + +using namespace std; + + +// client send +ReturnCode MqttProtocol::SendMessage(BaseTcpStream &socket, + const MqttMessage *const msg) { + ostringstream ss; + ReturnCode ret{msg->SendRemaining(ss)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendRemaining err %d", ret); + + return ret; + } + + ret = MqttMessage::SendFixedHeaderAndRemainingBuffer(socket, + msg->fixed_header(), ss.str()); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendFixedHeaderAndRemainingBuffer err %d", ret); + + return ret; + } + + if (!socket.flush().good()) { + phxrpc::log(LOG_ERR, "socket err %d", socket.LastError()); + + return static_cast(socket.LastError()); + } + + return ret; +} + +// client receive +ReturnCode MqttProtocol::RecvMessage(BaseTcpStream &socket, + MqttMessage *const msg) { + MqttMessage::FixedHeader fixed_header; + string remaining_buffer; + ReturnCode ret{MqttMessage::RecvFixedHeaderAndRemainingBuffer(socket, + fixed_header, remaining_buffer)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvFixedHeaderAndRemainingBuffer err %d", ret); + + return ret; + } + + istringstream ss(remaining_buffer); + + if (msg->fixed_header().control_packet_type == + fixed_header.control_packet_type) { + msg->set_fixed_header(fixed_header); + msg->set_remaining_length(remaining_buffer.size()); + return msg->RecvRemaining(ss); + } + phxrpc::log(LOG_ERR, "msg_type %d != recv_type %d", + static_cast(msg->fixed_header().control_packet_type), + static_cast(fixed_header.control_packet_type)); + + return ReturnCode::ERROR; +} + +// server receive +ReturnCode MqttProtocol::ServerRecv(BaseTcpStream &socket, BaseRequest *&req) { + MqttMessage::FixedHeader fixed_header; + string remaining_buffer; + ReturnCode ret{MqttMessage::RecvFixedHeaderAndRemainingBuffer(socket, + fixed_header, remaining_buffer)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvFixedHeaderAndRemainingBuffer err %d", ret); + + return ret; + } + + istringstream ss(remaining_buffer); + + if (MqttMessage::ControlPacketType::CONNECT == + fixed_header.control_packet_type) { + MqttConnect *connect{new MqttConnect}; + connect->set_fixed_header(fixed_header); + connect->set_remaining_length(remaining_buffer.size()); + // TODO: remove + phxrpc::log(LOG_ERR, "remaining_length %zu", remaining_buffer.size()); + req = connect; + return connect->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::PUBLISH == + fixed_header.control_packet_type) { + MqttPublish *publish{new MqttPublish}; + publish->set_fixed_header(fixed_header); + publish->set_remaining_length(remaining_buffer.size()); + req = publish; + return publish->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::PUBACK == + fixed_header.control_packet_type) { + MqttPuback *puback{new MqttPuback}; + puback->set_fixed_header(fixed_header); + puback->set_remaining_length(remaining_buffer.size()); + req = puback; + return puback->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::SUBSCRIBE == + fixed_header.control_packet_type) { + MqttSubscribe *subscribe{new MqttSubscribe}; + subscribe->set_fixed_header(fixed_header); + subscribe->set_remaining_length(remaining_buffer.size()); + req = subscribe; + return subscribe->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::UNSUBSCRIBE == + fixed_header.control_packet_type) { + MqttUnsubscribe *unsubscribe{new MqttUnsubscribe}; + unsubscribe->set_fixed_header(fixed_header); + unsubscribe->set_remaining_length(remaining_buffer.size()); + req = unsubscribe; + return unsubscribe->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::PINGREQ == + fixed_header.control_packet_type) { + MqttPingreq *pingreq{new MqttPingreq}; + pingreq->set_fixed_header(fixed_header); + pingreq->set_remaining_length(remaining_buffer.size()); + req = pingreq; + return pingreq->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::DISCONNECT == + fixed_header.control_packet_type) { + MqttDisconnect *disconnect{new MqttDisconnect}; + disconnect->set_fixed_header(fixed_header); + disconnect->set_remaining_length(remaining_buffer.size()); + req = disconnect; + return disconnect->RecvRemaining(ss); + } + phxrpc::log(LOG_ERR, "type %d not supported", + static_cast(fixed_header.control_packet_type)); + + return ReturnCode::ERROR; +} + + +} // namespace phxrpc + diff --git a/phxrpc/mqtt/mqtt_protocol.h b/phxrpc/mqtt/mqtt_protocol.h new file mode 100644 index 0000000..410b1fd --- /dev/null +++ b/phxrpc/mqtt/mqtt_protocol.h @@ -0,0 +1,55 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "phxrpc/msg/base_protocol.h" + + +namespace phxrpc { + + +enum class ReturnCode; + +class BaseTcpStream; + +class MqttMessage; + +class MqttProtocol : public BaseProtocol { + public: + MqttProtocol() = default; + virtual ~MqttProtocol() override = default; + + // client send + static ReturnCode SendMessage(BaseTcpStream &socket, + const MqttMessage *const msg); + // client receive + static ReturnCode RecvMessage(BaseTcpStream &socket, + MqttMessage *const msg); + + // server receive + virtual ReturnCode ServerRecv(BaseTcpStream &socket, + BaseRequest *&req) override; +}; + + +} + diff --git a/phxrpc/mqtt/test_mqtt_client b/phxrpc/mqtt/test_mqtt_client new file mode 100755 index 0000000..256435c Binary files /dev/null and b/phxrpc/mqtt/test_mqtt_client differ diff --git a/phxrpc/mqtt/test_mqtt_client.cpp b/phxrpc/mqtt/test_mqtt_client.cpp new file mode 100644 index 0000000..a2d3230 --- /dev/null +++ b/phxrpc/mqtt/test_mqtt_client.cpp @@ -0,0 +1,146 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include +#include +#include +#include +#include +#include + +#include "mqtt_msg.h" +#include "mqtt_client.h" + +#include "phxrpc/file/file_utils.h" +#include "phxrpc/file/opt_map.h" +#include "phxrpc/network/socket_stream_block.h" + + +using namespace phxrpc; +using namespace std; + + +void ShowUsage(const char *program) { + printf("\n%s [-h host] [-p port] [-r CONNECT|PUBLISH|SUBSCRIBE|UNSUBSCRIBE|PING|DISCONNECT] [-f file] [-v]\n", program); + + printf("\t-h mqtt host\n"); + printf("\t-p mqtt port\n"); + printf("\t-r mqtt method, only support CONNECT|PUBLISH|SUBSCRIBE|UNSUBSCRIBE|PING|DISCONNECT\n"); + printf("\t-f the file for content\n"); + printf("\t-v show this usage\n"); + printf("\n"); + + exit(0); +} + +int main(int argc, char *argv[]) { + assert(sigset(SIGPIPE, SIG_IGN) != SIG_ERR); + + OptMap optMap("h:p:r:f:v"); + + if ((!optMap.Parse(argc, argv)) || optMap.Has('v')) + ShowUsage(argv[0]); + + int port{0}; + const char *host{optMap.Get('h')}; + const char *method{optMap.Get('r')}; + const char *file{optMap.Get('f')}; + + if ((nullptr == host) || (!optMap.GetInt('p', &port))) { + printf("\nPlease specify host and port!\n"); + ShowUsage(argv[0]); + } + + if (nullptr == method) { + printf("\nPlease specify method!\n"); + ShowUsage(argv[0]); + } + + BlockTcpStream socket; + if (!BlockTcpUtils::Open(&socket, host, port, 100, nullptr, 0)) { + printf("Connect %s:%d fail\n", host, port); + exit(-1); + } + + int ret{0}; + + if (0 == strcasecmp(method, "CONNECT")) { + MqttConnect req; + MqttConnack resp; + ret = MqttClient::Connect(socket, req, resp); + if (0 == ret) { + printf("mqtt connect ret %d connect_return_code %d\n", + ret, resp.connect_return_code()); + } else { + printf("mqtt connect fail ret %d\n", ret); + } + } else if (0 == strcasecmp(method, "PUBLISH")) { + MqttPublish req; + MqttPuback resp; + ret = MqttClient::Publish(socket, req, resp); + if (0 == ret) { + printf("mqtt publish ret %d packet_identifier %u\n", + ret, resp.packet_identifier()); + } else { + printf("mqtt publish fail ret %d\n", ret); + } + } else if (0 == strcasecmp(method, "SUBSCRIBE")) { + MqttSubscribe req; + MqttSuback resp; + ret = MqttClient::Subscribe(socket, req, resp); + if (0 == ret) { + printf("mqtt subscribe ret %d\n", ret); + } else { + printf("mqtt subscribe fail ret %d\n", ret); + } + } else if (0 == strcasecmp(method, "UNSUBSCRIBE")) { + MqttUnsubscribe req; + MqttUnsuback resp; + ret = MqttClient::Unsubscribe(socket, req, resp); + if (0 == ret) { + printf("mqtt unsubscribe ret %d\n", ret); + } else { + printf("mqtt unsubscribe fail ret %d\n", ret); + } + } else if (0 == strcasecmp(method, "PING")) { + MqttPingreq req; + MqttPingresp resp; + ret = MqttClient::Ping(socket, req, resp); + if (0 == ret) { + printf("mqtt ping ret %d\n", ret); + } else { + printf("mqtt ping fail ret %d\n", ret); + } + } else if (0 == strcasecmp(method, "DISCONNECT")) { + MqttDisconnect req; + ret = MqttClient::Disconnect(socket, req); + if (0 == ret) { + printf("mqtt disconnect ret %d\n", ret); + } else { + printf("mqtt disconnect fail ret %d\n", ret); + } + } else { + printf("unsupport method %s\n", method); + } + + return 0; +} + diff --git a/phxrpc/mqtt/test_mqtt_protocol.cpp b/phxrpc/mqtt/test_mqtt_protocol.cpp new file mode 100644 index 0000000..6afd5e4 --- /dev/null +++ b/phxrpc/mqtt/test_mqtt_protocol.cpp @@ -0,0 +1,155 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "mqtt_msg.h" +#include "mqtt_protocol.h" + +#include "phxrpc/file/file_utils.h" +#include "phxrpc/file/opt_map.h" +#include "phxrpc/network/socket_stream_block.h" + + +using namespace phxrpc; +using namespace std; + + +void ShowUsage(const char *program) { + printf("\n%s [-r CONNECT|PUBLISH|SUBSCRIBE|UNSUBSCRIBE|PING|DISCONNECT] [-f file] [-v]\n", program); + + printf("\t-r mqtt method, CONNECT|PUBLISH|SUBSCRIBE|UNSUBSCRIBE|PING|DISCONNECT\n"); + printf("\t-f the file for content\n"); + printf("\t-v show this usage\n"); + printf("\n"); + + exit(0); +} + +void TraceMsg(const MqttMessage &msg) { + ostringstream ss_req; + msg.SendRemaining(ss_req); + const string &s_req(ss_req.str()); + cout << s_req.size() << ":" << endl; + for (int i{0}; s_req.size() > i; ++i) { + cout << static_cast(s_req.data()[i]) << "\t"; + } + cout << endl; + for (int i{0}; s_req.size() > i; ++i) { + if (isalnum(s_req.data()[i]) || '_' == s_req.data()[i]) + cout << s_req.data()[i] << "\t"; + else + cout << '.' << "\t"; + } + cout << endl; +} + +int main(int argc, char *argv[]) { + assert(sigset(SIGPIPE, SIG_IGN) != SIG_ERR); + + OptMap optMap("r:f:v"); + + if ((!optMap.Parse(argc, argv)) || optMap.Has('v')) + ShowUsage(argv[0]); + + const char *method{optMap.Get('r')}; + const char *file{optMap.Get('f')}; + + if (nullptr == method) { + printf("\nPlease specify method!\n"); + ShowUsage(argv[0]); + } + + int ret{0}; + + if (0 == strcasecmp(method, "CONNECT")) { + cout << "Req:" << endl; + MqttConnect connect; + connect.set_client_identifier("test_client_1"); + TraceMsg(connect); + + cout << "Resp:" << endl; + TraceMsg(MqttConnack()); + } else if (0 == strcasecmp(method, "PUBLISH")) { + cout << "Req:" << endl; + MqttPublish publish; + publish.set_topic_name("test_topic_1"); + string content{"test_msg_1"}; + publish.SetContent(content.c_str(), content.length()); + publish.set_packet_identifier(11); + TraceMsg(publish); + + cout << "Resp:" << endl; + MqttPuback puback; + puback.set_packet_identifier(11); + TraceMsg(puback); + } else if (0 == strcasecmp(method, "SUBSCRIBE")) { + cout << "Req:" << endl; + TraceMsg(MqttSubscribe()); + cout << "Resp:" << endl; + TraceMsg(MqttSuback()); + } else if (0 == strcasecmp(method, "UNSUBSCRIBE")) { + cout << "Req:" << endl; + TraceMsg(MqttUnsubscribe()); + cout << "Resp:" << endl; + TraceMsg(MqttUnsuback()); + } else if (0 == strcasecmp(method, "PING")) { + cout << "Req:" << endl; + TraceMsg(MqttPingreq()); + cout << "Resp:" << endl; + TraceMsg(MqttPingresp()); + } else if (0 == strcasecmp(method, "DISCONNECT")) { + cout << "Req:" << endl; + TraceMsg(MqttDisconnect()); + } else { + printf("unsupport method %s\n", method); + } + + //if (0 == ret) { + // printf("response:\n"); + + // printf("%s %d %s\n", response.GetVersion(), response.GetStatusCode(), + // response.GetReasonPhrase()); + + // printf("%zu headers\n", response.GetHeaderCount()); + // for (size_t i{0}; i < response.GetHeaderCount(); ++i) { + // const char *name{response.GetHeaderName(i)}; + // const char *val{response.GetHeaderValue(i)}; + // printf("%s: %s\r\n", name, val); + // } + + // printf("%zu bytes body\n", response.GetContent().size()); + // if (response.GetContent().size() > 0) { + // //printf("%s\n", (char*)response.getContent()); + // } + //} else { + // printf("mqtt request fail\n"); + //} + + return 0; +} + diff --git a/phxrpc/msg.h b/phxrpc/msg.h new file mode 100644 index 0000000..b734b41 --- /dev/null +++ b/phxrpc/msg.h @@ -0,0 +1,29 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "msg/base_dispatcher.h" +#include "msg/base_msg.h" +#include "msg/base_protocol.h" +#include "msg/common.h" +#include "msg/protocol_factory.h" + diff --git a/phxrpc/msg/base_dispatcher.h b/phxrpc/msg/base_dispatcher.h new file mode 100644 index 0000000..13de949 --- /dev/null +++ b/phxrpc/msg/base_dispatcher.h @@ -0,0 +1,67 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include +#include + +#include "phxrpc/msg/base_msg.h" + + +namespace phxrpc { + + +template +class BaseDispatcher { + public: + typedef int (Dispatcher::*URIFunc_t)(const BaseRequest *const req, + BaseResponse *const resp); + + typedef std::map URIFuncMap; + + BaseDispatcher(Dispatcher &dispatcher, const URIFuncMap &uri_func_map) + : dispatcher_(dispatcher), uri_func_map_(uri_func_map) { + } + + virtual ~BaseDispatcher() = default; + + bool Dispatch(const BaseRequest *const req, BaseResponse *const resp) { + int ret{-1}; + typename URIFuncMap::const_iterator iter(uri_func_map_.find(req->GetURI())); + + if (uri_func_map_.end() != iter) { + ret = (dispatcher_.*iter->second)(req, resp); + } + + resp->SetPhxRpcResult(ret); + + return uri_func_map_.end() != iter; + } + + private: + Dispatcher &dispatcher_; + const URIFuncMap &uri_func_map_; +}; + + +} // namespace phxrpc + diff --git a/phxrpc/msg/base_msg.cpp b/phxrpc/msg/base_msg.cpp new file mode 100644 index 0000000..b62c5a6 --- /dev/null +++ b/phxrpc/msg/base_msg.cpp @@ -0,0 +1,112 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include +#include +#include + +#include "base_msg.h" + + +namespace phxrpc { + + +using namespace std; + + +BaseMessage::BaseMessage() { +} + +BaseMessage::~BaseMessage() { +} + +void BaseMessage::SetVersion(const char *version) { + snprintf(version_, sizeof(version_), "%s", version); +} + +const char *BaseMessage::GetVersion() const { + return version_; +} + +void BaseMessage::SetClientIP(const char *client_ip) { + if (client_ip != nullptr) { + snprintf(client_ip_, sizeof(client_ip_), "%s", client_ip); + } +} + +const char *BaseMessage::GetClientIP() const { + return client_ip_; +} + +void BaseMessage::AppendContent(const void *content, const int length, const int max_length) { + int valid_length{length}; + if (valid_length <= 0) + valid_length = strlen((char *)content); + + int total = content_.size() + valid_length; + total = total > max_length ? total : max_length; + + //content_.reserve(total); + + content_.append((char *) content, valid_length); +} + +void BaseMessage::SetContent(const void *content, const int length) { + content_.clear(); + content_.append((char *)content, length); +} + +const string &BaseMessage::GetContent() const { + return content_; +} + +string &BaseMessage::GetContent() { + return content_; +} + + +BaseRequest::BaseRequest() { + set_direction(BaseMessage::Direction::REQUEST); +} + +BaseRequest::~BaseRequest() { +} + +void BaseRequest::SetURI(const char *uri) { + if (nullptr != uri) { + uri_ = string(uri); + } +} + +const char *BaseRequest::GetURI() const { + return uri_.c_str(); +} + + +BaseResponse::BaseResponse() { + set_direction(BaseMessage::Direction::RESPONSE); +} + +BaseResponse::~BaseResponse() {} + + +} + diff --git a/phxrpc/msg/base_msg.h b/phxrpc/msg/base_msg.h new file mode 100644 index 0000000..c1a8474 --- /dev/null +++ b/phxrpc/msg/base_msg.h @@ -0,0 +1,142 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include +#include + +#include "phxrpc/network.h" + +#include "common.h" + + +namespace google { + +namespace protobuf { + +class Message; + +} // protobuf + +} // google + + +namespace phxrpc { + + +class BaseMessage { + public: + enum class Direction { + NONE = 0, + REQUEST, + RESPONSE, + MAX, + }; + + enum class Protocol { + NONE = 0, + HTTP_GET = 101, + HTTP_POST = 102, + HTTP_HEAD = 103, + MQTT_FAKE_NONE = 200, + MQTT_CONNECT = 201, + MQTT_PUBLISH = 202, + MQTT_PUBACK = 203, + MQTT_PUBREC = 204, + MQTT_PUBREL = 205, + MQTT_PUBCOMP = 206, + MQTT_SUBSCRIBE = 207, + MQTT_UNSUBSCRIBE = 208, + MQTT_PING = 209, + MQTT_DISCONNECT = 210, + MAX, + }; + + BaseMessage(); + virtual ~BaseMessage(); + + virtual ReturnCode Send(BaseTcpStream &socket) const = 0; + virtual ReturnCode ToPb(google::protobuf::Message *const message) const = 0; + virtual ReturnCode FromPb(const google::protobuf::Message &message) = 0; + + void SetVersion(const char *version); + const char *GetVersion() const; + + void SetClientIP(const char *client_ip); + const char *GetClientIP() const; + + void AppendContent(const void *content, const int length = 0, const int max_length = 0); + void SetContent(const void *content, const int length = 0); + const std::string &GetContent() const; + std::string &GetContent(); + + Direction direction() const { return direction_; } + Protocol protocol() const { return protocol_; } + bool fake() const { return fake_; }; + + protected: + void set_direction(const Direction direction) { direction_ = direction; } + void set_protocol(const Protocol protocol) { protocol_ = protocol; } + void set_fake(const bool fake) { fake_ = fake; } + + char client_ip_[16]; + + private: + Direction direction_{Direction::NONE}; + Protocol protocol_{Protocol::NONE}; + char version_[16]; + std::string content_; + bool fake_{false}; +}; + + +class BaseResponse; + +class BaseRequest : virtual public BaseMessage { + public: + BaseRequest(); + virtual ~BaseRequest() override; + + void SetURI(const char *uri); + const char *GetURI() const; + + virtual BaseResponse *GenResponse() const = 0; + virtual int IsKeepAlive() const = 0; + + private: + std::string uri_; +}; + + +class BaseResponse : virtual public BaseMessage { + public: + BaseResponse(); + virtual ~BaseResponse() override; + + virtual void SetPhxRpcResult(const int result) = 0; + virtual void DispatchErr() = 0; + virtual ReturnCode ModifyResp(const bool keep_alive, const std::string &version) = 0; +}; + + +} + diff --git a/phxrpc/msg/base_protocol.cpp b/phxrpc/msg/base_protocol.cpp new file mode 100644 index 0000000..b10d23f --- /dev/null +++ b/phxrpc/msg/base_protocol.cpp @@ -0,0 +1,38 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "base_protocol.h" + +#include +#include +#include +#include +#include +#include + +#include "phxrpc/file/log_utils.h" + + +namespace phxrpc { + + +} + diff --git a/phxrpc/msg/base_protocol.h b/phxrpc/msg/base_protocol.h new file mode 100644 index 0000000..a5659ac --- /dev/null +++ b/phxrpc/msg/base_protocol.h @@ -0,0 +1,42 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "base_msg.h" + +#include "phxrpc/network.h" + + +namespace phxrpc { + + +class BaseProtocol { + public: + BaseProtocol() = default; + virtual ~BaseProtocol() = default; + + virtual ReturnCode ServerRecv(BaseTcpStream &socket, BaseRequest *&req) = 0; +}; + + +} + diff --git a/phxrpc/msg/common.h b/phxrpc/msg/common.h new file mode 100644 index 0000000..d3a1618 --- /dev/null +++ b/phxrpc/msg/common.h @@ -0,0 +1,67 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + + +namespace phxrpc { + + +enum class ReturnCode { + OK = 0, + ERROR = -1, + ERROR_UNIMPLEMENT = -101, + ERROR_STEAM_BAD_OR_FAILED = -102, + ERROR_LENGTH_UNDERFLOW = -103, + ERROR_LENGTH_OVERFLOW = -104, + ERROR_SOCKET_STREAM_TIMEOUT = -202, + ERROR_SOCKET_STREAM_NORMAL_CLOSED = -303, + ERROR_VIOLATE_PROTOCOL = -401, + MAX, +}; + + +enum class Direction { + NONE = 0, + REQUEST, + RESPONSE, + MAX, +}; + +enum class Protocol { + NONE = 0, + HTTP_GET = 101, + HTTP_POST = 102, + HTTP_HEAD = 103, + MQTT_CONNECT = 201, + MQTT_PUBLISH = 202, + MQTT_PUBREL = 203, + MQTT_SUBSCRIBE = 204, + MQTT_UNSUBSCRIBE = 205, + MQTT_PING = 206, + MQTT_DISCONNECT = 207, + MQTT_FAKE_DISCONNACK = 208, + MAX, +}; + + +} + diff --git a/phxrpc/msg/protocol_factory.cpp b/phxrpc/msg/protocol_factory.cpp new file mode 100644 index 0000000..51512f3 --- /dev/null +++ b/phxrpc/msg/protocol_factory.cpp @@ -0,0 +1,48 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "phxrpc/http.h" +#include "phxrpc/mqtt.h" + + +namespace phxrpc { + + +BaseProtocolFactory *BaseProtocolFactory::CreateFactory(UThreadTcpStream &in_stream) { + char c{static_cast(in_stream.peek())}; + if ('P' == c || 'G' == c || 'H' == c) { // look for POST GET HEAD + return new HttpProtocolFactory; + } + + return new MqttProtocolFactory; +} + +BaseProtocol *HttpProtocolFactory::GenProtocol() { + return new HttpProtocol; +} + +BaseProtocol *MqttProtocolFactory::GenProtocol() { + return new MqttProtocol; +} + + +} + diff --git a/phxrpc/msg/protocol_factory.h b/phxrpc/msg/protocol_factory.h new file mode 100644 index 0000000..70887b8 --- /dev/null +++ b/phxrpc/msg/protocol_factory.h @@ -0,0 +1,62 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + + +namespace phxrpc { + + +class BaseRequest; +class BaseProtocol; + + +class BaseProtocolFactory { + public: + BaseProtocolFactory() = default; + virtual ~BaseProtocolFactory() = default; + + static BaseProtocolFactory *CreateFactory(UThreadTcpStream &in_stream); + + virtual BaseProtocol *GenProtocol() = 0; +}; + + +class HttpProtocolFactory : public BaseProtocolFactory { + public: + HttpProtocolFactory() = default; + virtual ~HttpProtocolFactory() = default; + + virtual BaseProtocol *GenProtocol() override; +}; + + +class MqttProtocolFactory : public BaseProtocolFactory { + public: + MqttProtocolFactory() = default; + virtual ~MqttProtocolFactory() = default; + + virtual BaseProtocol *GenProtocol() override; +}; + + +} + diff --git a/phxrpc/network/Makefile b/phxrpc/network/Makefile index 29bc02c..fc148e2 100644 --- a/phxrpc/network/Makefile +++ b/phxrpc/network/Makefile @@ -1,8 +1,8 @@ include ../../phxrpc.mk TEST_TARGETS = test_echo_client test_echo_server \ - test_epoll_server test_epoll_client \ - test_uthread test_timer test_uthread_context \ + test_epoll_server test_epoll_client \ + test_uthread test_timer test_uthread_context all: $(TEST_TARGETS) @@ -12,7 +12,7 @@ test_echo_client: test_echo_client.o test_echo_server: test_echo_server.o $(LINKER) $^ -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -o $@ -test_uthread: test_uthread.o +test_uthread: test_uthread.o $(LINKER) $^ -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -o $@ test_epoll_server: test_epoll_server.o @@ -30,3 +30,4 @@ test_uthread_context : test_uthread_context.o clean: @( $(RM) $(TEST_TARGETS) ) @( $(RM) *.o core.* $(LIB_OBJS) ) + diff --git a/phxrpc/network/test_uthread.cpp b/phxrpc/network/test_uthread.cpp index 8905de2..84db8ad 100644 --- a/phxrpc/network/test_uthread.cpp +++ b/phxrpc/network/test_uthread.cpp @@ -67,7 +67,7 @@ void execute(UThreadRuntime & runtime, size_t count) { } void run(size_t count) { - UThreadRuntime runtime(64 * 1024); + UThreadRuntime runtime(64 * 1024, false); execute(runtime, count); diff --git a/phxrpc/network/test_uthread_context.cpp b/phxrpc/network/test_uthread_context.cpp index 87e3346..9abfe2d 100644 --- a/phxrpc/network/test_uthread_context.cpp +++ b/phxrpc/network/test_uthread_context.cpp @@ -26,8 +26,8 @@ using namespace phxrpc; void f1(void *); void f2(void *); -UThreadContextSystem c1(64 * 1024, &f1, nullptr, nullptr); -UThreadContextSystem c2(64 * 1024, &f2, nullptr, nullptr); +UThreadContextSystem c1(64 * 1024, &f1, nullptr, nullptr, true); +UThreadContextSystem c2(64 * 1024, &f2, nullptr, nullptr, true); int test_count = 0; diff --git a/phxrpc/network/timer.cpp b/phxrpc/network/timer.cpp index c18ece3..71fb94e 100644 --- a/phxrpc/network/timer.cpp +++ b/phxrpc/network/timer.cpp @@ -20,20 +20,26 @@ See the AUTHORS file for names of contributors. */ #include "timer.h" -#include -#include -#include + +#include +#include +#include +#include +#include +#include +#include #include -#include -#include +#include + #include "uthread_epoll.h" -#include -#include + using namespace std; + namespace phxrpc { + const uint64_t Timer::GetTimestampMS() { auto now_time = chrono::system_clock::now(); uint64_t now = (chrono::duration_cast(now_time.time_since_epoch())).count(); @@ -46,14 +52,14 @@ const uint64_t Timer::GetSteadyClockMS() { return now; } -void Timer :: MsSleep(const int time_ms) { +void Timer::MsSleep(const int time_ms) { timespec t; t.tv_sec = time_ms / 1000; t.tv_nsec = (time_ms % 1000) * 1000000; int ret = 0; do { ret = ::nanosleep(&t, &t); - } while (ret == -1 && errno == EINTR); + } while (ret == -1 && errno == EINTR); } Timer::Timer() { @@ -62,7 +68,7 @@ Timer::Timer() { Timer::~Timer() { } -void Timer :: heap_up(const size_t end_idx) { +void Timer::heap_up(const size_t end_idx) { size_t now_idx = end_idx - 1; TimerObj obj = timer_heap_[now_idx]; size_t parent_idx = (now_idx - 1) / 2; @@ -77,7 +83,7 @@ void Timer :: heap_up(const size_t end_idx) { UThreadSocketSetTimerID(*timer_heap_[now_idx].socket_, now_idx + 1); } -void Timer :: heap_down(const size_t begin_idx) { +void Timer::heap_down(const size_t begin_idx) { size_t now_idx = begin_idx; TimerObj obj = timer_heap_[now_idx]; size_t child_idx = (now_idx + 1) * 2; @@ -102,13 +108,13 @@ void Timer :: heap_down(const size_t begin_idx) { UThreadSocketSetTimerID(*timer_heap_[now_idx].socket_, now_idx + 1); } -void Timer :: AddTimer(uint64_t abs_time, UThreadSocket_t * socket) { +void Timer::AddTimer(uint64_t abs_time, UThreadSocket_t *socket) { TimerObj obj(abs_time, socket); timer_heap_.push_back(obj); heap_up(timer_heap_.size()); } -void Timer :: RemoveTimer(const size_t timer_id) { +void Timer::RemoveTimer(const size_t timer_id) { if (timer_id == 0) { return; } @@ -132,7 +138,7 @@ void Timer :: RemoveTimer(const size_t timer_id) { UThreadSocketSetTimerID(*timer_heap_[now_idx].socket_, now_idx + 1); } else { heap_down(now_idx); - } + } } const int Timer::GetNextTimeout() const { @@ -149,12 +155,12 @@ const int Timer::GetNextTimeout() const { return next_timeout; } -UThreadSocket_t * Timer::PopTimeout() { +UThreadSocket_t *Timer::PopTimeout() { if (timer_heap_.empty()) { return nullptr; } - UThreadSocket_t * socket = timer_heap_[0].socket_; + UThreadSocket_t *socket{timer_heap_[0].socket_}; UThreadSocketSetTimerID(*socket, 0); std::swap(timer_heap_[0], timer_heap_[timer_heap_.size() - 1]); @@ -167,17 +173,18 @@ UThreadSocket_t * Timer::PopTimeout() { return socket; } -std::vector Timer :: GetSocketList() { +std::vector Timer::GetSocketList() { std::vector socket_list; - for (auto & obj : timer_heap_) { + for (auto &obj : timer_heap_) { socket_list.push_back(obj.socket_); } return socket_list; } -const bool Timer :: empty() { +const bool Timer::empty() { return timer_heap_.empty(); } + } diff --git a/phxrpc/network/timer.h b/phxrpc/network/timer.h index 7a5307e..a9de44a 100644 --- a/phxrpc/network/timer.h +++ b/phxrpc/network/timer.h @@ -21,22 +21,24 @@ See the AUTHORS file for names of contributors. #pragma once +#include +#include #include -#include -#include + namespace phxrpc { + typedef struct tagUThreadSocket UThreadSocket_t; -class Timer { +class Timer final { public: Timer(); ~Timer(); - void AddTimer(uint64_t abs_time, UThreadSocket_t * socket); + void AddTimer(uint64_t abs_time, UThreadSocket_t *socket); void RemoveTimer(const size_t timer_id); - UThreadSocket_t * PopTimeout(); + UThreadSocket_t *PopTimeout(); const int GetNextTimeout() const; const bool empty(); static const uint64_t GetTimestampMS(); @@ -49,18 +51,18 @@ class Timer { void heap_down(const size_t begin_idx); struct TimerObj { - TimerObj(uint64_t abs_time, UThreadSocket_t * socket) + TimerObj(uint64_t abs_time, UThreadSocket_t *socket) : abs_time_(abs_time), socket_(socket){ } uint64_t abs_time_; - UThreadSocket_t * socket_; + UThreadSocket_t *socket_; - bool operator <(const TimerObj & obj) const { + bool operator <(const TimerObj &obj) const { return abs_time_ < obj.abs_time_; } - bool operator ==(const TimerObj & obj) const { + bool operator ==(const TimerObj &obj) const { return abs_time_ == obj.abs_time_; } }; @@ -68,4 +70,6 @@ class Timer { std::vector timer_heap_; }; + } + diff --git a/phxrpc/network/uthread_context_base.cpp b/phxrpc/network/uthread_context_base.cpp index b292dc5..d0fa089 100644 --- a/phxrpc/network/uthread_context_base.cpp +++ b/phxrpc/network/uthread_context_base.cpp @@ -26,9 +26,10 @@ namespace phxrpc { ContextCreateFunc_t UThreadContext::context_create_func_ = nullptr; UThreadContext * UThreadContext :: Create(size_t stack_size, - UThreadFunc_t func, void * args, UThreadDoneCallback_t callback) { + UThreadFunc_t func, void * args, + UThreadDoneCallback_t callback, const bool need_stack_protect) { if (context_create_func_ != nullptr) { - return context_create_func_(stack_size, func, args, callback); + return context_create_func_(stack_size, func, args, callback, need_stack_protect); } return nullptr; } diff --git a/phxrpc/network/uthread_context_base.h b/phxrpc/network/uthread_context_base.h index 00ffee7..294ec20 100644 --- a/phxrpc/network/uthread_context_base.h +++ b/phxrpc/network/uthread_context_base.h @@ -31,7 +31,7 @@ class UThreadContext; typedef std::function< void(void *) > UThreadFunc_t; typedef std::function< void() > UThreadDoneCallback_t; typedef std::function< UThreadContext* - (size_t, UThreadFunc_t, void *, UThreadDoneCallback_t) > ContextCreateFunc_t; + (size_t, UThreadFunc_t, void *, UThreadDoneCallback_t, const bool) > ContextCreateFunc_t; class UThreadContext { public: @@ -39,7 +39,8 @@ class UThreadContext { virtual ~UThreadContext() { } static UThreadContext * Create(size_t stack_size, - UThreadFunc_t func, void * args, UThreadDoneCallback_t callback); + UThreadFunc_t func, void * args, + UThreadDoneCallback_t callback, const bool need_stack_protect); static void SetContextCreateFunc(ContextCreateFunc_t context_create_func); static ContextCreateFunc_t GetContextCreateFunc(); diff --git a/phxrpc/network/uthread_context_system.cpp b/phxrpc/network/uthread_context_system.cpp index 8bf1b65..2843452 100644 --- a/phxrpc/network/uthread_context_system.cpp +++ b/phxrpc/network/uthread_context_system.cpp @@ -28,31 +28,27 @@ See the AUTHORS file for names of contributors. namespace phxrpc { -UThreadContextSystem :: UThreadContextSystem(size_t stack_size, UThreadFunc_t func, void * args, UThreadDoneCallback_t callback) - : func_(func), args_(args), stack_(nullptr), stack_size_(stack_size), - protect_page_(0), callback_(callback) { - - stack_ = (char *)calloc(1, stack_size_); - assert(stack_ != nullptr); - +UThreadContextSystem :: UThreadContextSystem(size_t stack_size, UThreadFunc_t func, void * args, + UThreadDoneCallback_t callback, const bool need_stack_protect) + : func_(func), args_(args), stack_(stack_size, need_stack_protect), callback_(callback) { Make(func, args); } UThreadContextSystem :: ~UThreadContextSystem() { - free(stack_); } UThreadContext * UThreadContextSystem :: DoCreate(size_t stack_size, - UThreadFunc_t func, void * args, UThreadDoneCallback_t callback) { - return new UThreadContextSystem(stack_size, func, args, callback); + UThreadFunc_t func, void * args, UThreadDoneCallback_t callback, + const bool need_stack_protect) { + return new UThreadContextSystem(stack_size, func, args, callback, need_stack_protect); } void UThreadContextSystem :: Make(UThreadFunc_t func, void * args) { func_ = func; args_ = args; getcontext(&context_); - context_.uc_stack.ss_sp = stack_; - context_.uc_stack.ss_size = stack_size_; + context_.uc_stack.ss_sp = stack_.top(); + context_.uc_stack.ss_size = stack_.size(); context_.uc_stack.ss_flags = 0; context_.uc_link = GetMainContext(); uintptr_t ptr = (uintptr_t)this; @@ -71,7 +67,7 @@ bool UThreadContextSystem :: Yield() { } ucontext_t * UThreadContextSystem :: GetMainContext() { - static thread_local ucontext_t main_context; + static __thread ucontext_t main_context; return &main_context; } diff --git a/phxrpc/network/uthread_context_system.h b/phxrpc/network/uthread_context_system.h index b2865aa..2c10405 100644 --- a/phxrpc/network/uthread_context_system.h +++ b/phxrpc/network/uthread_context_system.h @@ -27,16 +27,19 @@ See the AUTHORS file for names of contributors. #include #include "uthread_context_base.h" +#include "uthread_context_util.h" namespace phxrpc { class UThreadContextSystem : public UThreadContext { public: - UThreadContextSystem(size_t stack_size, UThreadFunc_t func, void * args, UThreadDoneCallback_t callback); + UThreadContextSystem(size_t stack_size, UThreadFunc_t func, void * args, + UThreadDoneCallback_t callback, const bool need_stack_protect); ~UThreadContextSystem(); static UThreadContext * DoCreate(size_t stack_size, - UThreadFunc_t func, void * args, UThreadDoneCallback_t callback); + UThreadFunc_t func, void * args, UThreadDoneCallback_t callback, + const bool need_stack_protect); void Make(UThreadFunc_t func, void * args) override; bool Resume() override; @@ -50,9 +53,7 @@ class UThreadContextSystem : public UThreadContext { ucontext_t context_; UThreadFunc_t func_; void * args_; - char * stack_; - size_t stack_size_; - int protect_page_; + UThreadStackMemory stack_; UThreadDoneCallback_t callback_; }; diff --git a/phxrpc/network/uthread_context_util.cpp b/phxrpc/network/uthread_context_util.cpp index e43e993..a787dce 100644 --- a/phxrpc/network/uthread_context_util.cpp +++ b/phxrpc/network/uthread_context_util.cpp @@ -22,27 +22,54 @@ See the AUTHORS file for names of contributors. #include "uthread_context_util.h" #include #include +#include namespace phxrpc { -int UThreadProtectStack(void * stack_top, size_t stack_size) { - int page = STACK_PROTECT_PAGE; +#ifdef __APPLE__ + #define MAP_ANONYMOUS MAP_ANON +#endif + +UThreadStackMemory :: UThreadStackMemory(const size_t stack_size, const bool need_protect) : + raw_stack_(nullptr), stack_(nullptr), need_protect_(need_protect) { int page_size = getpagesize(); - assert(stack_size >= (size_t)page_size * (page + 1)); - void * protect_addr = stack_top; - if ((size_t)protect_addr & (page_size - 1)) { - protect_addr = (void *)(((size_t)stack_top & (~(page_size - 1))) + page_size); + if ((stack_size % page_size) != 0) { + stack_size_ = (stack_size / page_size + 1) * page_size; + } else { + stack_size_ = stack_size; + } + + if (need_protect) { + raw_stack_ = mmap(NULL, stack_size_ + page_size * 2, + PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(raw_stack_ != nullptr); + assert(mprotect(raw_stack_, page_size, PROT_NONE) == 0); + assert(mprotect((void *)((char *)raw_stack_ + stack_size_ + page_size), page_size, PROT_NONE) == 0); + stack_ = (void *)((char *)raw_stack_ + page_size); + } else { + raw_stack_ = mmap(NULL, stack_size_, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(raw_stack_ != nullptr); + stack_ = raw_stack_; } - return mprotect(protect_addr, page_size * page, PROT_NONE); } -int UThreadUnProtectStack(void * stack_top, int page) { - void * protect_addr = stack_top; +UThreadStackMemory :: ~UThreadStackMemory() { int page_size = getpagesize(); - if ((size_t)protect_addr & (page_size - 1)) { - protect_addr = (void *)(((size_t)stack_top & (~(page_size - 1))) + page_size); + if (need_protect_) { + assert(mprotect(raw_stack_, page_size, PROT_READ | PROT_WRITE) == 0); + assert(mprotect((void *)((char *)raw_stack_ + stack_size_ + page_size), page_size, PROT_READ | PROT_WRITE) == 0); + assert(munmap(raw_stack_, stack_size_ + page_size * 2) == 0); + } else { + assert(munmap(raw_stack_, stack_size_) == 0); } - return mprotect(protect_addr, page_size * page, PROT_READ | PROT_WRITE); +} + +void * UThreadStackMemory :: top() { + return stack_; +} + +size_t UThreadStackMemory :: size() { + return stack_size_; } } //namespace phxrpc diff --git a/phxrpc/network/uthread_context_util.h b/phxrpc/network/uthread_context_util.h index 1747f99..65a7e85 100644 --- a/phxrpc/network/uthread_context_util.h +++ b/phxrpc/network/uthread_context_util.h @@ -26,9 +26,19 @@ See the AUTHORS file for names of contributors. namespace phxrpc { -#define STACK_PROTECT_PAGE 1 - -int UThreadProtectStack(void * stack_top, size_t stack_size); -int UThreadUnProtectStack(void * stack_top, int page); +class UThreadStackMemory { +public: + UThreadStackMemory(const size_t stack_size, const bool need_protect = true); + ~UThreadStackMemory(); + + void * top(); + size_t size(); + +private: + void * raw_stack_; + void * stack_; + size_t stack_size_; + int need_protect_; +}; } //namespace phxrpc diff --git a/phxrpc/network/uthread_epoll.cpp b/phxrpc/network/uthread_epoll.cpp index 227b43a..2f0f77a 100644 --- a/phxrpc/network/uthread_epoll.cpp +++ b/phxrpc/network/uthread_epoll.cpp @@ -19,29 +19,38 @@ permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include -#include -#include -#include -#include +#include "uthread_epoll.h" + +#include #include #include -#include #include -#include -#include -#include +#include +#include +#include + +#include +#include +#include +#include #include +#include + +#ifdef __APPLE__ +#include "epoll-darwin.h" +#else +#include +#endif -#include "uthread_epoll.h" -#include "socket_stream_base.h" #include "phxrpc/file/log_utils.h" +#include "phxrpc/network/socket_stream_base.h" + namespace phxrpc { + typedef struct tagUThreadSocket { - UThreadEpollScheduler * scheduler; + UThreadEpollScheduler *scheduler; int uthread_id; int epoll_fd; @@ -56,12 +65,12 @@ typedef struct tagUThreadSocket { void * args; } UThreadSocket_t; -EpollNotifier :: EpollNotifier(UThreadEpollScheduler * scheduler) : - scheduler_(scheduler) { +EpollNotifier::EpollNotifier(UThreadEpollScheduler *scheduler) + : scheduler_(scheduler) { pipe_fds_[0] = pipe_fds_[1] = -1; } -EpollNotifier :: ~EpollNotifier() { +EpollNotifier::~EpollNotifier() { if (pipe_fds_[0] != -1) { close(pipe_fds_[0]); } @@ -70,14 +79,14 @@ EpollNotifier :: ~EpollNotifier() { } } -void EpollNotifier :: Run() { +void EpollNotifier::Run() { assert(pipe(pipe_fds_) == 0); fcntl(pipe_fds_[1], F_SETFL, O_NONBLOCK); scheduler_->AddTask(std::bind(&EpollNotifier::Func, this), nullptr); } -void EpollNotifier :: Func() { - UThreadSocket_t * socket = scheduler_->CreateSocket(pipe_fds_[0], -1, -1, false); +void EpollNotifier::Func() { + UThreadSocket_t *socket{scheduler_->CreateSocket(pipe_fds_[0], -1, -1, false)}; char tmp[2] = {0}; while (true) { if (UThreadRead(*socket, tmp, 1, 0) < 0) { @@ -87,11 +96,99 @@ void EpollNotifier :: Func() { free(socket); } -void EpollNotifier :: Notify() { +void EpollNotifier::Notify() { ssize_t write_len = write(pipe_fds_[1], (void *)"a", 1); if (write_len < 0) { - log(LOG_ERR, "%s write err", __func__); + //log(LOG_ERR, "%s write err", __func__); + } +} + + +UThreadNotifier::UThreadNotifier() { + pipe_fds_[0] = pipe_fds_[1] = -1; +} + +UThreadNotifier::~UThreadNotifier() { + free(socket_); + if (pipe_fds_[0] != -1) { + close(pipe_fds_[0]); + } + if (pipe_fds_[1] != -1) { + close(pipe_fds_[1]); + } +} + +int UThreadNotifier::Init(UThreadEpollScheduler *const scheduler, + const int timeout_ms) { + int ret{pipe(pipe_fds_)}; + if (0 != ret) return ret; + fcntl(pipe_fds_[1], F_SETFL, O_NONBLOCK); + socket_ = scheduler->CreateSocket(pipe_fds_[0], timeout_ms, -1, false); + + return 0; +} + +int UThreadNotifier::SendNotify(void *const data) { + ssize_t write_len{write(pipe_fds_[1], (void *)&data, sizeof(void *))}; + if (write_len != static_cast(sizeof(void *))) { + log(LOG_ERR, "%s write errno %d", __func__, errno); + + return -1; + } + + return 0; +} + +int UThreadNotifier::WaitNotify(void *&data) { + ssize_t read_len{UThreadRead(*socket_, (void *)&data, sizeof(void *), 0)}; + if (read_len != static_cast(sizeof(void *))) { + log(LOG_ERR, "%s UThreadRead errno %d", __func__, errno); + + return -1; + } + + return 0; +} + + +UThreadNotifierPool::UThreadNotifierPool(UThreadEpollScheduler *const scheduler, + const int timeout_ms) + : scheduler_(scheduler), timeout_ms_(timeout_ms) { +} + +UThreadNotifierPool::~UThreadNotifierPool() { + for (auto &it : pool_map_) { + delete it.second; + } +} + +int UThreadNotifierPool::GetNotifier(const __uint128_t &id, UThreadNotifier *¬ifier) { + notifier = nullptr; + + auto it(pool_map_.find(id)); + if (pool_map_.end() != it && it->second) { + notifier = it->second; + + return 0; + } + + notifier = new UThreadNotifier(); + int ret{notifier->Init(scheduler_, timeout_ms_)}; + if (0 != ret) { + return ret; + } + + pool_map_[id] = notifier; + + return 0; +} + +void UThreadNotifierPool::ReleaseNotifier(const __uint128_t &id) { + if (pool_map_[id]) { + delete pool_map_[id]; + pool_map_[id] = nullptr; } + pool_map_.erase(id); } //////////////////////////////////////////////// @@ -102,10 +199,10 @@ enum UThreadEpollREventStatus { UThreadEpollREvent_Close = -2, }; -UThreadEpollScheduler::UThreadEpollScheduler(size_t stack_size, int max_task) : - epoll_wake_up_(this) { - runtime_ = new UThreadRuntime(stack_size); - max_task_ = max_task; +UThreadEpollScheduler::UThreadEpollScheduler(size_t stack_size, int max_task, const bool need_stack_protect) : + runtime_(stack_size, need_stack_protect), epoll_wake_up_(this) { + //epoll notifier use one task. + max_task_ = max_task + 1; epoll_fd_ = epoll_create(max_task_); @@ -118,6 +215,7 @@ UThreadEpollScheduler::UThreadEpollScheduler(size_t stack_size, int max_task) : run_forever_ = false; active_socket_func_ = nullptr; handler_accepted_fd_func_ = nullptr; + handler_new_request_func_ = nullptr; epoll_wait_events_ = 0; epoll_wait_events_per_second_ = 0; @@ -125,39 +223,46 @@ UThreadEpollScheduler::UThreadEpollScheduler(size_t stack_size, int max_task) : } UThreadEpollScheduler::~UThreadEpollScheduler() { - delete runtime_; - close(epoll_fd_); } -UThreadEpollScheduler * UThreadEpollScheduler :: Instance() { +UThreadEpollScheduler *UThreadEpollScheduler::Instance() { static UThreadEpollScheduler obj(64 * 1024, 300); return &obj; } -void UThreadEpollScheduler::AddTask(UThreadFunc_t func, void * args) { +bool UThreadEpollScheduler::IsTaskFull() { + return (runtime_.GetUnfinishedItemCount() + (int)todo_list_.size()) >= max_task_; +} + +void UThreadEpollScheduler::AddTask(UThreadFunc_t func, void *args) { todo_list_.push(std::make_pair(func, args)); } -void UThreadEpollScheduler :: SetActiveSocketFunc(UThreadActiveSocket_t active_socket_func) { +void UThreadEpollScheduler::SetActiveSocketFunc(UThreadActiveSocket_t active_socket_func) { active_socket_func_ = active_socket_func; } -void UThreadEpollScheduler :: SetHandlerAcceptedFdFunc(UThreadHanderAcceptedFdFunc_t handler_accepted_fd_func) { +void UThreadEpollScheduler::SetHandlerNewRequestFunc(UThreadHandlerNewRequest_t handler_new_request_func) { + handler_new_request_func_ = handler_new_request_func; +} + +void UThreadEpollScheduler::SetHandlerAcceptedFdFunc(UThreadHandlerAcceptedFdFunc_t handler_accepted_fd_func) { handler_accepted_fd_func_ = handler_accepted_fd_func; } bool UThreadEpollScheduler::YieldTask() { - return runtime_->Yield(); + return runtime_.Yield(); } int UThreadEpollScheduler::GetCurrUThread() { - return runtime_->GetCurrUThread(); + return runtime_.GetCurrUThread(); } -UThreadSocket_t * UThreadEpollScheduler::CreateSocket(int fd, int socket_timeout_ms, - int connect_timeout_ms, bool no_delay) { - UThreadSocket_t * socket = (UThreadSocket_t*) calloc(1, sizeof(UThreadSocket_t)); +UThreadSocket_t *UThreadEpollScheduler::CreateSocket(const int fd, + const int socket_timeout_ms, const int connect_timeout_ms, + const bool no_delay) { + UThreadSocket_t *socket = (UThreadSocket_t *)calloc(1, sizeof(UThreadSocket_t)); BaseTcpUtils::SetNonBlock(fd, true); if (no_delay) { @@ -181,8 +286,8 @@ UThreadSocket_t * UThreadEpollScheduler::CreateSocket(int fd, int socket_timeout void UThreadEpollScheduler::ConsumeTodoList() { while (!todo_list_.empty()) { auto & it = todo_list_.front(); - int id = runtime_->Create(it.first, it.second); - runtime_->Resume(id); + int id = runtime_.Create(it.first, it.second); + runtime_.Resume(id); todo_list_.pop(); } @@ -192,28 +297,28 @@ void UThreadEpollScheduler::Close() { closed_ = true; } -void UThreadEpollScheduler :: NotifyEpoll() { +void UThreadEpollScheduler::NotifyEpoll() { if (epoll_wait_events_per_second_ < 2000) { //phxrpc::log(LOG_ERR, "%s now epoll_wait per second %d", __func__, epoll_wait_events_per_second_); epoll_wake_up_.Notify(); } } -void UThreadEpollScheduler :: ResumeAll(int flag) { +void UThreadEpollScheduler::ResumeAll(int flag) { std::vector exist_socket_list = timer_.GetSocketList(); for (auto & socket : exist_socket_list) { socket->waited_events = flag; - runtime_->Resume(socket->uthread_id); + runtime_.Resume(socket->uthread_id); } } -void UThreadEpollScheduler :: RunForever() { +void UThreadEpollScheduler::RunForever() { run_forever_ = true; epoll_wake_up_.Run(); Run(); } -void UThreadEpollScheduler :: StatEpollwaitEvents(const int event_count) { +void UThreadEpollScheduler::StatEpollwaitEvents(const int event_count) { epoll_wait_events_ += event_count; auto now_time = Timer::GetSteadyClockMS(); if (now_time > epoll_wait_events_last_cal_time_ + 1000) { @@ -227,28 +332,33 @@ void UThreadEpollScheduler :: StatEpollwaitEvents(const int event_count) { bool UThreadEpollScheduler::Run() { ConsumeTodoList(); - struct epoll_event * events = (struct epoll_event*) calloc(max_task_, sizeof(struct epoll_event)); + struct epoll_event *events = (struct epoll_event*) calloc(max_task_, sizeof(struct epoll_event)); int next_timeout = timer_.GetNextTimeout(); - for (; (run_forever_) || (!runtime_->IsAllDone());) { + for (; (run_forever_) || (!runtime_.IsAllDone());) { int nfds = epoll_wait(epoll_fd_, events, max_task_, 4); if (nfds != -1) { for (int i = 0; i < nfds; i++) { UThreadSocket_t * socket = (UThreadSocket_t*) events[i].data.ptr; socket->waited_events = events[i].events; - runtime_->Resume(socket->uthread_id); + runtime_.Resume(socket->uthread_id); } //for server mode if (active_socket_func_ != nullptr) { UThreadSocket_t * socket = nullptr; while ((socket = active_socket_func_()) != nullptr) { - runtime_->Resume(socket->uthread_id); + runtime_.Resume(socket->uthread_id); } } + //for server uthread worker + if (handler_new_request_func_ != nullptr) { + handler_new_request_func_(); + } + if (handler_accepted_fd_func_ != nullptr) { handler_accepted_fd_func_(); } @@ -273,7 +383,7 @@ bool UThreadEpollScheduler::Run() { return true; } -void UThreadEpollScheduler::AddTimer(UThreadSocket_t * socket, int timeout_ms) { +void UThreadEpollScheduler::AddTimer(UThreadSocket_t *socket, const int timeout_ms) { RemoveTimer(socket->timer_id); if (timeout_ms == -1) { @@ -289,23 +399,23 @@ void UThreadEpollScheduler::RemoveTimer(const size_t timer_id) { } } -void UThreadEpollScheduler::DealwithTimeout(int & next_timeout) { +void UThreadEpollScheduler::DealwithTimeout(int &next_timeout) { while (true) { next_timeout = timer_.GetNextTimeout(); - if (next_timeout != 0) { + if (0 != next_timeout) { break; } UThreadSocket_t * socket = timer_.PopTimeout(); socket->waited_events = UThreadEpollREvent_Timeout; - runtime_->Resume(socket->uthread_id); + runtime_.Resume(socket->uthread_id); } } ////////////////////////////////////////////////////////////////////// -int UThreadPoll(UThreadSocket_t & socket, int events, int * revents, int timeout_ms) { - int ret = -1; +int UThreadPoll(UThreadSocket_t &socket, int events, int *revents, const int timeout_ms) { + int ret{-1}; socket.uthread_id = socket.scheduler->GetCurrUThread(); @@ -345,10 +455,10 @@ int UThreadPoll(UThreadSocket_t & socket, int events, int * revents, int timeout return ret; } -int UThreadPoll(UThreadSocket_t * list[], int count, int timeout_ms) { +int UThreadPoll(UThreadSocket_t *list[], int count, const int timeout_ms) { int nfds = -1; - UThreadSocket_t * socket = list[0]; + UThreadSocket_t *socket = list[0]; int epollfd = epoll_create(count); @@ -369,7 +479,7 @@ int UThreadPoll(UThreadSocket_t * list[], int count, int timeout_ms) { socket->scheduler->YieldTask(); if (0 != (EPOLLIN & fake_socket.waited_events)) { - struct epoll_event * events = (struct epoll_event*) calloc(count, sizeof(struct epoll_event)); + struct epoll_event * events = (struct epoll_event*)calloc(count, sizeof(struct epoll_event)); nfds = epoll_wait(epollfd, events, count, 0); @@ -386,7 +496,7 @@ int UThreadPoll(UThreadSocket_t * list[], int count, int timeout_ms) { return nfds; } -int UThreadConnect(UThreadSocket_t & socket, const struct sockaddr *addr, socklen_t addrlen) { +int UThreadConnect(UThreadSocket_t &socket, const struct sockaddr *addr, socklen_t addrlen) { int ret = connect(socket.socket, addr, addrlen); if (0 != ret) { @@ -404,7 +514,7 @@ int UThreadConnect(UThreadSocket_t & socket, const struct sockaddr *addr, sockle return ret; } -int UThreadAccept(UThreadSocket_t & socket, struct sockaddr *addr, socklen_t *addrlen) { +int UThreadAccept(UThreadSocket_t &socket, struct sockaddr *addr, socklen_t *addrlen) { int ret = accept(socket.socket, addr, addrlen); if (ret < 0) { if (EAGAIN != errno && EWOULDBLOCK != errno) { @@ -422,7 +532,7 @@ int UThreadAccept(UThreadSocket_t & socket, struct sockaddr *addr, socklen_t *ad return ret; } -ssize_t UThreadRead(UThreadSocket_t & socket, void * buf, size_t len, int flags) { +ssize_t UThreadRead(UThreadSocket_t &socket, void *buf, size_t len, const int flags) { int ret = read(socket.socket, buf, len); if (ret < 0 && EAGAIN == errno) { @@ -437,7 +547,7 @@ ssize_t UThreadRead(UThreadSocket_t & socket, void * buf, size_t len, int flags) return ret; } -ssize_t UThreadRecv(UThreadSocket_t & socket, void * buf, size_t len, int flags) { +ssize_t UThreadRecv(UThreadSocket_t &socket, void *buf, size_t len, const int flags) { int ret = recv(socket.socket, buf, len, flags); if (ret < 0 && EAGAIN == errno) { @@ -452,7 +562,7 @@ ssize_t UThreadRecv(UThreadSocket_t & socket, void * buf, size_t len, int flags) return ret; } -ssize_t UThreadSend(UThreadSocket_t & socket, const void *buf, size_t len, int flags) { +ssize_t UThreadSend(UThreadSocket_t &socket, const void *buf, size_t len, const int flags) { int ret = send(socket.socket, buf, len, flags); if (ret < 0 && EAGAIN == errno) { @@ -467,60 +577,61 @@ ssize_t UThreadSend(UThreadSocket_t & socket, const void *buf, size_t len, int f return ret; } -int UThreadClose(UThreadSocket_t & socket) { +int UThreadClose(UThreadSocket_t &socket) { if (socket.socket >= 0) { return close(socket.socket); } return -1; } -void UThreadSetConnectTimeout(UThreadSocket_t & socket, int connect_timeout_ms) { +void UThreadSetConnectTimeout(UThreadSocket_t &socket, const int connect_timeout_ms) { socket.connect_timeout_ms = connect_timeout_ms; } -void UThreadSetSocketTimeout(UThreadSocket_t & socket, int socket_timeout_ms) { +void UThreadSetSocketTimeout(UThreadSocket_t &socket, const int socket_timeout_ms) { socket.socket_timeout_ms = socket_timeout_ms; } -int UThreadSocketFd(UThreadSocket_t & socket) { +int UThreadSocketFd(UThreadSocket_t &socket) { return socket.socket; } -size_t UThreadSocketTimerID(UThreadSocket_t & socket) { +size_t UThreadSocketTimerID(UThreadSocket_t &socket) { return socket.timer_id; } -void UThreadSocketSetTimerID(UThreadSocket_t & socket, size_t timer_id) { +void UThreadSocketSetTimerID(UThreadSocket_t &socket, size_t timer_id) { socket.timer_id = timer_id; } -UThreadSocket_t * NewUThreadSocket() { - UThreadSocket_t * socket = (UThreadSocket_t*) calloc(1, sizeof(UThreadSocket_t)); +UThreadSocket_t *NewUThreadSocket() { + UThreadSocket_t *socket = (UThreadSocket_t *)calloc(1, sizeof(UThreadSocket_t)); return socket; } -void UThreadSetArgs(UThreadSocket_t & socket, void * args) { +void UThreadSetArgs(UThreadSocket_t &socket, void *args) { socket.args = args; } -void * UthreadGetArgs(UThreadSocket_t & socket) { +void *UThreadGetArgs(UThreadSocket_t &socket) { return socket.args; } -void UthreadWait(UThreadSocket_t & socket, int timeout_ms) { +void UThreadWait(UThreadSocket_t &socket, const int timeout_ms) { socket.uthread_id = socket.scheduler->GetCurrUThread(); socket.scheduler->AddTimer(&socket, timeout_ms); socket.scheduler->YieldTask(); socket.scheduler->RemoveTimer(socket.timer_id); } -void UthreadLazyDestory(UThreadSocket_t & socket) { +void UThreadLazyDestory(UThreadSocket_t &socket) { socket.uthread_id = -1; } -bool IsUthreadDestory(UThreadSocket_t & socket) { +bool IsUThreadDestory(UThreadSocket_t &socket) { return socket.uthread_id == -1; } + }; diff --git a/phxrpc/network/uthread_epoll.h b/phxrpc/network/uthread_epoll.h index dcc6ec0..8e2f52f 100644 --- a/phxrpc/network/uthread_epoll.h +++ b/phxrpc/network/uthread_epoll.h @@ -21,56 +21,95 @@ See the AUTHORS file for names of contributors. #pragma once -#include +#include + #include #include +#include -#include -#include +#include "phxrpc/network/timer.h" +#include "phxrpc/network/uthread_runtime.h" -#include "uthread_runtime.h" -#include "timer.h" namespace phxrpc { + class UThreadEpollScheduler; typedef struct tagUThreadSocket UThreadSocket_t; typedef std::pair UThreadEpollArgs_t; -typedef std::function< UThreadSocket_t *() > UThreadActiveSocket_t; -typedef std::function< void() > UThreadHanderAcceptedFdFunc_t; +typedef std::function UThreadActiveSocket_t; +typedef std::function UThreadHandlerAcceptedFdFunc_t; +typedef std::function UThreadHandlerNewRequest_t; + -class EpollNotifier { -public: - EpollNotifier(UThreadEpollScheduler * scheduler); +class EpollNotifier final { + public: + EpollNotifier(UThreadEpollScheduler *scheduler); ~EpollNotifier(); void Run(); void Func(); void Notify(); -private: - UThreadEpollScheduler * scheduler_; + private: + UThreadEpollScheduler *scheduler_{nullptr}; + int pipe_fds_[2]; +}; + + +class UThreadNotifier final { + public: + UThreadNotifier(); + ~UThreadNotifier(); + + int Init(UThreadEpollScheduler *const scheduler, const int timeout_ms); + int SendNotify(void *const data); + int WaitNotify(void *&data); + + private: + UThreadEpollScheduler *scheduler_{nullptr}; + UThreadSocket_t *socket_{nullptr}; int pipe_fds_[2]; }; -class UThreadEpollScheduler { -public: - UThreadEpollScheduler(size_t stack_size, int max_task); +class UThreadNotifierPool final { + public: + UThreadNotifierPool(UThreadEpollScheduler *const scheduler, + const int timeout_ms); + ~UThreadNotifierPool(); + + int GetNotifier(const __uint128_t &id, UThreadNotifier *¬ifier); + void ReleaseNotifier(const __uint128_t &id); + + private: + std::map pool_map_; + UThreadEpollScheduler *scheduler_{nullptr}; + int timeout_ms_{5000}; +}; + + +class UThreadEpollScheduler final { + public: + UThreadEpollScheduler(size_t stack_size, int max_task, const bool need_stack_protect = true); ~UThreadEpollScheduler(); - static UThreadEpollScheduler * Instance(); + static UThreadEpollScheduler *Instance(); + + bool IsTaskFull(); - void AddTask(UThreadFunc_t func, void * args); + void AddTask(UThreadFunc_t func, void *args); - UThreadSocket_t * CreateSocket(int fd, int socket_timeout_ms = 5000, - int connect_timeout_ms = 200, bool no_delay = true); + UThreadSocket_t *CreateSocket(const int fd, const int socket_timeout_ms = 5000, + const int connect_timeout_ms = 200, const bool no_delay = true); void SetActiveSocketFunc(UThreadActiveSocket_t active_socket_func); - void SetHandlerAcceptedFdFunc(UThreadHanderAcceptedFdFunc_t handler_accepted_fd_func); + void SetHandlerAcceptedFdFunc(UThreadHandlerAcceptedFdFunc_t handler_accepted_fd_func); + + void SetHandlerNewRequestFunc(UThreadHandlerNewRequest_t handler_new_request_func); bool YieldTask(); @@ -79,33 +118,34 @@ class UThreadEpollScheduler { void RunForever(); void Close(); - + void NotifyEpoll(); int GetCurrUThread(); - void AddTimer(UThreadSocket_t * socket, int timeout_ms); + void AddTimer(UThreadSocket_t *socket, const int timeout_ms); void RemoveTimer(const size_t timer_id); - void DealwithTimeout(int & next_timeout); + void DealwithTimeout(int &next_timeout); -private: - typedef std::queue > TaskQueue; + private: + typedef std::queue> TaskQueue; void ConsumeTodoList(); void ResumeAll(int flag); void StatEpollwaitEvents(const int event_count); -private: - UThreadRuntime * runtime_; + UThreadRuntime runtime_; int max_task_; TaskQueue todo_list_; int epoll_fd_; Timer timer_; - bool closed_; - bool run_forever_; + bool closed_{false}; + bool run_forever_{false}; UThreadActiveSocket_t active_socket_func_; - UThreadHanderAcceptedFdFunc_t handler_accepted_fd_func_; + UThreadHandlerAcceptedFdFunc_t handler_accepted_fd_func_; + UThreadHandlerNewRequest_t handler_new_request_func_; + int epoll_wait_events_; int epoll_wait_events_per_second_; uint64_t epoll_wait_events_last_cal_time_; @@ -113,62 +153,66 @@ class UThreadEpollScheduler { EpollNotifier epoll_wake_up_; }; + class __uthread { -public: - __uthread(UThreadEpollScheduler & scheduler) : scheduler_(scheduler) { } + public: + __uthread(UThreadEpollScheduler &scheduler) : scheduler_(scheduler) { } template void operator-(Func const & func) { scheduler_.AddTask(func, nullptr); } -private: - UThreadEpollScheduler & scheduler_; + private: + UThreadEpollScheduler &scheduler_; }; + #define uthread_begin phxrpc::UThreadEpollScheduler _uthread_scheduler(64 * 1024, 300); +#define uthread_begin_withargs(stack_size, max_task) phxrpc::UThreadEpollScheduler _uthread_scheduler(stack_size, max_task); #define uthread_s _uthread_scheduler #define uthread_t phxrpc::__uthread(_uthread_scheduler)- #define uthread_end _uthread_scheduler.Run(); ////////////////////////////////////////////////////////////////////// -int UThreadPoll(UThreadSocket_t & socket, int events, int * revents, int timeout_ms); +int UThreadPoll(UThreadSocket_t &socket, int events, int *revents, const int timeout_ms); -int UThreadPoll(UThreadSocket_t * list[], int count, int timeout_ms); +int UThreadPoll(UThreadSocket_t *list[], int count, const int timeout_ms); -int UThreadConnect(UThreadSocket_t & socket, const struct sockaddr *addr, socklen_t addrlen); +int UThreadConnect(UThreadSocket_t &socket, const struct sockaddr *addr, socklen_t addrlen); -int UThreadAccept(UThreadSocket_t & socket, struct sockaddr *addr, socklen_t *addrlen); +int UThreadAccept(UThreadSocket_t &socket, struct sockaddr *addr, socklen_t *addrlen); -ssize_t UThreadRecv(UThreadSocket_t & socket, void * buf, size_t len, int flags); +ssize_t UThreadRecv(UThreadSocket_t &socket, void *buf, size_t len, const int flags); -ssize_t UThreadRead(UThreadSocket_t & socket, void * buf, size_t len, int flags); +ssize_t UThreadRead(UThreadSocket_t &socket, void *buf, size_t len, const int flags); -ssize_t UThreadSend(UThreadSocket_t & socket, const void *buf, size_t len, int flags); +ssize_t UThreadSend(UThreadSocket_t &socket, const void *buf, size_t len, const int flags); -int UThreadClose(UThreadSocket_t & socket); +int UThreadClose(UThreadSocket_t &socket); -void UThreadSetConnectTimeout(UThreadSocket_t & socket, int connect_timeout_ms); +void UThreadSetConnectTimeout(UThreadSocket_t &socket, const int connect_timeout_ms); -void UThreadSetSocketTimeout(UThreadSocket_t & socket, int socket_timeout_ms); +void UThreadSetSocketTimeout(UThreadSocket_t &socket, const int socket_timeout_ms); -int UThreadSocketFd(UThreadSocket_t & socket); +int UThreadSocketFd(UThreadSocket_t &socket); -size_t UThreadSocketTimerID(UThreadSocket_t & socket); +size_t UThreadSocketTimerID(UThreadSocket_t &socket); -void UThreadSocketSetTimerID(UThreadSocket_t & socket, size_t timer_id); +void UThreadSocketSetTimerID(UThreadSocket_t &socket, size_t timer_id); -UThreadSocket_t * NewUThreadSocket(); +UThreadSocket_t *NewUThreadSocket(); -void UThreadSetArgs(UThreadSocket_t & socket, void * args); +void UThreadSetArgs(UThreadSocket_t &socket, void *args); -void * UthreadGetArgs(UThreadSocket_t & socket); +void *UThreadGetArgs(UThreadSocket_t &socket); -void UthreadWait(UThreadSocket_t & socket, int timeout_ms); +void UThreadWait(UThreadSocket_t &socket, const int timeout_ms); -void UthreadLazyDestory(UThreadSocket_t & socket); +void UThreadLazyDestory(UThreadSocket_t &socket); -bool IsUthreadDestory(UThreadSocket_t & socket); +bool IsUThreadDestory(UThreadSocket_t &socket); -}; + +} // namespace phxrpc diff --git a/phxrpc/network/uthread_runtime.cpp b/phxrpc/network/uthread_runtime.cpp index 7741684..2caf21c 100644 --- a/phxrpc/network/uthread_runtime.cpp +++ b/phxrpc/network/uthread_runtime.cpp @@ -33,9 +33,10 @@ enum { namespace phxrpc { -UThreadRuntime :: UThreadRuntime(size_t stack_size) +UThreadRuntime :: UThreadRuntime(size_t stack_size, const bool need_stack_protect) :stack_size_(stack_size), first_done_item_(-1), - current_uthread_(-1), unfinished_item_count_(0) { + current_uthread_(-1), unfinished_item_count_(0), + need_stack_protect_(need_stack_protect) { if (UThreadContext::GetContextCreateFunc() == nullptr) { UThreadContext::SetContextCreateFunc(UThreadContextSystem::DoCreate); } @@ -59,7 +60,8 @@ int UThreadRuntime :: Create(UThreadFunc_t func, void * args) { } else { index = context_list_.size(); auto new_context = UThreadContext::Create(stack_size_, func, args, - std::bind(&UThreadRuntime::UThreadDoneCallback, this)); + std::bind(&UThreadRuntime::UThreadDoneCallback, this), + need_stack_protect_); assert(new_context != nullptr); ContextSlot context_slot; context_slot.context = new_context; @@ -117,5 +119,9 @@ bool UThreadRuntime::IsAllDone() { return unfinished_item_count_ == 0; } +int UThreadRuntime :: GetUnfinishedItemCount() const { + return unfinished_item_count_; +} + } diff --git a/phxrpc/network/uthread_runtime.h b/phxrpc/network/uthread_runtime.h index aba9354..0a37175 100644 --- a/phxrpc/network/uthread_runtime.h +++ b/phxrpc/network/uthread_runtime.h @@ -30,7 +30,7 @@ namespace phxrpc { class UThreadRuntime { public: - UThreadRuntime(size_t stack_size); + UThreadRuntime(size_t stack_size, const bool need_stack_protect); ~UThreadRuntime(); int Create(UThreadFunc_t func, void * args); @@ -38,6 +38,7 @@ class UThreadRuntime { bool Yield(); bool Resume(size_t index); bool IsAllDone(); + int GetUnfinishedItemCount() const; void UThreadDoneCallback(); @@ -57,6 +58,7 @@ class UThreadRuntime { int first_done_item_; int current_uthread_; int unfinished_item_count_; + bool need_stack_protect_; }; } //namespace phxrpc diff --git a/phxrpc/rpc.h b/phxrpc/rpc.h index b5b2e39..62c7a6a 100644 --- a/phxrpc/rpc.h +++ b/phxrpc/rpc.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -22,13 +22,13 @@ See the AUTHORS file for names of contributors. #pragma once #include "rpc/client_config.h" -#include "rpc/server_config.h" +#include "rpc/client_monitor.h" +#include "rpc/http_caller.h" +#include "rpc/monitor_factory.h" +#include "rpc/mqtt_caller.h" #include "rpc/phxrpc.pb.h" -#include "rpc/hsha_server.h" +#include "rpc/resource_pool.h" +#include "rpc/server.h" #include "rpc/socket_stream_phxrpc.h" #include "rpc/uthread_caller.h" -#include "rpc/http_caller.h" -#include "rpc/client_monitor.h" -#include "rpc/server_monitor.h" -#include "rpc/monitor_factory.h" -#include "rpc/server_base.h" + diff --git a/phxrpc/rpc/Makefile b/phxrpc/rpc/Makefile index fb1850f..9ff9c2e 100644 --- a/phxrpc/rpc/Makefile +++ b/phxrpc/rpc/Makefile @@ -1,7 +1,6 @@ - include ../../phxrpc.mk -TEST_TARGETS = test_thread_queue test_hsha_server test_client \ +TEST_TARGETS = test_thread_queue test_hsha_server test_http_client test_mqtt_client \ all: $(TEST_TARGETS) @@ -11,9 +10,13 @@ test_thread_queue: test_thread_queue.o test_hsha_server: test_hsha_server.o $(LINKER) $^ -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -o $@ -test_client: test_client.o +test_http_client: test_http_client.o + $(LINKER) $^ -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -o $@ + +test_mqtt_client: test_mqtt_client.o $(LINKER) $^ -L$(PHXRPC_ROOT)/lib -lphxrpc $(LDFLAGS) -o $@ - + clean: @( $(RM) $(TEST_TARGETS) ) @( $(RM) *.o core.* $(LIB_OBJS) ) + diff --git a/phxrpc/rpc/base_server.cpp b/phxrpc/rpc/base_server.cpp new file mode 100644 index 0000000..4d18240 --- /dev/null +++ b/phxrpc/rpc/base_server.cpp @@ -0,0 +1,624 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "base_server.h" + +#include +#include +#include +#include +#include +#include + +#include "phxrpc/file.h" +#include "phxrpc/http.h" +#include "phxrpc/mqtt.h" +#include "phxrpc/msg.h" +#include "phxrpc/network.h" + +#include "server_monitor.h" +#include "monitor_factory.h" + + +using namespace std; + + +namespace phxrpc { + + +DataFlow::DataFlow() { +} + +DataFlow::~DataFlow() { +} + +void DataFlow::PushRequest(void *args, BaseRequest *req) { + in_queue_.push(make_pair(QueueExtData(args), req)); +} + +int DataFlow::PluckRequest(void *&args, BaseRequest *&req) { + pair rp; + bool succ = in_queue_.pluck(rp); + if (!succ) { + return 0; + } + args = rp.first.args; + req = rp.second; + + auto now_time = Timer::GetSteadyClockMS(); + return now_time > rp.first.enqueue_time_ms ? now_time - rp.first.enqueue_time_ms : 0; +} + +int DataFlow::PickRequest(void *&args, BaseRequest *&req) { + pair rp; + bool succ = in_queue_.pick(rp); + if (!succ) { + return 0; + } + args = rp.first.args; + req = rp.second; + + auto now_time(Timer::GetSteadyClockMS()); + return now_time > rp.first.enqueue_time_ms ? now_time - rp.first.enqueue_time_ms : 0; +} + +void DataFlow::PushResponse(void *args, BaseResponse *resp) { + out_queue_.push(make_pair(QueueExtData(args), resp)); +} + +int DataFlow::PluckResponse(void *&args, BaseResponse *&resp) { + pair rp; + bool succ = out_queue_.pluck(rp); + if (!succ) { + return 0; + } + args = rp.first.args; + resp = rp.second; + + auto now_time(Timer::GetSteadyClockMS()); + return now_time > rp.first.enqueue_time_ms ? now_time - rp.first.enqueue_time_ms : 0; +} + +int DataFlow::PickResponse(void *&args, BaseResponse *&resp) { + pair rp; + bool succ = out_queue_.pick(rp); + if (!succ) { + return 0; + } + args = rp.first.args; + resp = rp.second; + + auto now_time(Timer::GetSteadyClockMS()); + return now_time > rp.first.enqueue_time_ms ? now_time - rp.first.enqueue_time_ms : 0; +} + +bool DataFlow::CanPushRequest(const int max_queue_length) { + return in_queue_.size() < (size_t)max_queue_length; +} + +bool DataFlow::CanPluckRequest() { + return !in_queue_.empty(); +} + +bool DataFlow::CanPluckResponse() { + return !out_queue_.empty(); +} + +void DataFlow::BreakOut() { + in_queue_.break_out(); + out_queue_.break_out(); +} + + +HshaServerStat::TimeCost::TimeCost() { + now_time_ms_ = Timer::GetSteadyClockMS(); +} + +HshaServerStat::TimeCost::~TimeCost() { +} + +int HshaServerStat::TimeCost::Cost() { + auto now_time_ms = Timer::GetSteadyClockMS(); + auto cost_time_ms = now_time_ms > now_time_ms_ ? now_time_ms - now_time_ms_ : 0; + now_time_ms_ = now_time_ms; + return cost_time_ms; +} + +HshaServerStat::HshaServerStat(const HshaServerConfig *config, ServerMonitorPtr hsha_server_monitor) : + /* config_(config), */ thread_(&HshaServerStat::CalFunc, this), break_out_(false), + hsha_server_monitor_(hsha_server_monitor) { + hold_fds_ = 0; + accepted_fds_ = 0; + accept_qps_ = 0; + rejected_fds_ = 0; + reject_qps_ = 0; + queue_full_rejected_after_accepted_fds_ = 0; + queue_full_rejected_after_accepted_qps_ = 0; + accept_fail_ = 0; + accept_fail_qps_ = 0; + + io_read_requests_ = 0; + io_read_request_qps_ = 0; + io_read_bytes_ = 0; + + io_write_responses_ = 0; + io_write_response_qps_ = 0; + io_write_bytes_ = 0; + + io_read_fails_ = 0; + io_read_fail_qps_ = 0; + io_write_fails_ = 0; + io_write_fail_qps_ = 0; + + inqueue_push_requests_ = 0; + inqueue_push_qps_ = 0; + inqueue_pop_requests_ = 0; + inqueue_pop_qps_ = 0; + + outqueue_push_responses_ = 0; + outqueue_push_qps_ = 0; + outqueue_pop_responses_ = 0; + outqueue_pop_qps_ = 0; + + worker_timeouts_ = 0; + worker_timeout_qps_ = 0; + + rpc_time_costs_ = 0; + rpc_time_costs_count_ = 0; + rpc_avg_time_cost_per_second_ = 0; + rpc_time_cost_per_period_ = 0; + + inqueue_wait_time_costs_ = 0; + inqueue_wait_time_costs_count_ = 0; + inqueue_avg_wait_time_costs_per_second_ = 0; + inqueue_avg_wait_time_costs_per_second_cal_seq_ = 0; + inqueue_wait_time_costs_per_period_ = 0; + + outqueue_wait_time_costs_ = 0; + outqueue_wait_time_costs_count_ = 0; + outqueue_wait_time_costs_per_period_ = 0; + outqueue_avg_wait_time_costs_per_second_ = 0; + + enqueue_fast_rejects_ = 0; + enqueue_fast_reject_qps_ = 0; + + worker_idles_ = 0; + + worker_drop_requests_ = 0; + worker_drop_reqeust_qps_ = 0; + worker_time_costs_ = 0; + worker_time_costs_count_ = 0; + worker_avg_time_cost_per_second_ = 0; + worker_time_cost_per_period_ = 0; + worker_time_costs_per_second_ = 0; +} + +HshaServerStat::~HshaServerStat() { + break_out_ = true; + cv_.notify_all(); + thread_.join(); +} + +void HshaServerStat::MonitorReport() { + // accept + hsha_server_monitor_->Accept(accept_qps_); + hsha_server_monitor_->AcceptFail(accept_fail_qps_); + hsha_server_monitor_->FastRejectAfterAccept(reject_qps_); + + // io + hsha_server_monitor_->ReadError(io_read_fail_qps_); + hsha_server_monitor_->SendError(io_write_fail_qps_); + hsha_server_monitor_->OutOfQueue(queue_full_rejected_after_accepted_qps_); + hsha_server_monitor_->QueueDelay(rpc_time_cost_per_period_); + hsha_server_monitor_->FastRejectAfterRead(enqueue_fast_reject_qps_); + hsha_server_monitor_->RecvBytes(io_read_bytes_qps_); + hsha_server_monitor_->SendBytes(io_write_bytes_qps_); + hsha_server_monitor_->WaitInInQueue(inqueue_wait_time_costs_per_period_); + hsha_server_monitor_->WaitInOutQueue(outqueue_wait_time_costs_per_period_); + + // worker + hsha_server_monitor_->RequestCount(accept_qps_); + hsha_server_monitor_->ResponseCount(io_write_response_qps_); + hsha_server_monitor_->RequestCost(worker_time_costs_per_second_); + hsha_server_monitor_->WrokerInQueueTimeout(worker_drop_reqeust_qps_); +} + +void HshaServerStat::CalFunc() { + while (!break_out_) { + unique_lock lock(mutex_); + cv_.wait_for(lock, chrono::seconds(1)); + + //acceptor + accept_qps_ = static_cast(accepted_fds_); + accepted_fds_ = 0; + reject_qps_ = static_cast(rejected_fds_); + rejected_fds_ = 0; + queue_full_rejected_after_accepted_qps_ = static_cast(queue_full_rejected_after_accepted_fds_); + queue_full_rejected_after_accepted_fds_ = 0; + accept_fail_qps_ = static_cast(accept_fail_); + accept_fail_ = 0; + + //io + io_read_request_qps_ = static_cast(io_read_requests_); + io_read_requests_ = 0; + io_write_response_qps_ = static_cast(io_write_responses_); + io_write_responses_ = 0; + + io_read_bytes_qps_ = static_cast(io_read_bytes_); + io_read_bytes_ = 0; + io_write_bytes_qps_ = static_cast(io_write_bytes_); + io_write_bytes_ = 0; + + io_read_fail_qps_ = static_cast(io_read_fails_); + io_read_fails_ = 0; + io_write_fail_qps_ = static_cast(io_write_fails_); + io_write_fails_ = 0; + + //queue + inqueue_push_qps_ = static_cast(inqueue_push_requests_); + inqueue_push_requests_ = 0; + inqueue_pop_qps_ = static_cast(inqueue_pop_requests_); + inqueue_pop_requests_ = 0; + + outqueue_push_qps_ = static_cast(outqueue_push_responses_); + outqueue_push_responses_ = 0; + outqueue_pop_qps_ = static_cast(outqueue_pop_responses_); + outqueue_pop_responses_ = 0; + + //worker + worker_timeout_qps_ = static_cast(worker_timeouts_); + worker_timeouts_ = 0; + + //time cost + rpc_time_cost_per_period_ = 0; + if (rpc_time_costs_count_ >= RPC_TIME_COST_CAL_RATE) { + rpc_avg_time_cost_per_second_ = + static_cast(rpc_time_costs_) / rpc_time_costs_count_; + rpc_time_cost_per_period_ = static_cast(rpc_time_costs_); + rpc_time_costs_ = 0; + rpc_time_costs_count_ = 0; + } + + //worker time cost + worker_time_cost_per_period_ = 0; + if (worker_time_costs_count_ >= RPC_TIME_COST_CAL_RATE) { + worker_avg_time_cost_per_second_ = + static_cast(worker_time_costs_) / worker_time_costs_count_; + worker_time_cost_per_period_ = static_cast(worker_time_costs_); + worker_time_costs_ = 0; + worker_time_costs_count_ = 0; + } + + inqueue_wait_time_costs_per_period_ = 0; + if (inqueue_wait_time_costs_count_ >= QUEUE_WAIT_TIME_COST_CAL_RATE) { + inqueue_avg_wait_time_costs_per_second_ = + static_cast(inqueue_wait_time_costs_) / inqueue_wait_time_costs_count_; + inqueue_wait_time_costs_per_period_ = static_cast(inqueue_wait_time_costs_); + inqueue_wait_time_costs_ = 0; + inqueue_wait_time_costs_count_ = 0; + inqueue_avg_wait_time_costs_per_second_cal_seq_++; + } + + outqueue_wait_time_costs_per_period_ = 0; + if (outqueue_wait_time_costs_count_ >= QUEUE_WAIT_TIME_COST_CAL_RATE) { + outqueue_avg_wait_time_costs_per_second_ = + static_cast(outqueue_wait_time_costs_) / outqueue_wait_time_costs_count_; + outqueue_wait_time_costs_per_period_ = static_cast(outqueue_wait_time_costs_); + outqueue_wait_time_costs_ = 0; + outqueue_wait_time_costs_count_ = 0; + } + + enqueue_fast_reject_qps_ = static_cast(enqueue_fast_rejects_); + enqueue_fast_rejects_ = 0; + + worker_drop_reqeust_qps_ = static_cast(worker_drop_requests_); + worker_drop_requests_ = 0; + + worker_time_costs_per_second_ = static_cast(worker_time_costs_); + worker_time_costs_ = 0; + + MonitorReport(); + + phxrpc::log(LOG_NOTICE, "[SERVER_STAT] hold_fds %d accept_qps %d accept_reject_qps %d queue_full_reject_qps %d" + " read_request_qps %d write_response_qps %d" + " inqueue_push_qps %d rpc_time_cost_avg %d worker_time_cost_avg %d" + " inqueue_wait_time_avg %d outqueue_wait_time_qvg %d" + " fast_reject_qps %d" + " worker_idles %d worker_drop_request_qps %d io_read_fails %d, io_write_fails %d", + static_cast(hold_fds_), accept_qps_, reject_qps_, queue_full_rejected_after_accepted_qps_, + io_read_request_qps_, io_write_response_qps_, + inqueue_push_qps_, rpc_avg_time_cost_per_second_, worker_avg_time_cost_per_second_, + inqueue_avg_wait_time_costs_per_second_, outqueue_avg_wait_time_costs_per_second_, + enqueue_fast_reject_qps_, + static_cast(worker_idles_), worker_drop_reqeust_qps_, io_read_fail_qps_, io_write_fail_qps_ ); + + } +} + + +HshaServerQos::HshaServerQos(const HshaServerConfig *config, HshaServerStat *hsha_server_stat) + : config_(config), hsha_server_stat_(hsha_server_stat), + thread_(&HshaServerQos::CalFunc, this) { +} + +HshaServerQos::~HshaServerQos() { + break_out_ = true; + cv_.notify_all(); + thread_.join(); +} + +bool HshaServerQos::CanAccept() { + return static_cast(hsha_server_stat_->hold_fds_) < config_->GetMaxConnections(); +} + +bool HshaServerQos::CanEnqueue() { + static default_random_engine e_rand((int)time(nullptr)); + return ((int)(e_rand() % 100)) >= enqueue_reject_rate_; +} + +void HshaServerQos::CalFunc() { + while (!break_out_) { + unique_lock lock(mutex_); + cv_.wait_for(lock, chrono::seconds(1)); + + //fast reject + if (hsha_server_stat_->inqueue_avg_wait_time_costs_per_second_cal_seq_ + != inqueue_avg_wait_time_costs_per_second_cal_last_seq_) { + //inqueue avg wait time reflesh + int avg_queue_wait_time = (hsha_server_stat_->inqueue_avg_wait_time_costs_per_second_ + + hsha_server_stat_->outqueue_avg_wait_time_costs_per_second_) / 2; + + int rate = config_->GetFastRejectAdjustRate(); + if (avg_queue_wait_time > config_->GetFastRejectThresholdMS()) { + if (enqueue_reject_rate_ != 99) { + enqueue_reject_rate_ = enqueue_reject_rate_ + rate > 99 ? 99 : enqueue_reject_rate_ + rate; + } + } else { + if (enqueue_reject_rate_ != 0) { + enqueue_reject_rate_ = enqueue_reject_rate_ - rate < 0 ? 0 : enqueue_reject_rate_ - rate; + } + } + inqueue_avg_wait_time_costs_per_second_cal_last_seq_ = + hsha_server_stat_->inqueue_avg_wait_time_costs_per_second_cal_seq_; + } + + phxrpc::log(LOG_NOTICE, "[SERVER_QOS] accept_reject_qps %d queue_full_reject_qps %d" + " fast_reject_qps %d fast_reject_rate %d", + hsha_server_stat_->reject_qps_, hsha_server_stat_->queue_full_rejected_after_accepted_qps_, + hsha_server_stat_->enqueue_fast_reject_qps_, enqueue_reject_rate_); + } +} + + +NotifierPoolRouter::NotifierId::NotifierId(const uint64_t session_id_value, + const uint32_t packet_id_value) + : session_id(session_id_value), packet_id(packet_id_value) { +} + +__uint128_t NotifierPoolRouter::NotifierId::ToUint128() const { + return (static_cast<__uint128_t>(session_id) << 64 | packet_id); +} + +void NotifierPoolRouter::NotifierId::FromUint128(const __uint128_t &value) { + session_id = static_cast(value >> 64); + packet_id = static_cast(value); +} + + +void NotifierPoolRouter::Add(const NotifierId ¬ifier_id, const pair idx) { + Add(move(notifier_id.ToUint128()), idx); +} + +pair NotifierPoolRouter::Get(const NotifierId ¬ifier_id) const { + return Get(move(notifier_id.ToUint128())); +} + +void NotifierPoolRouter::Delete(const NotifierId ¬ifier_id) { + Delete(move(notifier_id.ToUint128())); +} + +void NotifierPoolRouter::Add(const __uint128_t &session_packet_id, const pair idx) { + lock_guard lock(mutex_); + session_packet_id2idx_map_[session_packet_id] = idx; +} + +pair NotifierPoolRouter::Get(const __uint128_t &session_packet_id) const { + lock_guard lock(mutex_); + const auto &it(session_packet_id2idx_map_.find(session_packet_id)); + if (session_packet_id2idx_map_.end() == it) { + return make_pair(-1, -1); + } + + return it->second; +} + +void NotifierPoolRouter::Delete(const __uint128_t &session_packet_id) { + lock_guard lock(mutex_); + session_packet_id2idx_map_.erase(session_packet_id); +} + + +Worker::Worker(const int idx, WorkerPool *const pool, + const int uthread_count, int uthread_stack_size) + : idx_(idx), pool_(pool), uthread_count_(uthread_count), + uthread_stack_size_(uthread_stack_size), + thread_(&Worker::Func, this) { +} + +Worker::~Worker() { + thread_.join(); + delete worker_scheduler_; +} + +void Worker::Func() { + if (uthread_count_ == 0) { + ThreadMode(); + } else { + UThreadMode(); + } +} + +void Worker::ThreadMode() { + while (!shut_down_) { + pool_->hsha_server_stat_->worker_idles_++; + + void *args{nullptr}; + BaseRequest *request{nullptr}; + int queue_wait_time_ms{pool_->data_flow_->PluckRequest(args, request)}; + if (request == nullptr) { + //break out + continue; + } + pool_->hsha_server_stat_->worker_idles_--; + + WorkerLogic(args, request, queue_wait_time_ms); + } +} + +void Worker::UThreadMode() { + worker_scheduler_ = new UThreadEpollScheduler(uthread_stack_size_, uthread_count_, true); + assert(worker_scheduler_ != nullptr); + worker_scheduler_->SetHandlerNewRequestFunc(bind(&Worker::HandlerNewRequestFunc, this)); + notifier_pool_ = new UThreadNotifierPool(worker_scheduler_, pool_->config_->GetSocketTimeoutMS()); + worker_scheduler_->RunForever(); +} + +void Worker::HandlerNewRequestFunc() { + if (worker_scheduler_->IsTaskFull()) { + return; + } + + void *args{nullptr}; + BaseRequest *request{nullptr}; + int queue_wait_time_ms{pool_->data_flow_->PickRequest(args, request)}; + if (!request) { + return; + } + + worker_scheduler_->AddTask(bind(&Worker::UThreadFunc, this, args, + request, queue_wait_time_ms), nullptr); +} + +void Worker::UThreadFunc(void *args, BaseRequest *req, int queue_wait_time_ms) { + WorkerLogic(args, req, queue_wait_time_ms); +} + +void Worker::WorkerLogic(void *args, BaseRequest *req, int queue_wait_time_ms) { + pool_->hsha_server_stat_->inqueue_pop_requests_++; + pool_->hsha_server_stat_->inqueue_wait_time_costs_ += queue_wait_time_ms; + pool_->hsha_server_stat_->inqueue_wait_time_costs_count_++; + + BaseResponse *resp{req->GenResponse()}; + if (queue_wait_time_ms < MAX_QUEUE_WAIT_TIME_COST) { + HshaServerStat::TimeCost time_cost; + + DispatcherArgs_t dispatcher_args(pool_->idx_, idx_, pool_->hsha_server_stat_->hsha_server_monitor_, + worker_scheduler_, pool_->root_server_, pool_->base_server_unit_, + notifier_pool_, pool_->notifier_pool_router_, + pool_->args_, args); + pool_->dispatch_(req, resp, &dispatcher_args); + + pool_->hsha_server_stat_->worker_time_costs_ += time_cost.Cost(); + pool_->hsha_server_stat_->worker_time_costs_count_++; + } else { + pool_->hsha_server_stat_->worker_drop_requests_++; + } + // fa should also PushResponse, otherwise session_id (which args points to) will memory leak + pool_->data_flow_->PushResponse(args, resp); + pool_->hsha_server_stat_->outqueue_push_responses_++; + + pool_->scheduler_->NotifyEpoll(); + + delete req; +} + +void Worker::NotifyEpoll() { + if (uthread_count_ == 0) { + return; + } + + worker_scheduler_->NotifyEpoll(); +} + +int Worker::NotifyTarget(const NotifierPoolRouter::NotifierId ¬ifier_id, void *const data) { + UThreadNotifier *notifier{nullptr}; + notifier_pool_->GetNotifier(move(notifier_id.ToUint128()), notifier); + if (!notifier) + return -1; + + return notifier->SendNotify(data); +} + +void Worker::Shutdown() { + shut_down_ = true; + pool_->data_flow_->BreakOut(); +} + + +WorkerPool::WorkerPool(const int idx, + UThreadEpollScheduler *scheduler, + const HshaServerConfig *config, + const int thread_count, + const int uthread_count_per_thread, + const int uthread_stack_size, + Server *const root_server, + BaseServerUnit *const base_server_unit, + NotifierPoolRouter *const notifier_pool_router, + DataFlow *const data_flow, + HshaServerStat *const hsha_server_stat, + Dispatch_t dispatch, + void *args) + : idx_(idx), scheduler_(scheduler), config_(config), root_server_(root_server), base_server_unit_(base_server_unit), + notifier_pool_router_(notifier_pool_router), + data_flow_(data_flow), + hsha_server_stat_(hsha_server_stat), dispatch_(dispatch), + args_(args), last_notify_idx_(0) { + for (int i{0}; i < thread_count; ++i) { + auto worker(new Worker(i, this, uthread_count_per_thread, uthread_stack_size)); + assert(worker != nullptr); + worker_list_.push_back(worker); + } +} + +WorkerPool::~WorkerPool() { + for (auto &worker : worker_list_) { + worker->Shutdown(); + delete worker; + } +} + +void WorkerPool::NotifyEpoll() { + lock_guard lock(mutex_); + if (last_notify_idx_ == worker_list_.size()) { + last_notify_idx_ = 0; + } + + worker_list_[last_notify_idx_++]->NotifyEpoll(); +} + +int WorkerPool::NotifyTarget(const int idx, const NotifierPoolRouter::NotifierId ¬ifier_id, + void *const data) { + return worker_list_[idx]->NotifyTarget(notifier_id, data); +} + + +} //namespace phxrpc + diff --git a/phxrpc/rpc/base_server.h b/phxrpc/rpc/base_server.h new file mode 100644 index 0000000..5ad174c --- /dev/null +++ b/phxrpc/rpc/base_server.h @@ -0,0 +1,333 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "server_config.h" +#include "thread_queue.h" + +#include "phxrpc/network.h" +#include "phxrpc/msg.h" +#include "server_base.h" +#include "server_monitor.h" + + +namespace phxrpc { + + +class DataFlow final { + public: + DataFlow(); + ~DataFlow(); + + void PushRequest(void *args, BaseRequest *req); + int PluckRequest(void *&args, BaseRequest *&req); + int PickRequest(void *&args, BaseRequest *&req); + void PushResponse(void *args, BaseResponse *resp); + int PluckResponse(void *&args, BaseResponse *&resp); + int PickResponse(void *&args, BaseResponse *&resp); + bool CanPushRequest(const int max_queue_length); + bool CanPluckRequest(); + bool CanPluckResponse(); + + void BreakOut(); + + private: + struct QueueExtData { + QueueExtData() { + enqueue_time_ms = 0; + args = nullptr; + } + QueueExtData(void *t_args) { + enqueue_time_ms = Timer::GetSteadyClockMS(); + args = t_args; + } + uint64_t enqueue_time_ms; + void *args; + }; + + ThdQueue> in_queue_; + ThdQueue> out_queue_; +}; + + +#define RPC_TIME_COST_CAL_RATE 1000 +#define QUEUE_WAIT_TIME_COST_CAL_RATE 1000 +#define MAX_QUEUE_WAIT_TIME_COST 500 +#define MAX_ACCEPT_QUEUE_LENGTH 102400 + + +class WorkerPool; + +class HshaServerStat final { + public: + HshaServerStat(const HshaServerConfig *config, ServerMonitorPtr hsha_server_monitor); + ~HshaServerStat(); + + void CalFunc(); + + class TimeCost { + public: + TimeCost(); + ~TimeCost(); + int Cost(); + private: + uint64_t now_time_ms_; + }; + + private: + void MonitorReport(); + + friend class HshaServerIO; + friend class FaServerIO; + friend class WorkerPool; + friend class Worker; + friend class HshaServerQos; + friend class HshaServerAcceptor; + friend class FaServerAcceptor; + //const HshaServerConfig *config_; + std::mutex mutex_; + std::condition_variable cv_; + std::thread thread_; + bool break_out_; + ServerMonitorPtr hsha_server_monitor_; + + std::atomic_int hold_fds_; + std::atomic_int accepted_fds_; + int accept_qps_; + std::atomic_int rejected_fds_; + int reject_qps_; + std::atomic_int queue_full_rejected_after_accepted_fds_; + int queue_full_rejected_after_accepted_qps_; + std::atomic_int accept_fail_; + int accept_fail_qps_; + + std::atomic_int io_read_requests_; + int io_read_request_qps_; + std::atomic_int io_write_responses_; + int io_write_response_qps_; + + std::atomic_int io_read_bytes_; + int io_read_bytes_qps_; + std::atomic_int io_write_bytes_; + int io_write_bytes_qps_; + + std::atomic_int io_read_fails_; + int io_read_fail_qps_; + std::atomic_int io_write_fails_; + int io_write_fail_qps_; + + std::atomic_int inqueue_push_requests_; + int inqueue_push_qps_; + std::atomic_int inqueue_pop_requests_; + int inqueue_pop_qps_; + + std::atomic_int outqueue_push_responses_; + int outqueue_push_qps_; + std::atomic_int outqueue_pop_responses_; + int outqueue_pop_qps_; + + std::atomic_int worker_timeouts_; + int worker_timeout_qps_; + + std::atomic_long rpc_time_costs_; + std::atomic_int rpc_time_costs_count_; + int rpc_avg_time_cost_per_second_; + int rpc_time_cost_per_period_; + + std::atomic_long inqueue_wait_time_costs_; + std::atomic_int inqueue_wait_time_costs_count_; + int inqueue_avg_wait_time_costs_per_second_; + int inqueue_avg_wait_time_costs_per_second_cal_seq_; + long inqueue_wait_time_costs_per_period_; + + std::atomic_long outqueue_wait_time_costs_; + std::atomic_int outqueue_wait_time_costs_count_; + int outqueue_avg_wait_time_costs_per_second_; + long outqueue_wait_time_costs_per_period_; + + std::atomic_int enqueue_fast_rejects_; + int enqueue_fast_reject_qps_; + + std::atomic_int worker_idles_; + + std::atomic_int worker_drop_requests_; + int worker_drop_reqeust_qps_; + + std::atomic_long worker_time_costs_; + std::atomic_int worker_time_costs_count_; + int worker_avg_time_cost_per_second_; + int worker_time_cost_per_period_; + long worker_time_costs_per_second_; +}; + + +class HshaServerQos final { + public: + HshaServerQos(const HshaServerConfig *config, HshaServerStat *hsha_server_stat); + ~HshaServerQos(); + + void CalFunc(); + bool CanAccept(); + bool CanEnqueue(); + + private: + const HshaServerConfig *config_{nullptr}; + HshaServerStat *hsha_server_stat_{nullptr}; + std::mutex mutex_; + std::condition_variable cv_; + std::thread thread_; + bool break_out_{false}; + int enqueue_reject_rate_{0}; + int inqueue_avg_wait_time_costs_per_second_cal_last_seq_{0}; +}; + + +class NotifierPoolRouter final { + public: + struct NotifierId { + NotifierId(const uint64_t session_id_value, const uint32_t packet_id_value); + + __uint128_t ToUint128() const; + void FromUint128(const __uint128_t &value); + + uint64_t session_id{0uLL}; + uint32_t packet_id{0u}; + }; + + void Add(const NotifierId ¬ifier_id, const std::pair idx); + std::pair Get(const NotifierId ¬ifier_id) const; + void Delete(const NotifierId ¬ifier_id); + + private: + void Add(const __uint128_t &session_packet_id, const std::pair idx); + std::pair Get(const __uint128_t &session_packet_id) const; + void Delete(const __uint128_t &session_packet_id); + + mutable std::mutex mutex_; + std::map<__uint128_t, std::pair> session_packet_id2idx_map_; +}; + + +class Worker final { + public: + Worker(const int idx, WorkerPool *const pool, + const int uthread_count, const int uthread_stack_size); + ~Worker(); + + void Func(); + void Shutdown(); + + void ThreadMode(); + void UThreadMode(); + void HandlerNewRequestFunc(); + void UThreadFunc(void *args, BaseRequest *req, int queue_wait_time_ms); + void WorkerLogic(void *args, BaseRequest *req, int queue_wait_time_ms); + void NotifyEpoll(); + int NotifyTarget(const NotifierPoolRouter::NotifierId ¬ifier_id, void *const data); + + UThreadNotifierPool *notifier_pool() { return notifier_pool_; } + + private: + int idx_{-1}; + WorkerPool *pool_{nullptr}; + int uthread_count_; + int uthread_stack_size_; + bool shut_down_{false}; + UThreadEpollScheduler *worker_scheduler_{nullptr}; + // TODO: support thread mode + UThreadNotifierPool *notifier_pool_{nullptr}; + std::thread thread_; +}; + + +typedef std::function Dispatch_t; + +class Server; +class BaseServerUnit; + +class WorkerPool final { + public: + WorkerPool(const int idx, UThreadEpollScheduler *scheduler, + const HshaServerConfig *config, + const int thread_count, + const int uthread_count_per_thread, + const int uthread_stack_size, + Server *const root_server, + BaseServerUnit *const base_server_unit, + NotifierPoolRouter *const notifier_pool_router, + DataFlow *const data_flow, + HshaServerStat *const hsha_server_stat, + Dispatch_t dispatch, + void *args); + ~WorkerPool(); + + void NotifyEpoll(); + int NotifyTarget(const int idx, const NotifierPoolRouter::NotifierId ¬ifier_id, void *const data); + + private: + friend class Worker; + int idx_{-1}; + UThreadEpollScheduler *scheduler_{nullptr}; + const HshaServerConfig *config_{nullptr}; + Server *root_server_{nullptr}; + BaseServerUnit *base_server_unit_{nullptr}; + NotifierPoolRouter *notifier_pool_router_{nullptr}; + DataFlow *data_flow_{nullptr}; + HshaServerStat *hsha_server_stat_{nullptr}; + Dispatch_t dispatch_; + void *args_{nullptr}; + std::vector worker_list_; + size_t last_notify_idx_; + std::mutex mutex_; +}; + + +class BaseServerUnit { + public: + BaseServerUnit() = default; + virtual ~BaseServerUnit() = default; + + protected: + DataFlow data_flow_; +}; + + +class BaseServer { + public: + BaseServer() = default; + virtual ~BaseServer() = default; + + virtual void DoRunForever() = 0; +}; + + +} //namespace phxrpc + diff --git a/phxrpc/rpc/client_config.cpp b/phxrpc/rpc/client_config.cpp index a6ae018..8c23bb0 100644 --- a/phxrpc/rpc/client_config.cpp +++ b/phxrpc/rpc/client_config.cpp @@ -1,26 +1,26 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include -#include +#include +#include #include #include "client_config.h" @@ -29,8 +29,10 @@ See the AUTHORS file for names of contributors. #include "phxrpc/file.h" + namespace phxrpc { + ClientConfig::ClientConfig() { connect_timeout_ms_ = 200; socket_timeout_ms_ = 5000; @@ -40,35 +42,36 @@ ClientConfig::ClientConfig() { ClientConfig::~ClientConfig() { } -void ClientConfig :: SetClientMonitor( ClientMonitorPtr client_monitor ) { +void ClientConfig::SetClientMonitor(ClientMonitorPtr client_monitor) { client_monitor_ = client_monitor; } -ClientMonitorPtr ClientConfig :: GetClientMonitor() { +ClientMonitorPtr ClientConfig::GetClientMonitor() { return client_monitor_; } -bool ClientConfig::Read(const char * config_file) { +bool ClientConfig::Read(const char *config_file) { Config config; if (!config.InitConfig(config_file)) { return false; } - int count = 0; - bool succ = true; + int count{0}; + bool succ{true}; succ &= config.ReadItem("Server", "ServerCount", &count); - succ &= config.ReadItem("Server", "PackageName", package_name_, sizeof(package_name_)); if (!succ) { - log(LOG_ERR, "Config::%s key ServerCount | PackageName not found", __func__); + log(LOG_ERR, "Config::%s key ServerCount not found", __func__); return false; } - for (int i = 0; i < count; i++) { - char section[64] = { 0 }; + config.ReadItem("Server", "PackageName", package_name_, sizeof(package_name_)); + + for (int i{0}; count > i; ++i) { + char section[64]{0}; snprintf(section, sizeof(section), "Server%d", i); Endpoint_t ep; - bool succ = true; + bool succ{true}; succ &= config.ReadItem(section, "IP", ep.ip, sizeof(ep.ip)); succ &= config.ReadItem(section, "Port", &(ep.port)); if (!succ) { @@ -87,30 +90,32 @@ bool ClientConfig::Read(const char * config_file) { return endpoints_.size() > 0; } -const Endpoint_t * ClientConfig::GetRandom() const { - const Endpoint_t * ret = NULL; +const Endpoint_t *ClientConfig::GetRandom() const { + const Endpoint_t *ret{nullptr}; if (endpoints_.size() > 0) { ret = &(endpoints_[random() % endpoints_.size()]); } - - if ( !ret ) { - if ( client_monitor_.get() ) { + + if (!ret) { + if (client_monitor_.get()) { client_monitor_->GetEndpointFail(); } + + log(LOG_ERR, "GetRandom fail, list.size %lu", endpoints_.size()); } return ret; } -const Endpoint_t * ClientConfig::GetByIndex(const size_t index) const { - const Endpoint_t * ret = NULL; +const Endpoint_t *ClientConfig::GetByIndex(const size_t index) const { + const Endpoint_t *ret{nullptr}; if (index < endpoints_.size()) { ret = &(endpoints_[index]); } - if ( !ret ) { - if ( client_monitor_.get() ) { + if (!ret) { + if (client_monitor_.get()) { client_monitor_->GetEndpointFail(); } } @@ -125,9 +130,10 @@ int ClientConfig::GetSocketTimeoutMS() { return socket_timeout_ms_; } -const char * ClientConfig :: GetPackageName() const { +const char *ClientConfig::GetPackageName() const { return package_name_; } -} + +} // namespace phxrpc diff --git a/phxrpc/rpc/client_config.h b/phxrpc/rpc/client_config.h index 96e26ad..b2b3b97 100644 --- a/phxrpc/rpc/client_config.h +++ b/phxrpc/rpc/client_config.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -23,40 +23,43 @@ See the AUTHORS file for names of contributors. #include "client_monitor.h" +#include #include #include -#include + namespace phxrpc { + typedef struct tagEndpoint { char ip[32]; int port; } Endpoint_t; + class ClientConfig { - public: + public: ClientConfig(); - ~ClientConfig(); + virtual ~ClientConfig(); - bool Read(const char * config_file); + bool Read(const char *config_file); - const Endpoint_t * GetRandom() const; + const Endpoint_t *GetRandom() const; - const Endpoint_t * GetByIndex(const size_t index) const; + const Endpoint_t *GetByIndex(const size_t index) const; int GetConnectTimeoutMS(); int GetSocketTimeoutMS(); - const char * GetPackageName() const; + const char *GetPackageName() const; - void SetClientMonitor( ClientMonitorPtr client_monitor ); + void SetClientMonitor(ClientMonitorPtr client_monitor); ClientMonitorPtr GetClientMonitor(); - private: + private: std::vector endpoints_; int connect_timeout_ms_; @@ -67,5 +70,6 @@ class ClientConfig { ClientMonitorPtr client_monitor_; }; -} + +} // namespace phxrpc diff --git a/phxrpc/rpc/client_monitor.cpp b/phxrpc/rpc/client_monitor.cpp index 5856933..191f415 100644 --- a/phxrpc/rpc/client_monitor.cpp +++ b/phxrpc/rpc/client_monitor.cpp @@ -1,69 +1,70 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include +#include #include #include #include "client_monitor.h" - + + namespace phxrpc { -//ClientMonitor begin -ClientMonitor :: ClientMonitor() { -} -ClientMonitor :: ~ClientMonitor() { +ClientMonitor::ClientMonitor() { } -void ClientMonitor :: ClientConnect( bool result ) { +ClientMonitor::~ClientMonitor() { } -void ClientMonitor :: SendBytes( size_t bytes ) { +void ClientMonitor::ClientConnect(bool result) { } -void ClientMonitor :: RecvBytes( size_t bytes ) { +void ClientMonitor::SendBytes(size_t bytes) { } -void ClientMonitor :: RequestCost( uint64_t begin_time, uint64_t end_time ) { +void ClientMonitor::RecvBytes(size_t bytes) { } -void ClientMonitor :: SendError() { +void ClientMonitor::RequestCost(uint64_t begin_time, uint64_t end_time) { } -void ClientMonitor :: SendCount() { +void ClientMonitor::SendError() { } -void ClientMonitor :: RecvError() { +void ClientMonitor::SendCount() { } -void ClientMonitor :: RecvCount() { +void ClientMonitor::RecvError() { } -void ClientMonitor :: GetEndpointFail() { +void ClientMonitor::RecvCount() { } -void ClientMonitor :: ClientCall( int cmdid, const char * method_name ) { +void ClientMonitor::GetEndpointFail() { } -//ClientMonitor end +void ClientMonitor::ClientCall(const int cmd_id, const char *method_name) { } + +} // namespace phxrpc + diff --git a/phxrpc/rpc/client_monitor.h b/phxrpc/rpc/client_monitor.h index 2514084..f4ce913 100644 --- a/phxrpc/rpc/client_monitor.h +++ b/phxrpc/rpc/client_monitor.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,41 +21,43 @@ See the AUTHORS file for names of contributors. #pragma once -#include + +#include #include #include + namespace phxrpc { class ClientMonitor { - public: + public: ClientMonitor(); virtual ~ClientMonitor(); - virtual void ClientConnect( bool result ); + virtual void ClientConnect(bool result); - virtual void SendBytes( size_t bytes ); + virtual void SendBytes(size_t bytes); virtual void SendError(); virtual void SendCount(); - virtual void RecvBytes( size_t bytes ); + virtual void RecvBytes(size_t bytes); virtual void RecvCount(); virtual void RecvError(); - virtual void RequestCost( uint64_t begin_time, uint64_t end_time ); + virtual void RequestCost(uint64_t begin_time, uint64_t end_time); virtual void GetEndpointFail(); - virtual void ClientCall( int cmd, const char * method_name ); + virtual void ClientCall(const int cmd_id, const char *method_name); }; typedef std::shared_ptr ClientMonitorPtr; -} +} // namespace phxrpc diff --git a/phxrpc/rpc/fa_server.cpp b/phxrpc/rpc/fa_server.cpp new file mode 100644 index 0000000..fe23725 --- /dev/null +++ b/phxrpc/rpc/fa_server.cpp @@ -0,0 +1,568 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "fa_server.h" + +#include +#include +#include +#include +#include +#include + +#include "phxrpc/file.h" +#include "phxrpc/http.h" +#include "phxrpc/mqtt.h" +#include "phxrpc/msg.h" +#include "phxrpc/network.h" + +#include "server_monitor.h" +#include "monitor_factory.h" + + +using namespace std; + + +namespace phxrpc { + + +//void MqttSession::Heartbeat() { +// if (0 >= session_attribute.keep_alive) { +// expire_time_ms_ = -1; +// } else { +// expire_time_ms_ = session_attribute.keep_alive * 1000 + Timer::GetSteadyClockMS(); +// } +//} +// +//bool MqttSession::IsExpired() { +// return expire_time_ms_ <= Timer::GetSteadyClockMS(); +//} + + +MqttSession *SessionManager::Create(const int fd, UThreadEpollScheduler *const scheduler, + const int socket_timeout_ms) { + MqttSession session; + session.session_id = (Timer::GetTimestampMS() << 32) | (++s_session_num); + session.socket = scheduler->CreateSocket(fd); + UThreadSetSocketTimeout(*(session.socket), socket_timeout_ms); + session.stream.reset(new UThreadTcpStream); + session.stream->Attach(session.socket); + + sessions_.emplace_back(move(session)); + + return &(sessions_.back()); +} + +//MqttSession *SessionManager::GetByClientId(const string &client_id) { +// for (auto &&session : sessions_) { +// if (session.session_attribute.client_identifier == client_id) +// return &session; +// } +// +// return nullptr; +//} + +MqttSession *SessionManager::GetBySessionId(const uint64_t session_id) { + for (auto &&session : sessions_) { + if (session.session_id == session_id) + return &session; + } + + return nullptr; +} + +MqttSession *SessionManager::GetByFd(const int fd) { + for (auto &&session : sessions_) { + if (UThreadSocketFd(*(session.socket)) == fd) + return &session; + } + + return nullptr; +} + +void SessionManager::DeleteBySessionId(const uint64_t session_id) { + for (auto it(sessions_.begin()); sessions_.end() != it; ++it) { + if (it->session_id == session_id) { + sessions_.erase(it); + + return; + } + } +} + +atomic_uint32_t SessionManager::s_session_num{0}; + + +void SessionRouter::Add(const uint64_t session_id, const int idx) { + lock_guard lock(mutex_); + session_id2thread_index_map_[session_id] = idx; +} + +int SessionRouter::Get(const uint64_t session_id) const { + lock_guard lock(mutex_); + const auto &it(session_id2thread_index_map_.find(session_id)); + if (session_id2thread_index_map_.end() == it) { + return -1; + } + + return it->second; +} + +void SessionRouter::Delete(const uint64_t session_id) { + lock_guard lock(mutex_); + session_id2thread_index_map_.erase(session_id); +} + + +FaServerIO::FaServerIO(const int idx, UThreadEpollScheduler *const scheduler, + const HshaServerConfig *config, DataFlow *data_flow, + HshaServerStat *hsha_server_stat, HshaServerQos *hsha_server_qos, + WorkerPool *worker_pool, SessionManager *session_mgr, + SessionRouter *session_router) + : idx_(idx), scheduler_(scheduler), config_(config), data_flow_(data_flow), + hsha_server_stat_(hsha_server_stat), + hsha_server_qos_(hsha_server_qos), worker_pool_(worker_pool), + session_mgr_(session_mgr), session_router_(session_router) { +} + +FaServerIO::~FaServerIO() { +} + +bool FaServerIO::AddAcceptedFd(int accepted_fd) { + lock_guard lock(queue_mutex_); + if (accepted_fd_list_.size() > MAX_ACCEPT_QUEUE_LENGTH) { + return false; + } + accepted_fd_list_.push(accepted_fd); + if (static_cast(hsha_server_stat_->io_read_request_qps_) < 5000 && + static_cast(hsha_server_stat_->accept_qps_) < 5000) { + scheduler_->NotifyEpoll(); + } + return true; +} + +void FaServerIO::HandlerAcceptedFd() { + lock_guard lock(queue_mutex_); + while (!accepted_fd_list_.empty()) { + int accepted_fd = accepted_fd_list_.front(); + accepted_fd_list_.pop(); + scheduler_->AddTask(bind(&FaServerIO::UThreadIFunc, this, accepted_fd), nullptr); + } +} + +void FaServerIO::UThreadIFunc(int accepted_fd) { + MqttSession *session{session_mgr_->Create(accepted_fd, scheduler_, config_->GetSocketTimeoutMS())}; + if (!session) { + phxrpc::log(LOG_ERR, "invalid fd %d", accepted_fd); + + return; + } + + unique_ptr factory( + BaseProtocolFactory::CreateFactory(*(session->stream))); + unique_ptr protocol(factory->GenProtocol()); + + while (true) { + HshaServerStat::TimeCost time_cost; + + hsha_server_stat_->io_read_requests_++; + + // will be deleted by worker + BaseRequest *req{nullptr}; + ReturnCode ret{protocol->ServerRecv(*(session->stream), req)}; + // TODO: remove + printf("session_id %" PRIx64 " ServerRecv ret %d idx %d fd %d\n", + session->session_id, ret, idx_, accepted_fd); + if (ReturnCode::OK != ret) { + delete req; + hsha_server_stat_->io_read_fails_++; + hsha_server_stat_->rpc_time_costs_count_++; + hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); + phxrpc::log(LOG_ERR, "%s read request fail, fd %d", __func__, accepted_fd); + + break; + } + + hsha_server_stat_->io_read_bytes_ += req->GetContent().size(); + + if (!data_flow_->CanPushRequest(config_->GetMaxQueueLength())) { + delete req; + hsha_server_stat_->queue_full_rejected_after_accepted_fds_++; + + break; + } + + if (!hsha_server_qos_->CanEnqueue()) { + // fast reject don't cal rpc_time_cost; + delete req; + hsha_server_stat_->enqueue_fast_rejects_++; + phxrpc::log(LOG_ERR, "%s fast reject, can't enqueue, fd %d", + __func__, accepted_fd); + + break; + } + + // if have enqueue, request will be deleted after pop. + //const bool is_keep_alive{0 != req->IsKeepAlive()}; + //const string version(req->GetVersion() != nullptr ? req->GetVersion() : ""); + + hsha_server_stat_->inqueue_push_requests_++; + ServiceContext *context{new ServiceContext}; + context->session_id = session->session_id; + data_flow_->PushRequest((void *)context, req); + // if is uthread worker mode, need notify. + // req deleted by worker after this line + worker_pool_->NotifyEpoll(); + //UThreadSetArgs(*socket, nullptr); + + //UThreadWait(*socket, config_->GetSocketTimeoutMS()); + //if (UThreadGetArgs(*socket) == nullptr) { + // // timeout + // hsha_server_stat_->worker_timeouts_++; + // hsha_server_stat_->rpc_time_costs_count_++; + // hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); + + // // because have enqueue, so socket will be closed after pop. + // socket = stream.DetachSocket(); + // UThreadLazyDestory(*socket); + + // phxrpc::log(LOG_ERR, "%s timeout, fd %d sockettimeoutms %d", + // __func__, accepted_fd, config_->GetSocketTimeoutMS()); + // break; + //} + + //hsha_server_stat_->io_write_responses_++; + //{ + // BaseResponse *resp((BaseResponse *)UThreadGetArgs(*socket)); + // if (!resp->fake()) { + // ret = resp->ModifyResp(is_keep_alive, version); + // ret = resp->Send(stream); + // hsha_server_stat_->io_write_bytes_ += resp->GetContent().size(); + // } + // delete resp; + //} + + //hsha_server_stat_->rpc_time_costs_count_++; + //hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); + + //if (ReturnCode::OK != ret) { + // hsha_server_stat_->io_write_fails_++; + //} + + //if (!is_keep_alive || (ReturnCode::OK != ret)) { + // break; + //} + } + + hsha_server_stat_->hold_fds_--; +} + +//UThreadSocket_t *FaServerIO::ActiveSocketFunc() { +// while (data_flow_->CanPluckResponse()) { +// void *args{nullptr}; +// BaseResponse *resp{nullptr}; +// int queue_wait_time_ms{data_flow_->PluckResponse(args, resp)}; +// if (!resp) { +// //break out +// return nullptr; +// } +// hsha_server_stat_->outqueue_wait_time_costs_ += queue_wait_time_ms; +// hsha_server_stat_->outqueue_wait_time_costs_count_++; +// +// UThreadSocket_t *socket = (UThreadSocket_t *)args; +// if (socket != nullptr && IsUThreadDestory(*socket)) { +// //socket aready timeout. +// //phxrpc::log(LOG_ERR, "%s socket aready timeout", __func__); +// UThreadClose(*socket); +// free(socket); +// delete resp; +// continue; +// } +// +// UThreadSetArgs(*socket, (void *)resp); +// return socket; +// } +// +// return nullptr; +//} + +void FaServerIO::HandlerNewResponseFunc() { + while (data_flow_->CanPluckResponse()) { + void *args{nullptr}; + BaseResponse *resp{nullptr}; + int queue_wait_time_ms{data_flow_->PluckResponse(args, resp)}; + if (!resp) { + return; + } + hsha_server_stat_->outqueue_wait_time_costs_ += queue_wait_time_ms; + hsha_server_stat_->outqueue_wait_time_costs_count_++; + + scheduler_->AddTask(bind(&FaServerIO::UThreadOFunc, this, args, + resp, queue_wait_time_ms), nullptr); + } +} + +void FaServerIO::UThreadOFunc(void *args, BaseResponse *resp, int queue_wait_time_ms) { + ServiceContext *context{(ServiceContext *)args}; + if (!context) { + phxrpc::log(LOG_ERR, "context nullptr"); + delete resp; + + return; + } + + // 1. update session + const auto &session(session_mgr_->GetBySessionId(context->session_id)); + if (!session) { + phxrpc::log(LOG_ERR, "invalid session_id %" PRIx64, context->session_id); + delete context; + delete resp; + + return; + } + if (context->destroy_session) { + // mqtt disconnect + session_router_->Delete(session->session_id); + session_mgr_->DeleteBySessionId(session->session_id); + + delete context; + delete resp; + + return; + } + + if (context->init_session) { + //// mqtt connect: if client_id exist, close old session + //const auto &old_session(session_mgr_->GetByClientId( + // context->session_attribute.client_identifier)); + //if (old_session) { + // if (old_session->session_id == session->session_id) { + // // mqtt-3.1.0-2: disconnect current connection + + // session_router_->Delete(session->session_id); + // session_mgr_->DeleteBySessionId(session->session_id); + + // delete context; + // delete resp; + + // return; + // } else { + // // mqtt-3.1.4-2: disconnect other connection with same client_id + // session_router_->Delete(old_session->session_id); + // session_mgr_->DeleteBySessionId(old_session->session_id); + // } + //} + + //// mqtt connect: set client_id and init + //session->session_attribute = context->session_attribute; + //session->Heartbeat(); + session_router_->Add(session->session_id, idx_); + } + + if (context->heartbeat_session) { + // mqtt ping + //session->Heartbeat(); + } + + // 2. send response + if (!resp->fake()) { + ReturnCode ret{resp->Send(*(session->stream))}; + // TODO: remove + printf("session_id %" PRIx64 " Send ret %d idx %d\n", context->session_id, ret, idx_); + //printf("session_id %" PRIx64 " Send client_id \"%s\" ret %d idx %d\n", + // context->session_id, session->session_attribute.client_identifier.c_str(), ret, idx_); + hsha_server_stat_->io_write_bytes_ += resp->GetContent().size(); + } + delete context; + delete resp; +} + +void FaServerIO::RunForever() { + scheduler_->SetHandlerAcceptedFdFunc(bind(&FaServerIO::HandlerAcceptedFd, this)); + // TODO: don't hack HandlerNewRequestFunc + scheduler_->SetHandlerNewRequestFunc(bind(&FaServerIO::HandlerNewResponseFunc, this)); + //scheduler_->SetActiveSocketFunc(bind(&FaServerIO::ActiveSocketFunc, this)); + scheduler_->RunForever(); +} + + +FaServerUnit::FaServerUnit( + const int idx, + Server *const root_server, + FaServer *const fa_server, + int worker_thread_count, + int worker_uthread_count_per_thread, + int worker_uthread_stack_size, + NotifierPoolRouter *const notifier_pool_router, + Dispatch_t dispatch, + void *args, SessionRouter *session_router) + : root_server_(root_server), + fa_server_(fa_server), +#ifndef __APPLE__ + scheduler_(8 * 1024, 1000000, false), +#else + scheduler_(32 * 1024, 1000000, false), +#endif + worker_pool_(idx, &scheduler_, fa_server_->config_, + worker_thread_count, worker_uthread_count_per_thread, + worker_uthread_stack_size, root_server, this, notifier_pool_router, + &data_flow_, &fa_server_->hsha_server_stat_, dispatch, args), + fa_server_io_(idx, &scheduler_, fa_server_->config_, &data_flow_, + &fa_server_->hsha_server_stat_, &fa_server_->hsha_server_qos_, + &worker_pool_, &session_mgr_, session_router), + thread_(&FaServerUnit::RunFunc, this) { +} + +FaServerUnit::~FaServerUnit() { + thread_.join(); +} + +void FaServerUnit::RunFunc() { + fa_server_io_.RunForever(); +} + +bool FaServerUnit::AddAcceptedFd(int accepted_fd) { + return fa_server_io_.AddAcceptedFd(accepted_fd); +} + +void FaServerUnit::PushResponse(void *args, BaseResponse *const resp) { + data_flow_.PushResponse(args, resp); + //fa_server_io_.hsha_server_stat_.outqueue_push_responses_++; +} + + +FaServerAcceptor::FaServerAcceptor(FaServer *fa_server) + : fa_server_(fa_server) { +} + +FaServerAcceptor::~FaServerAcceptor() { +} + +void FaServerAcceptor::LoopAccept(const char *bind_ip, const int port) { + int listen_fd{-1}; + if (!BlockTcpUtils::Listen(&listen_fd, bind_ip, port)) { + printf("listen fail, ip %s mqtt_port %d\n", bind_ip, port); + exit(-1); + } + + printf("listen succ, ip %s mqtt_port %d\n", bind_ip, port); + +#ifndef __APPLE__ + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(0, &mask); + pid_t thread_id = 0; + int ret{sched_setaffinity(thread_id, sizeof(mask), &mask)}; + if (ret != 0) { + printf("sched_setaffinity fail\n"); + } +#endif + + while (true) { + struct sockaddr_in addr; + socklen_t socklen = sizeof(addr); + int accepted_fd{accept(listen_fd, (struct sockaddr *) &addr, &socklen)}; + if (accepted_fd >= 0) { + if (!fa_server_->hsha_server_qos_.CanAccept()) { + fa_server_->hsha_server_stat_.rejected_fds_++; + phxrpc::log(LOG_ERR, "%s too many connection, reject accept, fd %d", __func__, accepted_fd); + close(accepted_fd); + continue; + } + + idx_ %= fa_server_->fa_server_unit_list_.size(); + if (!fa_server_->fa_server_unit_list_[idx_++]->AddAcceptedFd(accepted_fd)) { + fa_server_->hsha_server_stat_.rejected_fds_++; + phxrpc::log(LOG_ERR, "%s accept queue full, reject accept, fd %d", __func__, accepted_fd); + close(accepted_fd); + continue; + } + + fa_server_->hsha_server_stat_.accepted_fds_++; + fa_server_->hsha_server_stat_.hold_fds_++; + } else { + fa_server_->hsha_server_stat_.accept_fail_++; + } + } + + close(listen_fd); +} + + +FaServer::FaServer(const HshaServerConfig &config, const Dispatch_t &dispatch, void *args, + Server *const root_server) + : config_(&config), + hsha_server_monitor_(MonitorFactory::GetFactory()-> + CreateServerMonitor(config.GetPackageName())), + hsha_server_stat_(&config, hsha_server_monitor_), + hsha_server_qos_(&config, &hsha_server_stat_), + fa_server_acceptor_(this), root_server_(root_server) { + size_t io_count = (size_t)config.GetIOThreadCount(); + size_t worker_thread_count = (size_t)config.GetMaxThreads(); + assert(worker_thread_count > 0); + if (worker_thread_count < io_count) { + io_count = worker_thread_count; + } + + int worker_uthread_stack_size = config.GetWorkerUThreadStackSize(); + size_t worker_thread_count_per_io = worker_thread_count / io_count; + for (size_t i{0}; i < io_count; ++i) { + if (i == io_count - 1) { + worker_thread_count_per_io = worker_thread_count - (worker_thread_count_per_io * (io_count - 1)); + } + auto fa_hsha_server_unit = + new FaServerUnit(i, root_server, this, (int)worker_thread_count_per_io, + config.GetWorkerUThreadCount(), worker_uthread_stack_size, + ¬ifier_pool_router_, dispatch, args, &session_router_); + assert(fa_hsha_server_unit != nullptr); + fa_server_unit_list_.push_back(fa_hsha_server_unit); + } + printf("server already started, %zu io threads %zu workers\n", io_count, worker_thread_count); + if (config.GetWorkerUThreadCount() > 0) { + printf("server in uthread mode, %d uthread per worker\n", config.GetWorkerUThreadCount()); + } +} + +FaServer::~FaServer() { + for (auto &fa_server_unit : fa_server_unit_list_) { + delete fa_server_unit; + } + + fa_accept_thread_.join(); +} + +void FaServer::DoRunForever() { + fa_accept_thread_ = thread(&FaServerAcceptor::LoopAccept, fa_server_acceptor_, + config_->GetBindIP(), config_->GetMqttPort()); +} + +void FaServer::PushResponse(const uint64_t session_id, BaseResponse *resp) { + // push to server unit outqueue + int server_unit_idx{session_router_.Get(session_id)}; + ServiceContext *context{new ServiceContext}; + context->session_id = session_id; + // forward req and do not delete here + fa_server_unit_list_[server_unit_idx]->PushResponse(context, (BaseResponse *)resp); +} + + +} //namespace phxrpc + diff --git a/phxrpc/rpc/fa_server.h b/phxrpc/rpc/fa_server.h new file mode 100644 index 0000000..a0ceb1c --- /dev/null +++ b/phxrpc/rpc/fa_server.h @@ -0,0 +1,206 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "base_server.h" + + +namespace phxrpc { + + +struct ResidentMessage final { + std::string topic_name; + std::string content; + uint32_t qos{0u}; +}; + + +class MqttSession final { + public: + //enum class Status { + // None = 0, + // Connected, + // Closed, + //}; + + //void Heartbeat(); + //bool IsExpired(); + + uint64_t session_id{0uLL}; + // not use unique_ptr because socket is own by stream + UThreadSocket_t *socket{nullptr}; + std::unique_ptr stream; + //Status status{Status::None}; + //SessionAttribute session_attribute; + std::vector resident_messages; + + private: + uint64_t expire_time_ms_{0uLL}; +}; + + +class SessionManager final { + public: + MqttSession *Create(const int fd, UThreadEpollScheduler *const scheduler, + const int socket_timeout_ms); + + //MqttSession *GetByClientId(const std::string &client_id); + + MqttSession *GetBySessionId(const uint64_t session_id); + + MqttSession *GetByFd(const int fd); + + void DeleteBySessionId(const uint64_t session_id); + + private: + static std::atomic_uint32_t s_session_num; + + std::list sessions_; +}; + + +class SessionRouter final { + public: + void Add(const uint64_t session_id, const int idx); + int Get(const uint64_t session_id) const; + void Delete(const uint64_t session_id); + + private: + mutable std::mutex mutex_; + std::map session_id2thread_index_map_; +}; + + +class FaServerIO final { + public: + FaServerIO(const int idx, UThreadEpollScheduler *const scheduler, + const HshaServerConfig *config, DataFlow *data_flow, + HshaServerStat *hsha_server_stat, HshaServerQos *hsha_server_qos, + WorkerPool *worker_pool, SessionManager *session_mgr, + SessionRouter *session_router); + ~FaServerIO(); + + void RunForever(); + + bool AddAcceptedFd(int accepted_fd); + + void HandlerAcceptedFd(); + + void UThreadIFunc(int accept_fd); + + //UThreadSocket_t *ActiveSocketFunc(); + + void HandlerNewResponseFunc(); + + void UThreadOFunc(void *args, BaseResponse *resp, int queue_wait_time_ms); + + private: + int idx_{-1}; + UThreadEpollScheduler *scheduler_{nullptr}; + const HshaServerConfig *config_{nullptr}; + DataFlow *data_flow_{nullptr}; + HshaServerStat *hsha_server_stat_{nullptr}; + HshaServerQos *hsha_server_qos_{nullptr}; + WorkerPool *worker_pool_{nullptr}; + SessionManager *session_mgr_{nullptr}; + SessionRouter *session_router_{nullptr}; + + std::queue accepted_fd_list_; + std::mutex queue_mutex_; +}; + + +class FaServer; + +class FaServerUnit : public BaseServerUnit { + public: + FaServerUnit(const int idx, + Server *const root_server, + FaServer *const fa_server, + int worker_thread_count, + int worker_uthread_count_per_thread, + int worker_uthread_stack_size, + NotifierPoolRouter *const notifier_pool_router, + Dispatch_t dispatch, + void *args, SessionRouter *session_router); + virtual ~FaServerUnit() override; + + void RunFunc(); + bool AddAcceptedFd(int accepted_fd); + void PushResponse(void *args, BaseResponse *const resp); + + private: + Server *root_server_{nullptr}; + FaServer *fa_server_{nullptr}; + UThreadEpollScheduler scheduler_; + WorkerPool worker_pool_; + FaServerIO fa_server_io_; + SessionManager session_mgr_; + std::thread thread_; +}; + + +class FaServerAcceptor final { + public: + FaServerAcceptor(FaServer *fa_server); + ~FaServerAcceptor(); + + void LoopAccept(const char *bind_ip, const int port); + + private: + FaServer *fa_server_{nullptr}; + size_t idx_{0}; +}; + + +class FaServer : public BaseServer { + public: + FaServer(const HshaServerConfig &config, const Dispatch_t &dispatch, void *args, + Server *const root_server); + virtual ~FaServer() override; + + virtual void DoRunForever() override; + + void PushResponse(const uint64_t session_id, BaseResponse *const resp); + + Server *root_server() const { return root_server_; } + + const HshaServerConfig *config_{nullptr}; + ServerMonitorPtr hsha_server_monitor_; + HshaServerStat hsha_server_stat_; + HshaServerQos hsha_server_qos_; + FaServerAcceptor fa_server_acceptor_; + + std::vector fa_server_unit_list_; + + std::thread fa_accept_thread_; + + SessionRouter session_router_; + + private: + Server *root_server_{nullptr}; + NotifierPoolRouter notifier_pool_router_; +}; + + +} //namespace phxrpc + diff --git a/phxrpc/rpc/hsha_server.cpp b/phxrpc/rpc/hsha_server.cpp index 4ab4fdc..ffd25cb 100644 --- a/phxrpc/rpc/hsha_server.cpp +++ b/phxrpc/rpc/hsha_server.cpp @@ -1,623 +1,273 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ #include "hsha_server.h" -#include -#include + +#include #include #include +#include +#include +#include + +#include "phxrpc/file.h" +#include "phxrpc/http.h" +#include "phxrpc/mqtt.h" +#include "phxrpc/msg.h" +#include "phxrpc/network.h" #include "server_monitor.h" #include "monitor_factory.h" -#include "phxrpc/network.h" -#include "phxrpc/http.h" -#include "phxrpc/file.h" - -#include using namespace std; -namespace phxrpc { - -DataFlow :: DataFlow() { -} - -DataFlow :: ~DataFlow() { -} - -void DataFlow :: PushRequest(void * args, HttpRequest * request) { - in_queue_.push(make_pair(QueueExtData(args), request)); -} - -int DataFlow :: PluckRequest(void *& args, HttpRequest *& request) { - pair rp; - bool succ = in_queue_.pluck(rp); - if (!succ) { - return 0; - } - args = rp.first.args; - request = rp.second; - - auto now_time = Timer::GetSteadyClockMS(); - return now_time > rp.first.enqueue_time_ms ? now_time - rp.first.enqueue_time_ms : 0; -} - -void DataFlow :: PushResponse(void * args, HttpResponse * response) { - out_queue_.push(make_pair(QueueExtData(args), response)); -} - -int DataFlow :: PluckResponse(void *& args, HttpResponse *& response) { - pair rp; - bool succ = out_queue_.pluck(rp); - if (!succ) { - return 0; - } - args = rp.first.args; - response = rp.second; - - auto now_time = Timer::GetSteadyClockMS(); - return now_time > rp.first.enqueue_time_ms ? now_time - rp.first.enqueue_time_ms : 0; -} - -bool DataFlow :: CanPushRequest(const int max_queue_length) { - return in_queue_.size() < (size_t)max_queue_length; -} - -bool DataFlow :: CanPluckResponse() { - return !out_queue_.empty(); -} - -void DataFlow :: BreakOut() { - in_queue_.break_out(); - out_queue_.break_out(); -} - -//////////////////////////////////////// - -HshaServerStat :: TimeCost :: TimeCost() { - now_time_ms_ = Timer::GetSteadyClockMS(); -} - -HshaServerStat :: TimeCost :: ~TimeCost() { -} - -int HshaServerStat :: TimeCost :: Cost() { - auto now_time_ms = Timer::GetSteadyClockMS(); - auto cost_time_ms = now_time_ms > now_time_ms_ ? now_time_ms - now_time_ms_ : 0; - now_time_ms_ = now_time_ms; - return cost_time_ms; -} - -HshaServerStat :: HshaServerStat(const HshaServerConfig * config, ServerMonitorPtr hsha_server_monitor ) : - config_(config), thread_(&HshaServerStat::CalFunc, this), break_out_(false), - hsha_server_monitor_(hsha_server_monitor) { - hold_fds_ = 0; - accepted_fds_ = 0; - accept_qps_ = 0; - rejected_fds_ = 0; - reject_qps_ = 0; - queue_full_rejected_after_accepted_fds_ = 0; - queue_full_rejected_after_accepted_qps_ = 0; - accept_fail_ = 0; - accept_fail_qps_ = 0; - - io_read_requests_ = 0; - io_read_request_qps_ = 0; - io_read_bytes_ = 0; - - io_write_responses_ = 0; - io_write_response_qps_ = 0; - io_write_bytes_ = 0; - - io_read_fails_ = 0; - io_read_fail_qps_ = 0; - io_write_fails_ = 0; - io_write_fail_qps_ = 0; - - inqueue_push_requests_ = 0; - inqueue_push_qps_ = 0; - inqueue_pop_requests_ = 0; - inqueue_pop_qps_ = 0; - - outqueue_push_responses_ = 0; - outqueue_push_qps_ = 0; - outqueue_pop_responses_ = 0; - outqueue_pop_qps_ = 0; - - worker_timeouts_ = 0; - worker_timeout_qps_ = 0; - - rpc_time_costs_ = 0; - rpc_time_costs_count_ = 0; - rpc_avg_time_cost_per_second_ = 0; - rpc_time_cost_per_period_ = 0; - - inqueue_wait_time_costs_ = 0; - inqueue_wait_time_costs_count_ = 0; - inqueue_avg_wait_time_costs_per_second_ = 0; - inqueue_avg_wait_time_costs_per_second_cal_seq_ = 0; - inqueue_wait_time_costs_per_period_ = 0; - - outqueue_wait_time_costs_ = 0; - outqueue_wait_time_costs_count_ = 0; - outqueue_wait_time_costs_per_period_ = 0; - outqueue_avg_wait_time_costs_per_second_ = 0; - - enqueue_fast_rejects_ = 0; - enqueue_fast_reject_qps_ = 0; - - worker_idles_ = 0; - - worker_drop_requests_ = 0; - worker_drop_reqeust_qps_ = 0; - worker_time_costs_ = 0; - worker_time_costs_per_second_ = 0; -} - -HshaServerStat :: ~HshaServerStat() { - break_out_ = true; - cv_.notify_all(); - thread_.join(); -} - -void HshaServerStat :: MonitorReport() { - //accept - hsha_server_monitor_->Accept( accept_qps_ ); - hsha_server_monitor_->AcceptFail( accept_fail_qps_ ); - hsha_server_monitor_->FastRejectAfterAccept( reject_qps_ ); - - //io - hsha_server_monitor_->ReadError( io_read_fail_qps_ ); - hsha_server_monitor_->SendError( io_write_fail_qps_ ); - hsha_server_monitor_->OutOfQueue( queue_full_rejected_after_accepted_qps_ ); - hsha_server_monitor_->QueueDelay( rpc_time_cost_per_period_ ); - hsha_server_monitor_->FastRejectAfterRead( enqueue_fast_reject_qps_ ); - hsha_server_monitor_->RecvBytes( io_read_bytes_qps_ ); - hsha_server_monitor_->SendBytes( io_write_bytes_qps_ ); - hsha_server_monitor_->WaitInInQueue( inqueue_wait_time_costs_per_period_ ); - hsha_server_monitor_->WaitInOutQueue( outqueue_wait_time_costs_per_period_ ); - - //worker - hsha_server_monitor_->RequestCount( accept_qps_ ); - hsha_server_monitor_->ResponseCount( io_write_response_qps_ ); - hsha_server_monitor_->RequestCost( worker_time_costs_per_second_ ); - hsha_server_monitor_->WrokerInQueueTimeout( worker_drop_reqeust_qps_ ); -} - -void HshaServerStat :: CalFunc() { - while (!break_out_) { - std::unique_lock lock(mutex_); - cv_.wait_for(lock, std::chrono::seconds(1)); - - //acceptor - accept_qps_ = static_cast(accepted_fds_); - accepted_fds_ = 0; - reject_qps_ = static_cast(rejected_fds_); - rejected_fds_ = 0; - queue_full_rejected_after_accepted_qps_ = static_cast(queue_full_rejected_after_accepted_fds_); - queue_full_rejected_after_accepted_fds_ = 0; - accept_fail_qps_ = static_cast(accept_fail_); - accept_fail_ = 0; - - //io - io_read_request_qps_ = static_cast(io_read_requests_); - io_read_requests_ = 0; - io_write_response_qps_ = static_cast(io_write_responses_); - io_write_responses_ = 0; - - io_read_bytes_qps_ = static_cast(io_read_bytes_); - io_read_bytes_ = 0; - io_write_bytes_qps_ = static_cast(io_write_bytes_); - io_write_bytes_ = 0; - - io_read_fail_qps_ = static_cast(io_read_fails_); - io_read_fails_ = 0; - io_write_fail_qps_ = static_cast(io_write_fails_); - io_write_fails_ = 0; - - //queue - inqueue_push_qps_ = static_cast(inqueue_push_requests_); - inqueue_push_requests_ = 0; - inqueue_pop_qps_ = static_cast(inqueue_pop_requests_); - inqueue_pop_requests_ = 0; - - outqueue_push_qps_ = static_cast(outqueue_push_responses_); - outqueue_push_responses_ = 0; - outqueue_pop_qps_ = static_cast(outqueue_pop_responses_); - outqueue_pop_responses_ = 0; - - //worker - worker_timeout_qps_ = static_cast(worker_timeouts_); - worker_timeouts_ = 0; - - //time cost - rpc_time_cost_per_period_ = 0; - if (rpc_time_costs_count_ >= RPC_TIME_COST_CAL_RATE) { - rpc_avg_time_cost_per_second_ = - static_cast(rpc_time_costs_) / rpc_time_costs_count_; - rpc_time_cost_per_period_ = static_cast(rpc_time_costs_); - rpc_time_costs_ = 0; - rpc_time_costs_count_ = 0; - } - - inqueue_wait_time_costs_per_period_ = 0; - if (inqueue_wait_time_costs_count_ >= QUEUE_WAIT_TIME_COST_CAL_RATE) { - inqueue_avg_wait_time_costs_per_second_ = - static_cast(inqueue_wait_time_costs_) / inqueue_wait_time_costs_count_; - inqueue_wait_time_costs_per_period_ = static_cast(inqueue_wait_time_costs_); - inqueue_wait_time_costs_ = 0; - inqueue_wait_time_costs_count_ = 0; - inqueue_avg_wait_time_costs_per_second_cal_seq_++; - } - - outqueue_wait_time_costs_per_period_ = 0; - if (outqueue_wait_time_costs_count_ >= QUEUE_WAIT_TIME_COST_CAL_RATE) { - outqueue_avg_wait_time_costs_per_second_ = - static_cast(outqueue_wait_time_costs_) / outqueue_wait_time_costs_count_; - outqueue_wait_time_costs_per_period_ = static_cast(outqueue_wait_time_costs_); - outqueue_wait_time_costs_ = 0; - outqueue_wait_time_costs_count_ = 0; - } - - enqueue_fast_reject_qps_ = static_cast(enqueue_fast_rejects_); - enqueue_fast_rejects_ = 0; - - worker_drop_reqeust_qps_ = static_cast(worker_drop_requests_); - worker_drop_requests_ = 0; - - worker_time_costs_per_second_ = static_cast(worker_time_costs_); - worker_time_costs_ = 0; - - MonitorReport(); - - phxrpc::log(LOG_NOTICE, "[SERVER_STAT] hold_fds %d accept_qps %d accept_reject_qps %d queue_full_reject_qps %d" - " read_request_qps %d write_response_qps %d" - " inqueue_push_qps %d rpc_time_cost_avg %d" - " inqueue_wait_time_avg %d outqueue_wait_time_qvg %d" - " fast_reject_qps %d" - " worker_idles %d worker_drop_request_qps %d io_read_fails %d, io_write_fails %d", - static_cast(hold_fds_), accept_qps_, reject_qps_, queue_full_rejected_after_accepted_qps_, - io_read_request_qps_, io_write_response_qps_, - inqueue_push_qps_, rpc_avg_time_cost_per_second_, - inqueue_avg_wait_time_costs_per_second_, outqueue_avg_wait_time_costs_per_second_, - enqueue_fast_reject_qps_, - static_cast(worker_idles_), worker_drop_reqeust_qps_, io_read_fail_qps_, io_write_fail_qps_ ); - - } -} - -//////////////////////////////////////// - -HshaServerQos :: HshaServerQos(const HshaServerConfig * config, HshaServerStat * hsha_server_stat) - : config_(config), hsha_server_stat_(hsha_server_stat), - thread_(&HshaServerQos::CalFunc, this), break_out_(false) { - enqueue_reject_rate_ = 0; - inqueue_avg_wait_time_costs_per_second_cal_last_seq_ = 0; -} - -HshaServerQos :: ~HshaServerQos() { - break_out_ = true; - cv_.notify_all(); - thread_.join(); -} - -bool HshaServerQos :: CanAccept() { - return static_cast(hsha_server_stat_->hold_fds_) < config_->GetMaxConnections(); -} - -bool HshaServerQos :: CanEnqueue() { - static std::default_random_engine e_rand((int)time(nullptr)); - return ((int)(e_rand() % 100)) >= enqueue_reject_rate_; -} - -void HshaServerQos :: CalFunc() { - while (!break_out_) { - std::unique_lock lock(mutex_); - cv_.wait_for(lock, std::chrono::seconds(1)); - - //fast reject - if (hsha_server_stat_->inqueue_avg_wait_time_costs_per_second_cal_seq_ - != inqueue_avg_wait_time_costs_per_second_cal_last_seq_) { - //inqueue avg wait time reflesh - int avg_queue_wait_time = (hsha_server_stat_->inqueue_avg_wait_time_costs_per_second_ - + hsha_server_stat_->outqueue_avg_wait_time_costs_per_second_) / 2; - - if (avg_queue_wait_time > config_->GetFastRejectThresholdMS()) { - if (enqueue_reject_rate_ != 99) { - enqueue_reject_rate_ = enqueue_reject_rate_ + 5 > 99 ? 99 : enqueue_reject_rate_ + 5; - } - } else { - if (enqueue_reject_rate_ != 0) { - enqueue_reject_rate_ = enqueue_reject_rate_ - 5 < 0 ? 0 : enqueue_reject_rate_ - 5; - } - } - inqueue_avg_wait_time_costs_per_second_cal_last_seq_ = - hsha_server_stat_->inqueue_avg_wait_time_costs_per_second_cal_seq_; - } - - phxrpc::log(LOG_NOTICE, "[SERVER_QOS] accept_reject_qps %d queue_full_reject_qps %d" - " fast_reject_qps %d fast_reject_rate %d", - hsha_server_stat_->reject_qps_, hsha_server_stat_->queue_full_rejected_after_accepted_qps_, - hsha_server_stat_->enqueue_fast_reject_qps_, enqueue_reject_rate_); - } -} - -//////////////////////////////////////// - -Worker :: Worker(WorkerPool * pool) - : pool_(pool), shut_down_(false), thread_(&Worker::Func, this) { -} - -Worker :: ~Worker() { - thread_.join(); -} - -void Worker :: Func() { - while (!shut_down_) { - pool_->hsha_server_stat_->worker_idles_++; - - void * args = nullptr; - HttpRequest * request = nullptr; - int queue_wait_time_ms = pool_->data_flow_->PluckRequest(args, request); - if (request == nullptr) { - //break out - continue; - } - pool_->hsha_server_stat_->worker_idles_--; - - pool_->hsha_server_stat_->inqueue_pop_requests_++; - pool_->hsha_server_stat_->inqueue_wait_time_costs_ += queue_wait_time_ms; - pool_->hsha_server_stat_->inqueue_wait_time_costs_count_++; - - HttpResponse * response = new HttpResponse; - if (queue_wait_time_ms < MAX_QUEUE_WAIT_TIME_COST) { - HshaServerStat::TimeCost time_cost; - pool_->dispatch_(*request, response, &(pool_->dispatcher_args_)); - pool_->hsha_server_stat_->worker_time_costs_ += time_cost.Cost(); - } else { - pool_->hsha_server_stat_->worker_drop_requests_++; - } - pool_->data_flow_->PushResponse(args, response); - pool_->hsha_server_stat_->outqueue_push_responses_++; - - pool_->scheduler_->NotifyEpoll(); - - delete request; - } -} - -void Worker :: Shutdown() { - shut_down_ = true; - pool_->data_flow_->BreakOut(); -} - -//////////////////////////////////////// - -WorkerPool :: WorkerPool(UThreadEpollScheduler * scheduler, size_t thread_count, DataFlow * data_flow, - HshaServerStat * hsha_server_stat, Dispatch_t dispatch, void * args) - : scheduler_(scheduler), data_flow_(data_flow), - hsha_server_stat_(hsha_server_stat), dispatch_(dispatch), - dispatcher_args_(hsha_server_stat_->hsha_server_monitor_, args ) { - for (size_t i = 0; i < thread_count; i++) { - auto worker = new Worker(this); - assert(worker != nullptr); - worker_list_.push_back(worker); - } -} -WorkerPool :: ~WorkerPool() { - for (auto & worker : worker_list_) { - worker->Shutdown(); - delete worker; - } -} +namespace phxrpc { -//////////////////////////////////////// -HshaServerIO :: HshaServerIO(int idx, UThreadEpollScheduler * scheduler, const HshaServerConfig * config, - DataFlow * data_flow, HshaServerStat * hsha_server_stat, HshaServerQos * hsha_server_qos) - : idx_(idx), scheduler_(scheduler), config_(config), - data_flow_(data_flow), listen_fd_(-1), hsha_server_stat_(hsha_server_stat), - hsha_server_qos_(hsha_server_qos){ +HshaServerIO::HshaServerIO(const int idx, UThreadEpollScheduler *const scheduler, + const HshaServerConfig *config, + DataFlow *data_flow, HshaServerStat *hsha_server_stat, + HshaServerQos *hsha_server_qos, WorkerPool *worker_pool) + : idx_(idx), scheduler_(scheduler), config_(config), data_flow_(data_flow), + hsha_server_stat_(hsha_server_stat), + hsha_server_qos_(hsha_server_qos), worker_pool_(worker_pool) { } -HshaServerIO :: ~HshaServerIO() { +HshaServerIO::~HshaServerIO() { } -bool HshaServerIO :: AddAcceptedFd(int accepted_fd) { - std::lock_guard lock(queue_mutex_); +bool HshaServerIO::AddAcceptedFd(int accepted_fd) { + lock_guard lock(queue_mutex_); if (accepted_fd_list_.size() > MAX_ACCEPT_QUEUE_LENGTH) { return false; } accepted_fd_list_.push(accepted_fd); - if (static_cast(hsha_server_stat_->io_read_request_qps_) < 5000 - && static_cast(hsha_server_stat_->accept_qps_) < 5000) { + if (static_cast(hsha_server_stat_->io_read_request_qps_) < 5000 && + static_cast(hsha_server_stat_->accept_qps_) < 5000) { scheduler_->NotifyEpoll(); } return true; } -void HshaServerIO :: HandlerAcceptedFd() { - std::lock_guard lock(queue_mutex_); +void HshaServerIO::HandlerAcceptedFd() { + lock_guard lock(queue_mutex_); while (!accepted_fd_list_.empty()) { int accepted_fd = accepted_fd_list_.front(); accepted_fd_list_.pop(); - scheduler_->AddTask(std::bind(&HshaServerIO::IOFunc, this, accepted_fd), nullptr); + scheduler_->AddTask(bind(&HshaServerIO::IOFunc, this, accepted_fd), nullptr); } } -void HshaServerIO :: IOFunc(int accepted_fd) { - UThreadSocket_t * socket = scheduler_->CreateSocket(accepted_fd); +void HshaServerIO::IOFunc(int accepted_fd) { + UThreadSocket_t *socket{scheduler_->CreateSocket(accepted_fd)}; UThreadTcpStream stream; stream.Attach(socket); - UThreadSetSocketTimeout(*socket, config_->GetSocketTimeoutMS()); - HshaServerStat::TimeCost time_cost; + UThreadSetSocketTimeout(*socket, config_->GetSocketTimeoutMS()); while (true) { + HshaServerStat::TimeCost time_cost; + hsha_server_stat_->io_read_requests_++; - HttpRequest * request = new HttpRequest; - int socket_ret = HttpProto::RecvReq(stream, request); - if (socket_ret != 0) { - delete request; + + unique_ptr factory( + BaseProtocolFactory::CreateFactory(stream)); + unique_ptr protocol(factory->GenProtocol()); + // will be deleted by worker + BaseRequest *req{nullptr}; + ReturnCode ret{protocol->ServerRecv(stream, req)}; + if (ReturnCode::OK != ret) { + delete req; hsha_server_stat_->io_read_fails_++; hsha_server_stat_->rpc_time_costs_count_++; - //phxrpc::log(LOG_ERR, "%s read request fail, fd %d", __func__, accepted_fd); + hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); + phxrpc::log(LOG_ERR, "%s read request fail, fd %d", __func__, accepted_fd); + break; } - hsha_server_stat_->io_read_bytes_ += request->GetContent().size(); + hsha_server_stat_->io_read_bytes_ += req->GetContent().size(); if (!data_flow_->CanPushRequest(config_->GetMaxQueueLength())) { - delete request; + delete req; hsha_server_stat_->queue_full_rejected_after_accepted_fds_++; + break; } if (!hsha_server_qos_->CanEnqueue()) { - //fast reject don't cal rpc_time_cost; - delete request; + // fast reject don't cal rpc_time_cost; + delete req; hsha_server_stat_->enqueue_fast_rejects_++; - //phxrpc::log(LOG_ERR, "%s fast reject, can't enqueue, fd %d", __func__, accepted_fd); + phxrpc::log(LOG_ERR, "%s fast reject, can't enqueue, fd %d", + __func__, accepted_fd); + break; } - //if have enqueue, request will be deleted after pop. - bool is_keep_alive = request->IsKeepAlive(); - std::string version = string(request->GetVersion() != nullptr ? request->GetVersion() : ""); + // if have enqueue, request will be deleted after pop. + const bool is_keep_alive{0 != req->IsKeepAlive()}; + const string version(req->GetVersion() != nullptr ? req->GetVersion() : ""); hsha_server_stat_->inqueue_push_requests_++; - data_flow_->PushRequest((void *)socket, request); + data_flow_->PushRequest((void *)socket, req); + // if is uthread worker mode, need notify. + // req deleted by worker after this line + worker_pool_->NotifyEpoll(); UThreadSetArgs(*socket, nullptr); - UthreadWait(*socket, config_->GetSocketTimeoutMS()); - if (UthreadGetArgs(*socket) == nullptr) { - //timeout + UThreadWait(*socket, config_->GetSocketTimeoutMS()); + if (UThreadGetArgs(*socket) == nullptr) { + // timeout hsha_server_stat_->worker_timeouts_++; hsha_server_stat_->rpc_time_costs_count_++; + hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); - //because have enqueue, so socket will be closed after pop. - socket = stream.DetachSocket(); - UthreadLazyDestory(*socket); + // because have enqueue, so socket will be closed after pop. + socket = stream.DetachSocket(); + UThreadLazyDestory(*socket); - //phxrpc::log(LOG_ERR, "%s timeout, fd %d sockettimeoutms %d", - //__func__, accepted_fd, config_->GetSocketTimeoutMS()); + phxrpc::log(LOG_ERR, "%s timeout, fd %d socket_timeout_ms %d", + __func__, accepted_fd, config_->GetSocketTimeoutMS()); break; } hsha_server_stat_->io_write_responses_++; - HttpResponse * response = (HttpResponse *)UthreadGetArgs(*socket); - HttpProto::FixRespHeaders(is_keep_alive, version.c_str(), response); - socket_ret = HttpProto::SendResp(stream, *response); - hsha_server_stat_->io_write_bytes_ += response->GetContent().size(); - delete response; + { + BaseResponse *resp((BaseResponse *)UThreadGetArgs(*socket)); + if (!resp->fake()) { + ret = resp->ModifyResp(is_keep_alive, version); + ret = resp->Send(stream); + hsha_server_stat_->io_write_bytes_ += resp->GetContent().size(); + } + delete resp; + } hsha_server_stat_->rpc_time_costs_count_++; + hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); - if (socket_ret != 0) { + if (ReturnCode::OK != ret) { hsha_server_stat_->io_write_fails_++; } - if(!is_keep_alive || (socket_ret != 0)) { + if (!is_keep_alive || (ReturnCode::OK != ret)) { break; - } else { - hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); } } - hsha_server_stat_->rpc_time_costs_ += time_cost.Cost(); hsha_server_stat_->hold_fds_--; } -UThreadSocket_t * HshaServerIO :: ActiveSocketFunc() { +UThreadSocket_t *HshaServerIO::ActiveSocketFunc() { while (data_flow_->CanPluckResponse()) { - void * args = nullptr; - HttpResponse * response = nullptr; - int queue_wait_time_ms = data_flow_->PluckResponse(args, response); - if (response == nullptr) { + void *args{nullptr}; + BaseResponse *resp{nullptr}; + int queue_wait_time_ms{data_flow_->PluckResponse(args, resp)}; + if (!resp) { //break out return nullptr; } hsha_server_stat_->outqueue_wait_time_costs_ += queue_wait_time_ms; hsha_server_stat_->outqueue_wait_time_costs_count_++; - UThreadSocket_t * socket = (UThreadSocket_t *)args; - if (socket != nullptr && IsUthreadDestory(*socket)) { + UThreadSocket_t *socket = (UThreadSocket_t *)args; + if (socket != nullptr && IsUThreadDestory(*socket)) { //socket aready timeout. //phxrpc::log(LOG_ERR, "%s socket aready timeout", __func__); UThreadClose(*socket); free(socket); - delete response; + delete resp; continue; } - UThreadSetArgs(*socket, (void *)response); + UThreadSetArgs(*socket, (void *)resp); return socket; } return nullptr; } -void HshaServerIO :: RunForever() { - scheduler_->SetHandlerAcceptedFdFunc(std::bind(&HshaServerIO::HandlerAcceptedFd, this)); - scheduler_->SetActiveSocketFunc(std::bind(&HshaServerIO::ActiveSocketFunc, this)); +void HshaServerIO::RunForever() { + scheduler_->SetHandlerAcceptedFdFunc(bind(&HshaServerIO::HandlerAcceptedFd, this)); + scheduler_->SetActiveSocketFunc(bind(&HshaServerIO::ActiveSocketFunc, this)); scheduler_->RunForever(); } -///////////////////////////////////////////////// - -HshaServerUnit :: HshaServerUnit(HshaServer * hsha_server, int idx, int worker_thread_count, - Dispatch_t dispatch, void * args) : - hsha_server_(hsha_server), - scheduler_(16 * 1024, 1000000), - hsha_server_io_(idx, &scheduler_, hsha_server_->config_, &data_flow_, - &hsha_server_->hsha_server_stat_, &hsha_server_->hsha_server_qos_), - worker_pool_(&scheduler_, worker_thread_count, &data_flow_, - &hsha_server_->hsha_server_stat_, dispatch, args), - thread_(&HshaServerUnit::RunFunc, this) { -} -HshaServerUnit :: ~HshaServerUnit() { +HshaServerUnit::HshaServerUnit( + const int idx, + Server *const root_server, + HshaServer *const hsha_server, + int worker_thread_count, + int worker_uthread_count_per_thread, + int worker_uthread_stack_size, + NotifierPoolRouter *const notifier_pool_router, + Dispatch_t dispatch, + void *args) + : root_server_(root_server), + hsha_server_(hsha_server), +#ifndef __APPLE__ + scheduler_(8 * 1024, 1000000, false), +#else + scheduler_(32 * 1024, 1000000, false), +#endif + worker_pool_(idx, &scheduler_, hsha_server_->config_, + worker_thread_count, worker_uthread_count_per_thread, + worker_uthread_stack_size, root_server, this, notifier_pool_router, + &data_flow_, &hsha_server_->hsha_server_stat_, dispatch, args), + hsha_server_io_(idx, &scheduler_, hsha_server_->config_, &data_flow_, + &hsha_server_->hsha_server_stat_, + &hsha_server_->hsha_server_qos_, &worker_pool_), + thread_(&HshaServerUnit::RunFunc, this) { +} + +HshaServerUnit::~HshaServerUnit() { thread_.join(); } -void HshaServerUnit :: RunFunc() { +void HshaServerUnit::RunFunc() { hsha_server_io_.RunForever(); } -bool HshaServerUnit :: AddAcceptedFd(int accepted_fd) { +bool HshaServerUnit::AddAcceptedFd(int accepted_fd) { return hsha_server_io_.AddAcceptedFd(accepted_fd); } -///////////////////////////////////////////////// +int HshaServerUnit::NotifyTargetWorker(const int idx, + const NotifierPoolRouter::NotifierId ¬ifier_id, + void *const data) { + return worker_pool_.NotifyTarget(idx, notifier_id, data); +} + -HshaServerAcceptor :: HshaServerAcceptor(HshaServer * hsha_server) - : hsha_server_(hsha_server), idx_(0) { +HshaServerAcceptor::HshaServerAcceptor(HshaServer *hsha_server) + : hsha_server_(hsha_server) { } -HshaServerAcceptor :: ~HshaServerAcceptor() { +HshaServerAcceptor::~HshaServerAcceptor() { } -void HshaServerAcceptor :: LoopAccept(const char * bind_ip, const int port) { - int listen_fd = -1; +void HshaServerAcceptor::LoopAccept(const char *bind_ip, const int port) { + int listen_fd{-1}; if (!BlockTcpUtils::Listen(&listen_fd, bind_ip, port)) { printf("listen fail, ip %s port %d\n", bind_ip, port); exit(-1); @@ -625,19 +275,21 @@ void HshaServerAcceptor :: LoopAccept(const char * bind_ip, const int port) { printf("listen succ, ip %s port %d\n", bind_ip, port); +#ifndef __APPLE__ cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(0, &mask); pid_t thread_id = 0; - int ret = sched_setaffinity(thread_id, sizeof(mask), &mask); + int ret{sched_setaffinity(thread_id, sizeof(mask), &mask)}; if (ret != 0) { printf("sched_setaffinity fail\n"); } +#endif while (true) { struct sockaddr_in addr; socklen_t socklen = sizeof(addr); - int accepted_fd = accept(listen_fd, (struct sockaddr*) &addr, &socklen); + int accepted_fd{accept(listen_fd, (struct sockaddr *) &addr, &socklen)}; if (accepted_fd >= 0) { if (!hsha_server_->hsha_server_qos_.CanAccept()) { hsha_server_->hsha_server_stat_.rejected_fds_++; @@ -664,43 +316,93 @@ void HshaServerAcceptor :: LoopAccept(const char * bind_ip, const int port) { close(listen_fd); } -//////////////////////////////////////// - -HshaServer :: HshaServer( - const HshaServerConfig & config, - Dispatch_t dispatch, - void * args) : - config_(&config), - hsha_server_monitor_(MonitorFactory::GetFactory()->CreateServerMonitor(config.GetPackageName())), - hsha_server_stat_(&config, hsha_server_monitor_), - hsha_server_qos_(&config, &hsha_server_stat_), - hsha_server_acceptor_(this) { + +HshaServer::HshaServer(const HshaServerConfig &config, const Dispatch_t &dispatch, void *args, + Server *const root_server) + : config_(&config), + hsha_server_monitor_(MonitorFactory::GetFactory()-> + CreateServerMonitor(config.GetPackageName())), + hsha_server_stat_(&config, hsha_server_monitor_), + hsha_server_qos_(&config, &hsha_server_stat_), + hsha_server_acceptor_(this), root_server_(root_server) { size_t io_count = (size_t)config.GetIOThreadCount(); size_t worker_thread_count = (size_t)config.GetMaxThreads(); assert(worker_thread_count > 0); if (worker_thread_count < io_count) { io_count = worker_thread_count; } + + int worker_uthread_stack_size = config.GetWorkerUThreadStackSize(); size_t worker_thread_count_per_io = worker_thread_count / io_count; - for (size_t i = 0; i < io_count; i++) { + for (size_t i{0}; i < io_count; ++i) { if (i == io_count - 1) { worker_thread_count_per_io = worker_thread_count - (worker_thread_count_per_io * (io_count - 1)); } - auto hsha_server_unit = new HshaServerUnit(this, i, worker_thread_count_per_io, dispatch, args); + auto hsha_server_unit = + new HshaServerUnit(i, root_server, this, (int)worker_thread_count_per_io, + config.GetWorkerUThreadCount(), worker_uthread_stack_size, + ¬ifier_pool_router_, dispatch, args); assert(hsha_server_unit != nullptr); server_unit_list_.push_back(hsha_server_unit); } printf("server already started, %zu io threads %zu workers\n", io_count, worker_thread_count); + if (config.GetWorkerUThreadCount() > 0) { + printf("server in uthread mode, %d uthread per worker\n", config.GetWorkerUThreadCount()); + } } -HshaServer :: ~HshaServer() { - for (auto & hsha_server_unit : server_unit_list_) { +HshaServer::~HshaServer() { + for (auto &hsha_server_unit : server_unit_list_) { delete hsha_server_unit; } + + hsha_accept_thread_.join(); } -void HshaServer :: RunForever() { - hsha_server_acceptor_.LoopAccept(config_->GetBindIP(), config_->GetPort()); +void HshaServer::DoRunForever() { + hsha_accept_thread_ = thread(&HshaServerAcceptor::LoopAccept, hsha_server_acceptor_, + config_->GetBindIP(), config_->GetPort()); } -} //namespace phxrpc +int HshaServer::SendNotify(const NotifierPoolRouter::NotifierId ¬ifier_id, void *const data) { + auto idx{notifier_pool_router_.Get(notifier_id)}; + return server_unit_list_[idx.first]-> + NotifyTargetWorker(idx.second, notifier_id, data); +} + +int HshaServer::WaitNotify(UThreadNotifierPool *const notifier_pool, const int pool_idx, const int worker_idx, + const NotifierPoolRouter::NotifierId ¬ifier_id, void *&data) { + notifier_pool_router_.Add(notifier_id, make_pair(pool_idx, worker_idx)); + // TODO: remove + auto temp(notifier_pool_router_.Get(notifier_id)); + printf("%s notifier_pool_router idx %d:%d\n", __func__, temp.first, temp.second); + UThreadNotifier *notifier{nullptr}; + int ret{notifier_pool->GetNotifier(move(notifier_id.ToUint128()), notifier)}; + if (0 != ret) { + // TODO: remove + printf("%s GetNotifier err %d\n", __func__, ret); + notifier_pool_router_.Delete(notifier_id); + + return ret; + } + + // yield and wait + ret = notifier->WaitNotify(data); + if (0 != ret) { + // TODO: remove + printf("%s WaitNotify err %d\n", __func__, ret); + notifier_pool_router_.Delete(notifier_id); + notifier_pool->ReleaseNotifier(move(notifier_id.ToUint128())); + + return ret; + } + + notifier_pool_router_.Delete(notifier_id); + notifier_pool->ReleaseNotifier(move(notifier_id.ToUint128())); + + return 0; +} + + +} //namespace phxrpc + diff --git a/phxrpc/rpc/hsha_server.h b/phxrpc/rpc/hsha_server.h index dfc683d..3b02650 100644 --- a/phxrpc/rpc/hsha_server.h +++ b/phxrpc/rpc/hsha_server.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,224 +21,18 @@ See the AUTHORS file for names of contributors. #pragma once -#include -#include -#include -#include -#include -#include -#include -#include "server_config.h" -#include "thread_queue.h" - -#include "phxrpc/network.h" -#include "phxrpc/http.h" -#include "server_base.h" -#include "server_monitor.h" +#include "base_server.h" -namespace phxrpc { - -class WorkerPool; - -class DataFlow { -public: - DataFlow(); - ~DataFlow(); - - void PushRequest(void * args, HttpRequest * request); - int PluckRequest(void *& args, HttpRequest *& request); - void PushResponse(void * args, HttpResponse * response); - int PluckResponse(void *& args, HttpResponse *& response); - bool CanPushRequest(const int max_queue_length); - bool CanPluckResponse(); - - void BreakOut(); - -private: - struct QueueExtData { - QueueExtData() { - enqueue_time_ms = 0; - args = nullptr; - } - QueueExtData(void * t_args) { - enqueue_time_ms = Timer::GetSteadyClockMS(); - args = t_args; - } - uint64_t enqueue_time_ms; - void * args; - }; - ThdQueue > in_queue_; - ThdQueue > out_queue_; -}; - -///////////////////////////////// - -#define RPC_TIME_COST_CAL_RATE 1000 -#define QUEUE_WAIT_TIME_COST_CAL_RATE 1000 -#define MAX_QUEUE_WAIT_TIME_COST 500 -#define MAX_ACCEPT_QUEUE_LENGTH 102400 - -class HshaServerStat { -public: - HshaServerStat(const HshaServerConfig * config, ServerMonitorPtr hsha_server_monitor); - ~HshaServerStat(); - - void CalFunc(); - - class TimeCost { - public: - TimeCost(); - ~TimeCost(); - int Cost(); - private: - uint64_t now_time_ms_; - }; - -private: - void MonitorReport(); - - friend class HshaServerIO; - friend class WorkerPool; - friend class Worker; - friend class HshaServerQos; - friend class HshaServerAcceptor; - const HshaServerConfig * config_; - std::mutex mutex_; - std::condition_variable cv_; - std::thread thread_; - bool break_out_; - ServerMonitorPtr hsha_server_monitor_; - - std::atomic_int hold_fds_; - std::atomic_int accepted_fds_; - int accept_qps_; - std::atomic_int rejected_fds_; - int reject_qps_; - std::atomic_int queue_full_rejected_after_accepted_fds_; - int queue_full_rejected_after_accepted_qps_; - std::atomic_int accept_fail_; - int accept_fail_qps_; - - std::atomic_int io_read_requests_; - int io_read_request_qps_; - std::atomic_int io_write_responses_; - int io_write_response_qps_; - - std::atomic_int io_read_bytes_; - int io_read_bytes_qps_; - std::atomic_int io_write_bytes_; - int io_write_bytes_qps_; - - std::atomic_int io_read_fails_; - int io_read_fail_qps_; - std::atomic_int io_write_fails_; - int io_write_fail_qps_; - - std::atomic_int inqueue_push_requests_; - int inqueue_push_qps_; - std::atomic_int inqueue_pop_requests_; - int inqueue_pop_qps_; - - std::atomic_int outqueue_push_responses_; - int outqueue_push_qps_; - std::atomic_int outqueue_pop_responses_; - int outqueue_pop_qps_; - - std::atomic_int worker_timeouts_; - int worker_timeout_qps_; - - std::atomic_long rpc_time_costs_; - std::atomic_int rpc_time_costs_count_; - int rpc_avg_time_cost_per_second_; - int rpc_time_cost_per_period_; - - std::atomic_long inqueue_wait_time_costs_; - std::atomic_int inqueue_wait_time_costs_count_; - int inqueue_avg_wait_time_costs_per_second_; - int inqueue_avg_wait_time_costs_per_second_cal_seq_; - long inqueue_wait_time_costs_per_period_; - - std::atomic_long outqueue_wait_time_costs_; - std::atomic_int outqueue_wait_time_costs_count_; - int outqueue_avg_wait_time_costs_per_second_; - long outqueue_wait_time_costs_per_period_; - - std::atomic_int enqueue_fast_rejects_; - int enqueue_fast_reject_qps_; - - std::atomic_int worker_idles_; - - std::atomic_int worker_drop_requests_; - int worker_drop_reqeust_qps_; - std::atomic_long worker_time_costs_; - long worker_time_costs_per_second_; -}; - - -////////////////////////////////// -class HshaServerQos { -public: - HshaServerQos(const HshaServerConfig * config, HshaServerStat * hsha_server_stat); - ~HshaServerQos(); - - void CalFunc(); - bool CanAccept(); - bool CanEnqueue(); - -private: - const HshaServerConfig * config_; - HshaServerStat * hsha_server_stat_; - std::mutex mutex_; - std::condition_variable cv_; - std::thread thread_; - bool break_out_; - int enqueue_reject_rate_; - int inqueue_avg_wait_time_costs_per_second_cal_last_seq_; -}; - -////////////////////////////////// - -class Worker { -public: - Worker(WorkerPool * pool); - ~Worker(); - - void Func(); - void Shutdown(); - -private: - WorkerPool * pool_; - bool shut_down_; - std::thread thread_; -}; - -///////////////////////////////// - -typedef std::function< void(const HttpRequest &, HttpResponse *, DispatcherArgs_t *) > Dispatch_t; - -class WorkerPool { -public: - WorkerPool(UThreadEpollScheduler * scheduler, size_t thread_count, DataFlow * data_flow, - HshaServerStat * hsha_server_stat, Dispatch_t dispatch, void * args); - ~WorkerPool(); - -private: - friend class Worker; - UThreadEpollScheduler * scheduler_; - DataFlow * data_flow_; - HshaServerStat * hsha_server_stat_; - Dispatch_t dispatch_; - DispatcherArgs_t dispatcher_args_; - std::vector worker_list_; -}; +namespace phxrpc { -///////////////////////////////// -class HshaServerIO { -public: - HshaServerIO(int idx, UThreadEpollScheduler * scheduler, const HshaServerConfig * config, - DataFlow * data_flow, HshaServerStat * hsha_server_stat, HshaServerQos * hsha_server_qos); +class HshaServerIO final { + public: + HshaServerIO(const int idx, UThreadEpollScheduler *const scheduler, + const HshaServerConfig *config, + DataFlow *data_flow, HshaServerStat *hsha_server_stat, + HshaServerQos *hsha_server_qos, WorkerPool *worker_pool); ~HshaServerIO(); void RunForever(); @@ -249,71 +43,96 @@ class HshaServerIO { void IOFunc(int accept_fd); - UThreadSocket_t * ActiveSocketFunc(); + UThreadSocket_t *ActiveSocketFunc(); -private: - int idx_; - UThreadEpollScheduler * scheduler_; - const HshaServerConfig * config_; - DataFlow * data_flow_; - int listen_fd_; - HshaServerStat * hsha_server_stat_; - HshaServerQos * hsha_server_qos_; + private: + int idx_{-1}; + UThreadEpollScheduler *scheduler_{nullptr}; + const HshaServerConfig *config_{nullptr}; + DataFlow *data_flow_{nullptr}; + HshaServerStat *hsha_server_stat_{nullptr}; + HshaServerQos *hsha_server_qos_{nullptr}; + WorkerPool *worker_pool_{nullptr}; std::queue accepted_fd_list_; std::mutex queue_mutex_; }; -///////////////////////////////// class HshaServer; -class HshaServerUnit { -public: - HshaServerUnit(HshaServer * hsha_server, int idx, int worker_thread_count, Dispatch_t dispatch, void * args); - ~HshaServerUnit(); + +class HshaServerUnit : public BaseServerUnit { + public: + HshaServerUnit(const int idx, + Server *const root_server, + HshaServer *const hsha_server, + int worker_thread_count, + int worker_uthread_count_per_thread, + int worker_uthread_stack_size, + NotifierPoolRouter *const notifier_pool_router, + Dispatch_t dispatch, + void *args); + virtual ~HshaServerUnit() override; void RunFunc(); bool AddAcceptedFd(int accepted_fd); + int NotifyTargetWorker(const int idx, const NotifierPoolRouter::NotifierId ¬ifier_id, + void *const data); -private: - HshaServer * hsha_server_; + private: + Server *root_server_{nullptr}; + HshaServer *hsha_server_{nullptr}; UThreadEpollScheduler scheduler_; - DataFlow data_flow_; - HshaServerIO hsha_server_io_; WorkerPool worker_pool_; + HshaServerIO hsha_server_io_; std::thread thread_; }; -///////////////////////////////// -class HshaServerAcceptor { -public: - HshaServerAcceptor(HshaServer * hsha_server); +class HshaServerAcceptor final { + public: + HshaServerAcceptor(HshaServer *hsha_server); ~HshaServerAcceptor(); - void LoopAccept(const char * bind_ip, const int port); + void LoopAccept(const char *bind_ip, const int port); -private: - HshaServer * hsha_server_; - size_t idx_; + private: + HshaServer *hsha_server_{nullptr}; + size_t idx_{}; }; -///////////////////////////////// -class HshaServer { -public: - HshaServer(const HshaServerConfig & config, Dispatch_t dispatch, void * args); - ~HshaServer(); +class HshaServer : public BaseServer { + public: + HshaServer(const HshaServerConfig &config, const Dispatch_t &dispatch, void *args, + Server *const root_server); + virtual ~HshaServer() override; - void RunForever(); + virtual void DoRunForever() override; + + int SendNotify(const NotifierPoolRouter::NotifierId ¬ifier_id, void *const data); + int WaitNotify(UThreadNotifierPool *const notifier_pool, const int pool_idx, const int worker_idx, + const NotifierPoolRouter::NotifierId ¬ifier_id, void *&data); - const HshaServerConfig * config_; + Server *root_server() const { return root_server_; } + + const HshaServerConfig *config_{nullptr}; ServerMonitorPtr hsha_server_monitor_; HshaServerStat hsha_server_stat_; HshaServerQos hsha_server_qos_; HshaServerAcceptor hsha_server_acceptor_; std::vector server_unit_list_; + + std::thread hsha_accept_thread_; + + private: + void LoopReadCrossUnitResponse(); + + Server *root_server_{nullptr}; + NotifierPoolRouter notifier_pool_router_; }; -} //namespace phxrpc + +} //namespace phxrpc + diff --git a/phxrpc/rpc/http_caller.cpp b/phxrpc/rpc/http_caller.cpp index c177ee8..c5d2897 100644 --- a/phxrpc/rpc/http_caller.cpp +++ b/phxrpc/rpc/http_caller.cpp @@ -1,25 +1,26 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ #include + #include #include "http_caller.h" @@ -27,74 +28,87 @@ See the AUTHORS file for names of contributors. #include "phxrpc/network.h" #include "phxrpc/http.h" +#include "phxrpc/file.h" + namespace phxrpc { -HttpCaller::HttpCaller(BaseTcpStream & socket, ClientMonitor & client_monitor ) - : socket_(socket), client_monitor_(client_monitor), cmdid_(-1) { + +HttpCaller::HttpCaller(BaseTcpStream &socket, ClientMonitor &client_monitor) + : socket_(socket), client_monitor_(client_monitor), cmd_id_(-1) { } HttpCaller::~HttpCaller() { } -HttpRequest & HttpCaller::GetRequest() { - return request_; +HttpRequest &HttpCaller::GetRequest() { + return req_; } -HttpResponse & HttpCaller::GetResponse() { - return response_; +HttpResponse &HttpCaller::GetResponse() { + return resp_; } -void HttpCaller::MonitorReport( ClientMonitor & client_monitor, bool send_error, bool recv_error, size_t send_size, - size_t recv_size, uint64_t call_begin, uint64_t call_end ) { - - if ( send_error ) { +void HttpCaller::MonitorReport(ClientMonitor &client_monitor, bool send_error, + bool recv_error, size_t send_size, + size_t recv_size, uint64_t call_begin, + uint64_t call_end) { + if (send_error) { client_monitor.SendError(); } - if ( recv_error ) { + if (recv_error) { client_monitor.RecvError(); } - client_monitor.SendBytes( send_size ); - client_monitor.RecvBytes( recv_size ); - client_monitor.RequestCost( call_begin, call_end ); - if ( cmdid_ > 0 ) { - client_monitor.ClientCall( cmdid_, GetRequest().GetURI() ); + client_monitor.SendBytes(send_size); + client_monitor.RecvBytes(recv_size); + client_monitor.RequestCost(call_begin, call_end); + if (0 < cmd_id_) { + client_monitor.ClientCall(cmd_id_, GetRequest().GetURI()); } } -int HttpCaller::Call(const google::protobuf::MessageLite & request, google::protobuf::MessageLite * response) { - if (!request.SerializeToString(&request_.GetContent())) { +int HttpCaller::Call(const google::protobuf::MessageLite &req, + google::protobuf::MessageLite *resp) { + if (!req.SerializeToString(&req_.GetContent())) { return -1; } - uint64_t call_begin = Timer::GetSteadyClockMS(); - request_.AddHeader(HttpMessage::HEADER_CONTENT_LENGTH, request_.GetContent().size()); + uint64_t call_begin{Timer::GetSteadyClockMS()}; + req_.AddHeader(HttpMessage::HEADER_CONTENT_LENGTH, req_.GetContent().size()); HttpClient::PostStat post_stat; - int ret = HttpClient::Post(socket_, request_, &response_, &post_stat); - MonitorReport( client_monitor_, post_stat.send_error_, post_stat.recv_error_, request_.GetContent().size(), - response_.GetContent().size(), call_begin, Timer::GetSteadyClockMS() ); - - if (ret != 0) { + int ret{HttpClient::Post(socket_, req_, &resp_, &post_stat)}; + MonitorReport(client_monitor_, post_stat.send_error_, + post_stat.recv_error_, req_.GetContent().size(), + resp_.GetContent().size(), call_begin, + Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "http call err %d", ret); return ret; } - if (!response->ParseFromString(response_.GetContent())) { + if (!resp->ParseFromString(resp_.GetContent())) { return -1; } - const char * result = response_.GetHeaderValue(HttpMessage::HEADER_X_PHXRPC_RESULT); - ret = atoi(NULL == result ? "-1" : result); + const char *result{resp_.GetHeaderValue(HttpMessage::HEADER_X_PHXRPC_RESULT)}; + ret = atoi(nullptr == result ? "-1" : result); + + if (ret < 0) { + phxrpc::log(LOG_ERR, "http call %s err %d", req_.GetURI(), ret); + } + return ret; } -void HttpCaller :: SetURI( const char * uri, int cmdid ) { - cmdid_ = cmdid; - GetRequest().SetURI( uri ); +void HttpCaller::SetURI(const char *const uri, const int cmdid) { + cmd_id_ = cmdid; + GetRequest().SetURI(uri); } -void HttpCaller :: SetKeepAlive( const bool keep_alive ) { +void HttpCaller::SetKeepAlive(const bool keep_alive) { if (keep_alive) { GetRequest().AddHeader(HttpMessage::HEADER_CONNECTION, "Keep-Alive"); } else { @@ -102,4 +116,6 @@ void HttpCaller :: SetKeepAlive( const bool keep_alive ) { } } -} + +} // namespace phxrpc + diff --git a/phxrpc/rpc/http_caller.h b/phxrpc/rpc/http_caller.h index 9818fa5..cec0aad 100644 --- a/phxrpc/rpc/http_caller.h +++ b/phxrpc/rpc/http_caller.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -24,43 +24,55 @@ See the AUTHORS file for names of contributors. #include "client_monitor.h" #include "phxrpc/http.h" + namespace google { + namespace protobuf { + + class MessageLite; -}; -}; + + +} + +} + namespace phxrpc { + class BaseTcpStream; class HttpCaller { -public: - HttpCaller(BaseTcpStream & socket, ClientMonitor & client_monitor ); + public: + HttpCaller(BaseTcpStream &socket, ClientMonitor &client_monitor); + + virtual ~HttpCaller(); - ~HttpCaller(); + HttpRequest &GetRequest(); - HttpRequest & GetRequest(); + HttpResponse &GetResponse(); - HttpResponse & GetResponse(); + int Call(const google::protobuf::MessageLite &req, + google::protobuf::MessageLite *resp); - int Call(const google::protobuf::MessageLite & request, google::protobuf::MessageLite * response); + void SetURI(const char *const uri, const int cmdid); - void SetURI( const char * uri, int cmdid ); + void SetKeepAlive(const bool keep_alive); - void SetKeepAlive( const bool keep_alive ); + private: + void MonitorReport(phxrpc::ClientMonitor &client_monitor, bool send_error, + bool recv_error, size_t send_size, size_t recv_size, + uint64_t call_begin, uint64_t call_end); -private: - void MonitorReport( phxrpc::ClientMonitor & client_monitor, bool send_error, bool recv_error, - size_t send_size, size_t recv_size, uint64_t call_begin, uint64_t call_end ); -private: - BaseTcpStream & socket_; - ClientMonitor & client_monitor_; - int cmdid_; + BaseTcpStream &socket_; + ClientMonitor &client_monitor_; + int cmd_id_; - HttpRequest request_; - HttpResponse response_; + HttpRequest req_; + HttpResponse resp_; }; -} + +} // namespace phxrpc diff --git a/phxrpc/rpc/monitor_factory.cpp b/phxrpc/rpc/monitor_factory.cpp index e07483f..9937432 100644 --- a/phxrpc/rpc/monitor_factory.cpp +++ b/phxrpc/rpc/monitor_factory.cpp @@ -1,57 +1,61 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ +#include #include -#include #include "monitor_factory.h" + namespace phxrpc { -static MonitorFactory * g_monitor_factory_ = NULL; -MonitorFactory :: MonitorFactory() { +static MonitorFactory *g_monitor_factory_ = nullptr; + +MonitorFactory::MonitorFactory() { } -MonitorFactory :: ~MonitorFactory() { +MonitorFactory::~MonitorFactory() { } -void MonitorFactory :: SetFactory( MonitorFactory * factory ) { +void MonitorFactory::SetFactory(MonitorFactory *factory) { g_monitor_factory_ = factory; } -MonitorFactory * MonitorFactory :: GetFactory() { +MonitorFactory *MonitorFactory::GetFactory() { static MonitorFactory monitor_factory; - if ( !g_monitor_factory_ ) { + if (!g_monitor_factory_) { return &monitor_factory; } return g_monitor_factory_; } -ClientMonitorPtr MonitorFactory :: CreateClientMonitor( const char * package_name ) { - return ClientMonitorPtr( new ClientMonitor() ); +ClientMonitorPtr MonitorFactory::CreateClientMonitor(const char *package_name) { + return ClientMonitorPtr(new ClientMonitor()); } -ServerMonitorPtr MonitorFactory :: CreateServerMonitor( const char * package_name ) { - return ServerMonitorPtr( new ServerMonitor() ); +ServerMonitorPtr MonitorFactory::CreateServerMonitor(const char *package_name) { + return ServerMonitorPtr(new ServerMonitor()); } -} + +} // namespace phxrpc + diff --git a/phxrpc/rpc/monitor_factory.h b/phxrpc/rpc/monitor_factory.h index c1c9428..0f16b63 100644 --- a/phxrpc/rpc/monitor_factory.h +++ b/phxrpc/rpc/monitor_factory.h @@ -1,52 +1,54 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ #pragma once + +#include #include #include -#include #include "client_monitor.h" #include "server_monitor.h" + namespace phxrpc { typedef std::shared_ptr ServerMonitorPtr; class MonitorFactory { - public: + public: MonitorFactory(); virtual ~MonitorFactory(); - virtual ClientMonitorPtr CreateClientMonitor( const char * package_name ); - virtual ServerMonitorPtr CreateServerMonitor( const char * package_name ); + virtual ClientMonitorPtr CreateClientMonitor(const char *package_name); + virtual ServerMonitorPtr CreateServerMonitor(const char *package_name); - public: - static void SetFactory( MonitorFactory * factory ); + static void SetFactory(MonitorFactory *factory); - static MonitorFactory * GetFactory(); + static MonitorFactory *GetFactory(); }; -} +} // namespace phxrpc + diff --git a/phxrpc/rpc/mqtt_caller.cpp b/phxrpc/rpc/mqtt_caller.cpp new file mode 100644 index 0000000..490083c --- /dev/null +++ b/phxrpc/rpc/mqtt_caller.cpp @@ -0,0 +1,431 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include + +#include + +#include "mqtt_caller.h" +#include "monitor_factory.h" + +#include "phxrpc/network.h" +#include "phxrpc/http.h" +#include "phxrpc/file.h" + + +namespace phxrpc { + + +MqttCaller::MqttCaller(BaseTcpStream &socket, ClientMonitor &client_monitor) + : socket_(socket), client_monitor_(client_monitor), cmd_id_(-1) { +} + +MqttCaller::~MqttCaller() { +} + +void MqttCaller::MonitorReport(ClientMonitor &client_monitor, bool send_error, + bool recv_error, size_t send_size, + size_t recv_size, uint64_t call_begin, + uint64_t call_end) { + if (send_error) { + client_monitor.SendError(); + } + + if (recv_error) { + client_monitor.RecvError(); + } + + client_monitor.SendBytes(send_size); + client_monitor.RecvBytes(recv_size); + client_monitor.RequestCost(call_begin, call_end); + if (0 < cmd_id_) { + client_monitor.ClientCall(cmd_id_, ""); + } +} + +int MqttCaller::PhxMqttConnectCall(const phxrpc::MqttConnectPb &req, + phxrpc::MqttConnackPb *resp) { + int ret{-1}; + phxrpc::MqttConnect connect; + phxrpc::MqttConnack connack; + + // unpack request + { + ret = static_cast(connect.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Connect(socket_, connect, connack, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, connect.GetContent().size(), + connack.GetContent().size(), call_begin, + Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt connect call err %d", ret); + return ret; + } + + // pack response + { + ret = static_cast(connack.ToPb(resp)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "ToPb ret %d", ret); + + return ret; + } + } + + return ret; +} + +int MqttCaller::PhxMqttPublishCall(const phxrpc::MqttPublishPb &req, + google::protobuf::Empty *resp) { + int ret{-1}; + phxrpc::MqttPublish publish; + + // unpack request + { + ret = static_cast(publish.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Publish(socket_, publish, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, publish.GetContent().size(), + 0, call_begin, Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt publish call err %d", ret); + return ret; + } + + // pack response + //{ + // ret = static_cast(puback.ToPb(resp)); + // if (0 != ret) { + // phxrpc::log(LOG_ERR, "ToPb ret %d", ret); + + // return ret; + // } + //} + + return ret; +} + +int MqttCaller::PhxMqttPubackCall(const phxrpc::MqttPubackPb &req, + google::protobuf::Empty *resp) { + int ret{-1}; + phxrpc::MqttPuback puback; + + // unpack request + { + ret = static_cast(puback.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Puback(socket_, puback, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, puback.GetContent().size(), + 0, call_begin, Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt puback call err %d", ret); + return ret; + } + + return ret; +} + +int MqttCaller::PhxMqttPubrecCall(const phxrpc::MqttPubrecPb &req, + google::protobuf::Empty *resp) { + int ret{-1}; + phxrpc::MqttPubrec pubrec; + + // unpack request + { + ret = static_cast(pubrec.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Pubrec(socket_, pubrec, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, pubrec.GetContent().size(), + 0, call_begin, Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt pubrec call err %d", ret); + return ret; + } + + return ret; +} + +int MqttCaller::PhxMqttPubrelCall(const phxrpc::MqttPubrelPb &req, + google::protobuf::Empty *resp) { + int ret{-1}; + phxrpc::MqttPubrel pubrel; + + // unpack request + { + ret = static_cast(pubrel.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Pubrel(socket_, pubrel, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, pubrel.GetContent().size(), + 0, call_begin, Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt pubrel call err %d", ret); + return ret; + } + + return ret; +} + +int MqttCaller::PhxMqttPubcompCall(const phxrpc::MqttPubcompPb &req, + google::protobuf::Empty *resp) { + int ret{-1}; + phxrpc::MqttPubcomp pubcomp; + + // unpack request + { + ret = static_cast(pubcomp.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Pubcomp(socket_, pubcomp, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, pubcomp.GetContent().size(), + 0, call_begin, Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt pubcomp call err %d", ret); + return ret; + } + + return ret; +} + +int MqttCaller::PhxMqttSubscribeCall(const phxrpc::MqttSubscribePb &req, + phxrpc::MqttSubackPb *resp) { + int ret{-1}; + phxrpc::MqttSubscribe subscribe; + phxrpc::MqttSuback suback; + + // unpack request + { + ret = static_cast(subscribe.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Subscribe(socket_, subscribe, suback, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, subscribe.GetContent().size(), + suback.GetContent().size(), call_begin, + Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt publish call err %d", ret); + return ret; + } + + // pack response + { + ret = static_cast(suback.ToPb(resp)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "ToPb ret %d", ret); + + return ret; + } + } + + return ret; +} + +int MqttCaller::PhxMqttUnsubscribeCall(const phxrpc::MqttUnsubscribePb &req, + phxrpc::MqttUnsubackPb *resp) { + int ret{-1}; + phxrpc::MqttUnsubscribe unsubscribe; + phxrpc::MqttUnsuback unsuback; + + // unpack request + { + ret = static_cast(unsubscribe.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Unsubscribe(socket_, unsubscribe, unsuback, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, unsubscribe.GetContent().size(), + unsuback.GetContent().size(), call_begin, + Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt publish call err %d", ret); + return ret; + } + + // pack response + { + ret = static_cast(unsuback.ToPb(resp)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "ToPb ret %d", ret); + + return ret; + } + } + + return ret; +} + +int MqttCaller::PhxMqttPingCall(const phxrpc::MqttPingreqPb &req, + phxrpc::MqttPingrespPb *resp) { + int ret{-1}; + phxrpc::MqttPingreq pingreq; + phxrpc::MqttPingresp pingresp; + + // unpack request + { + ret = static_cast(pingreq.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Ping(socket_, pingreq, pingresp, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, pingreq.GetContent().size(), + pingresp.GetContent().size(), call_begin, + Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt publish call err %d", ret); + return ret; + } + + // pack response + { + ret = static_cast(pingresp.ToPb(resp)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "ToPb ret %d", ret); + + return ret; + } + } + + return ret; +} + +int MqttCaller::PhxMqttDisconnectCall(const phxrpc::MqttDisconnectPb &req, + google::protobuf::Empty *resp) { + int ret{-1}; + phxrpc::MqttDisconnect disconnect; + + // unpack request + { + ret = static_cast(disconnect.FromPb(req)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + ret = MqttClient::Disconnect(socket_, disconnect, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, disconnect.GetContent().size(), + 0, call_begin, Timer::GetSteadyClockMS()); + + if (0 != ret) { + phxrpc::log(LOG_ERR, "mqtt disconnect call err %d", ret); + return ret; + } + + return ret; +} + +void MqttCaller::SetURI(const char *const uri, const int cmdid) { + cmd_id_ = cmdid; +} + +void MqttCaller::SetKeepAlive(const bool keep_alive) { +} + + +} // namespace phxrpc + diff --git a/phxrpc/rpc/mqtt_caller.h b/phxrpc/rpc/mqtt_caller.h new file mode 100644 index 0000000..d5914b2 --- /dev/null +++ b/phxrpc/rpc/mqtt_caller.h @@ -0,0 +1,92 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "phxrpc/mqtt.h" +#include "phxrpc/rpc/phxrpc.pb.h" + +#include "client_monitor.h" + + +namespace google { + +namespace protobuf { + + +class Empty; +class MessageLite; + + +} + +} + + +namespace phxrpc { + + +class BaseTcpStream; + +class MqttCaller { + public: + MqttCaller(BaseTcpStream &socket, ClientMonitor &client_monitor); + + virtual ~MqttCaller(); + + int PhxMqttConnectCall(const phxrpc::MqttConnectPb &req, + phxrpc::MqttConnackPb *resp); + int PhxMqttPublishCall(const phxrpc::MqttPublishPb &req, + google::protobuf::Empty *resp); + int PhxMqttPubackCall(const phxrpc::MqttPubackPb &req, + google::protobuf::Empty *resp); + int PhxMqttPubrecCall(const phxrpc::MqttPubrecPb &req, + google::protobuf::Empty *resp); + int PhxMqttPubrelCall(const phxrpc::MqttPubrelPb &req, + google::protobuf::Empty *resp); + int PhxMqttPubcompCall(const phxrpc::MqttPubcompPb &req, + google::protobuf::Empty *resp); + int PhxMqttSubscribeCall(const phxrpc::MqttSubscribePb &req, + phxrpc::MqttSubackPb *resp); + int PhxMqttUnsubscribeCall(const phxrpc::MqttUnsubscribePb &req, + phxrpc::MqttUnsubackPb *resp); + int PhxMqttPingCall(const phxrpc::MqttPingreqPb &req, + phxrpc::MqttPingrespPb *resp); + int PhxMqttDisconnectCall(const phxrpc::MqttDisconnectPb &req, + google::protobuf::Empty *resp); + + void SetURI(const char *const uri, const int cmdid); + + void SetKeepAlive(const bool keep_alive); + + private: + void MonitorReport(phxrpc::ClientMonitor &client_monitor, bool send_error, + bool recv_error, size_t send_size, size_t recv_size, + uint64_t call_begin, uint64_t call_end); + + BaseTcpStream &socket_; + ClientMonitor &client_monitor_; + int cmd_id_; +}; + + +} // namespace phxrpc + diff --git a/phxrpc/rpc/phxrpc.proto b/phxrpc/rpc/phxrpc.proto index d9853e8..fce20c3 100644 --- a/phxrpc/rpc/phxrpc.proto +++ b/phxrpc/rpc/phxrpc.proto @@ -1,12 +1,95 @@ -syntax = "proto2"; +syntax = "proto3"; package phxrpc; import "google/protobuf/descriptor.proto"; +import "google/protobuf/wrappers.proto"; + extend google.protobuf.MethodOptions { - optional int32 CmdID = 2000000; - optional string OptString = 2000001; - optional string Usage = 2000002; + int32 CmdID = 2000000; + string OptString = 2000001; + string Usage = 2000002; +} + +message MqttConnectPb { + string client_identifier = 11; + string proto_name = 12; + uint32 proto_level = 13; + bool clean_session = 14; + uint32 keep_alive = 15; + string user_name = 16; + string password = 17; + bool will_flag = 18; + uint32 will_qos = 19; + bool will_retain = 20; + string will_topic = 21; + string will_message = 22; +} + +message MqttConnackPb { + bool session_present = 11; + uint32 connect_return_code = 12; +} + +message MqttPublishPb { + bool dup = 1; + uint32 qos = 2; + bool retain = 3; + uint32 packet_identifier = 11; + string topic_name = 12; + string content = 13; +} + +message MqttPubackPb { + uint32 packet_identifier = 11; +} + +message MqttPubrecPb { +} + +message MqttPubrelPb { +} + +message MqttPubcompPb { +} + +message MqttSubscribePb { + uint32 packet_identifier = 11; + repeated string topic_filters = 12; + repeated uint32 qoss = 13; +} + +message MqttSubackPb { + uint32 packet_identifier = 11; + repeated uint32 return_codes = 12; +} + +message MqttUnsubscribePb { + uint32 packet_identifier = 11; + repeated string topic_filters = 12; +} + +message MqttUnsubackPb { + uint32 packet_identifier = 11; +} + +message MqttPingreqPb { +} + +message MqttPingrespPb { +} + +message MqttDisconnectPb { +} + +message HttpPublishPb { + uint64 session_id = 1; + MqttPublishPb mqtt_publish = 11; +} + +message HttpPubackPb { + uint64 session_id = 1; + MqttPubackPb mqtt_puback = 11; } diff --git a/phxrpc/rpc/resource_pool.h b/phxrpc/rpc/resource_pool.h new file mode 100644 index 0000000..d26906f --- /dev/null +++ b/phxrpc/rpc/resource_pool.h @@ -0,0 +1,69 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include +#include +#include + + +namespace phxrpc { + + +template +class ResourcePoll { + public: + ResourcePoll() {} + ~ResourcePoll() {} + + static ResourcePoll *GetInstance() { + static ResourcePoll pool; + return &pool; + } + + std::unique_ptr Get(const KeyType &key) { + std::lock_guard lg(lock_); + + auto &&it(key2resources_.find(key)); + if (key2resources_.end() == it) return nullptr; + auto &resources = it->second; + if (resources.empty()) return nullptr; + auto resource = std::move(resources.front()); + resources.pop(); + return resource; + } + + void Put(const KeyType &key, std::unique_ptr &resource) { + std::lock_guard lg(lock_); + + auto &&resources = key2resources_[key]; + resources.push(std::move(resource)); + } + + protected: + std::map>> key2resources_; + std::mutex lock_; +}; + + +} // namespace phxrpc + diff --git a/phxrpc/rpc/server.cpp b/phxrpc/rpc/server.cpp new file mode 100644 index 0000000..4047f3e --- /dev/null +++ b/phxrpc/rpc/server.cpp @@ -0,0 +1,45 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "server.h" + + +using namespace std; + + +namespace phxrpc { + + +Server::Server(const HshaServerConfig &config, const Dispatch_t &dispatch, void *args) + : hsha_server_(config, dispatch, args, this), + fa_server_(config, dispatch, args, this) { +} + +Server::~Server() {} + +void Server::RunForever() { + hsha_server_.DoRunForever(); + fa_server_.DoRunForever(); +} + + +} //namespace phxrpc + diff --git a/phxrpc/rpc/server.h b/phxrpc/rpc/server.h new file mode 100644 index 0000000..09950dd --- /dev/null +++ b/phxrpc/rpc/server.h @@ -0,0 +1,48 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#include "fa_server.h" +#include "hsha_server.h" + + +namespace phxrpc { + + +class Server { + public: + Server(const HshaServerConfig &config, const Dispatch_t &dispatch, void *args); + virtual ~Server(); + + HshaServer *hsha_server() { return &hsha_server_; } + FaServer *fa_server() { return &fa_server_; } + + void RunForever(); + + private: + HshaServer hsha_server_; + FaServer fa_server_; +}; + + +} //namespace phxrpc + diff --git a/phxrpc/rpc/server_base.cpp b/phxrpc/rpc/server_base.cpp new file mode 100644 index 0000000..f12df66 --- /dev/null +++ b/phxrpc/rpc/server_base.cpp @@ -0,0 +1,51 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "server_base.h" + +#include +#include +#include + + +namespace phxrpc { + + +void ServerUtils::Daemonize() { + int fd; + + if (fork() != 0) exit(0); /* parent exits */ + setsid(); /* create a new session */ + + /* Every output goes to /dev/null. If Redis is daemonized but + * the 'logfile' is set to 'stdout' in the configuration file + * it will not log at all. */ + if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) close(fd); + } +} + + +} + diff --git a/phxrpc/rpc/server_base.h b/phxrpc/rpc/server_base.h index 484d134..dd5fb54 100644 --- a/phxrpc/rpc/server_base.h +++ b/phxrpc/rpc/server_base.h @@ -22,19 +22,79 @@ See the AUTHORS file for names of contributors. #pragma once #include "server_monitor.h" +#include "phxrpc/network.h" + namespace phxrpc { + +//struct SessionAttribute { +// std::string client_identifier; +// bool clean_session{false}; +// uint32_t keep_alive{10}; +// std::string user_name; +// std::string password; +// bool will_flag{false}; +// uint32_t will_qos{0}; +// bool will_retain{false}; +// std::string will_topic; +// std::string will_message; +//}; + +struct ServiceContext { + uint64_t session_id{0uL}; + bool init_session{false}; + bool heartbeat_session{false}; + bool destroy_session{false}; + //SessionAttribute session_attribute; +}; + + +class Server; +class BaseServerUnit; +class NotifierPoolRouter; +class DataFlow; + typedef struct tagDispatcherArgs { - phxrpc::ServerMonitorPtr server_monitor; - void * service_args; + int pool_idx{-1}; + int worker_idx{-1}; + ServerMonitorPtr server_monitor; + UThreadEpollScheduler *server_worker_uthread_scheduler{nullptr}; + Server *root_server{nullptr}; + BaseServerUnit *base_server_unit{nullptr}; + UThreadNotifierPool *notifier_pool{nullptr}; + NotifierPoolRouter *notifier_pool_router{nullptr}; + void *service_args{nullptr}; + void *context{nullptr}; - tagDispatcherArgs() : service_args(NULL) { + tagDispatcherArgs() : service_args(nullptr) { } - tagDispatcherArgs( phxrpc::ServerMonitorPtr monitor, void * args ) : - server_monitor(monitor), service_args(args) { + tagDispatcherArgs(const int pool_idx_value, const int worker_idx_value, + ServerMonitorPtr server_monitor_value, + UThreadEpollScheduler *const server_worker_uthread_scheduler_value, + Server *const root_server_value, + BaseServerUnit *const base_server_unit_value, + UThreadNotifierPool *notifier_pool_value, + NotifierPoolRouter *notifier_pool_router_value, + void *const service_args_value, void *const context_value) + : pool_idx(pool_idx_value), worker_idx(worker_idx_value), + server_monitor(server_monitor_value), + server_worker_uthread_scheduler(server_worker_uthread_scheduler_value), + root_server(root_server_value), + base_server_unit(base_server_unit_value), + notifier_pool(notifier_pool_value), + notifier_pool_router(notifier_pool_router_value), + service_args(service_args_value), context(context_value) { } -}DispatcherArgs_t; +} DispatcherArgs_t; + + +class ServerUtils { + public: + static void Daemonize(); +}; + } + diff --git a/phxrpc/rpc/server_config.cpp b/phxrpc/rpc/server_config.cpp index 9b27a37..aa998f5 100644 --- a/phxrpc/rpc/server_config.cpp +++ b/phxrpc/rpc/server_config.cpp @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -24,20 +24,23 @@ See the AUTHORS file for names of contributors. #include "server_config.h" #include "phxrpc/file.h" + namespace phxrpc { + ServerConfig::ServerConfig() { memset(bind_ip_, 0, sizeof(bind_ip_)); port_ = -1; + mqtt_port_ = -1; max_threads_ = 120; - socket_timeout_ms_ = 5000; + socket_timeout_ms_ = 30000; memset(package_name_, 0, sizeof(package_name_)) ; } ServerConfig::~ServerConfig() { } -bool ServerConfig::Read(const char * config_file) { +bool ServerConfig::Read(const char *config_file) { Config config; if (!config.InitConfig(config_file)) { return false; @@ -46,9 +49,13 @@ bool ServerConfig::Read(const char * config_file) { bool succ = true; succ &= config.ReadItem("Server", "BindIP", bind_ip_, sizeof(bind_ip_)); succ &= config.ReadItem("Server", "Port", &port_); + succ &= config.ReadItem("Server", "MqttPort", &mqtt_port_); succ &= config.ReadItem("Server", "PackageName", package_name_, sizeof(package_name_)); config.ReadItem("Server", "MaxThreads", &max_threads_, 20); - config.ReadItem("ServerTimeout", "SocketTimeoutMS", &socket_timeout_ms_, 5000); + // TODO: + config.ReadItem("Log", "LogDir", log_dir_, sizeof(log_dir_), "/data1/mm64/walnuthe/log"); + config.ReadItem("Log", "LogLevel", &log_level_, LOG_ERR); + config.ReadItem("ServerTimeout", "SocketTimeoutMS", &socket_timeout_ms_, 30000); if (succ) { return DoRead(config); @@ -58,15 +65,15 @@ bool ServerConfig::Read(const char * config_file) { } } -bool ServerConfig :: DoRead(Config & config) { +bool ServerConfig::DoRead(Config &config) { return true; } -void ServerConfig::SetBindIP(const char * ip) { +void ServerConfig::SetBindIP(const char *ip) { snprintf(bind_ip_, sizeof(bind_ip_), "%s", ip); } -const char * ServerConfig::GetBindIP() const { +const char *ServerConfig::GetBindIP() const { return bind_ip_; } @@ -78,6 +85,14 @@ int ServerConfig::GetPort() const { return port_; } +void ServerConfig::SetMqttPort(int mqtt_port) { + mqtt_port_ = mqtt_port; +} + +int ServerConfig::GetMqttPort() const { + return mqtt_port_; +} + void ServerConfig::SetMaxThreads(int max_threads) { max_threads_ = max_threads; } @@ -94,64 +109,108 @@ int ServerConfig::GetSocketTimeoutMS() const { return socket_timeout_ms_; } -void ServerConfig::SetPackageName(const char * package_name) { +void ServerConfig::SetPackageName(const char *package_name) { strncpy(package_name_,package_name, sizeof(package_name_) - 1); } -const char * ServerConfig :: GetPackageName() const { +const char *ServerConfig::GetPackageName() const { return package_name_; } +const char *ServerConfig::GetLogDir() const { + return log_dir_; +} + +void ServerConfig::SetLogLevel(int log_level) { + log_level_ = log_level; +} + +int ServerConfig::GetLogLevel() const { + return log_level_; +} + ////////////////////////////////////////////////////// -HshaServerConfig :: HshaServerConfig() - : max_connections_(800000), - max_queue_length_(20480), +HshaServerConfig::HshaServerConfig() + : max_connections_(800000), + max_queue_length_(20480), fast_reject_threshold_ms_(20), - io_thread_count_(3) { + fast_reject_adjust_rate_(5), + io_thread_count_(3), + worker_uthread_count_(0), + worker_uthread_stack_size_(64 * 1024) { } -HshaServerConfig :: ~HshaServerConfig() { +HshaServerConfig::~HshaServerConfig() { } -bool HshaServerConfig :: DoRead(Config & config) { +bool HshaServerConfig::DoRead(Config &config) { config.ReadItem("Server", "MaxConnections", &max_connections_, 800000); config.ReadItem("Server", "IOThreadCount", &io_thread_count_, 3); + config.ReadItem("Server", "WorkerUThreadCount", &worker_uthread_count_, 0); + config.ReadItem("Server", "WorkerUThreadStackSize", &worker_uthread_stack_size_, 64 * 1024); config.ReadItem("Server", "MaxQueueLength", &max_queue_length_, 20480); config.ReadItem("Server", "FastRejectThresholdMS", &fast_reject_threshold_ms_, 20); + config.ReadItem("Server", "FastRejectAdjustRate", &fast_reject_adjust_rate_, 5); return true; } -void HshaServerConfig :: SetMaxConnections(const int max_connections) { +void HshaServerConfig::SetMaxConnections(const int max_connections) { max_connections_ = max_connections; } -int HshaServerConfig :: GetMaxConnections() const { +int HshaServerConfig::GetMaxConnections() const { return max_connections_; } -void HshaServerConfig :: SetMaxQueueLength(const int max_queue_length) { +void HshaServerConfig::SetMaxQueueLength(const int max_queue_length) { max_queue_length_ = max_queue_length; } -int HshaServerConfig :: GetMaxQueueLength() const { +int HshaServerConfig::GetMaxQueueLength() const { return max_queue_length_; } -void HshaServerConfig :: SetFastRejectThresholdMS(const int fast_reject_threshold_ms) { +void HshaServerConfig::SetFastRejectThresholdMS(const int fast_reject_threshold_ms) { fast_reject_threshold_ms_ = fast_reject_threshold_ms; } -int HshaServerConfig :: GetFastRejectThresholdMS() const { +int HshaServerConfig::GetFastRejectThresholdMS() const { return fast_reject_threshold_ms_; } -void HshaServerConfig :: SetIOThreadCount(const int io_thread_count) { +void HshaServerConfig::SetFastRejectAdjustRate(const int fast_reject_adjust_rate) { + fast_reject_adjust_rate_ = fast_reject_adjust_rate; +} + +int HshaServerConfig::GetFastRejectAdjustRate() const { + return fast_reject_adjust_rate_; +} + +void HshaServerConfig::SetIOThreadCount(const int io_thread_count) { io_thread_count_ = io_thread_count; } -int HshaServerConfig :: GetIOThreadCount() const { +int HshaServerConfig::GetIOThreadCount() const { return io_thread_count_; } +void HshaServerConfig::SetWorkerUThreadCount(const int worker_uthread_count) { + worker_uthread_count_ = worker_uthread_count; +} + +int HshaServerConfig::GetWorkerUThreadCount() const { + return worker_uthread_count_; +} + +void HshaServerConfig::SetWorkerUThreadStackSize(const int worker_uthread_stack_size) { + worker_uthread_stack_size_ = worker_uthread_stack_size; +} + +int HshaServerConfig::GetWorkerUThreadStackSize() const { + return worker_uthread_stack_size_; } + + +} // namespace phxrpc + diff --git a/phxrpc/rpc/server_config.h b/phxrpc/rpc/server_config.h index e98321e..8437514 100644 --- a/phxrpc/rpc/server_config.h +++ b/phxrpc/rpc/server_config.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,50 +21,65 @@ See the AUTHORS file for names of contributors. #pragma once -#include #include +#include + #include "phxrpc/file.h" + namespace phxrpc { + class ServerConfig { -public: + public: ServerConfig(); virtual ~ServerConfig(); - bool Read(const char * config_file); + bool Read(const char *config_file); - virtual bool DoRead(Config & config); + virtual bool DoRead(Config &config); - void SetBindIP(const char * ip); - const char * GetBindIP() const; + void SetBindIP(const char *ip); + const char *GetBindIP() const; void SetPort(int port); int GetPort() const; + void SetMqttPort(int mqtt_port); + int GetMqttPort() const; + void SetMaxThreads(int max_threads); int GetMaxThreads() const; void SetSocketTimeoutMS(int socket_timeout_ms); int GetSocketTimeoutMS() const; - void SetPackageName(const char * package_name); - const char * GetPackageName() const; + void SetPackageName(const char *package_name); + const char *GetPackageName() const; + + const char *GetLogDir() const; -private: + void SetLogLevel(int log_level); + int GetLogLevel() const; + + private: char bind_ip_[32]; int port_; + int mqtt_port_; int max_threads_; int socket_timeout_ms_; char package_name_[64]; + char log_dir_[128]; + int log_level_; }; + class HshaServerConfig : public ServerConfig { -public: + public: HshaServerConfig(); - ~HshaServerConfig(); + virtual ~HshaServerConfig() override; - bool DoRead(Config & config); + bool DoRead(Config &config) override; void SetMaxConnections(const int max_connections); int GetMaxConnections() const; @@ -75,15 +90,28 @@ class HshaServerConfig : public ServerConfig { void SetFastRejectThresholdMS(const int fast_reject_threshold_ms); int GetFastRejectThresholdMS() const; + void SetFastRejectAdjustRate(const int fast_reject_adjust_rate); + int GetFastRejectAdjustRate() const; + void SetIOThreadCount(const int io_thread_count); int GetIOThreadCount() const; -private: + void SetWorkerUThreadCount(const int worker_uthread_count); + int GetWorkerUThreadCount() const; + + void SetWorkerUThreadStackSize(const int worker_uthread_stack_size); + int GetWorkerUThreadStackSize() const; + + private: int max_connections_; int max_queue_length_; int fast_reject_threshold_ms_; + int fast_reject_adjust_rate_; int io_thread_count_; + int worker_uthread_count_; + int worker_uthread_stack_size_; }; -} + +} // namespace phxrpc diff --git a/phxrpc/rpc/socket_stream_phxrpc.cpp b/phxrpc/rpc/socket_stream_phxrpc.cpp index 5257bf3..bf0b26d 100644 --- a/phxrpc/rpc/socket_stream_phxrpc.cpp +++ b/phxrpc/rpc/socket_stream_phxrpc.cpp @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -21,28 +21,37 @@ See the AUTHORS file for names of contributors. #include "socket_stream_phxrpc.h" + namespace phxrpc { -bool PhxrpcTcpUtils :: Open(BlockTcpStream * stream, const char * ip, unsigned short port, int connect_timeout_ms, - const char * bind_addr, int bind_port, ClientMonitor & client_monitor ) { - bool ret = BlockTcpUtils::Open( stream, ip, port, connect_timeout_ms, - bind_addr, bind_port ); - client_monitor.ClientConnect( ret ); + +bool PhxrpcTcpUtils::Open(BlockTcpStream *stream, const char *ip, + unsigned short port, int connect_timeout_ms, + const char *bind_addr, int bind_port, + ClientMonitor &client_monitor) { + bool ret = BlockTcpUtils::Open(stream, ip, port, connect_timeout_ms, + bind_addr, bind_port); + client_monitor.ClientConnect(ret); + return ret; } -bool PhxrpcTcpUtils :: Open(UThreadEpollScheduler * tt, UThreadTcpStream* stream, const char * ip, unsigned short port, - int connect_timeout_ms, ClientMonitor & client_monitor ) { - bool ret = UThreadTcpUtils::Open( tt, stream, ip, port, connect_timeout_ms ); +bool PhxrpcTcpUtils::Open(UThreadEpollScheduler *tt, UThreadTcpStream *stream, + const char *ip, unsigned short port, + int connect_timeout_ms, + ClientMonitor &client_monitor) { + bool ret = UThreadTcpUtils::Open(tt, stream, ip, port, connect_timeout_ms); if (!ret && errno == 0) { //normal active close client_monitor.ClientConnect(true); } else { client_monitor.ClientConnect(ret); } + return ret; } -} +} // namespace phxrpc + diff --git a/phxrpc/rpc/socket_stream_phxrpc.h b/phxrpc/rpc/socket_stream_phxrpc.h index 0a13ace..f031628 100644 --- a/phxrpc/rpc/socket_stream_phxrpc.h +++ b/phxrpc/rpc/socket_stream_phxrpc.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -24,15 +24,22 @@ See the AUTHORS file for names of contributors. #include "client_monitor.h" #include "phxrpc/network.h" + namespace phxrpc { -class PhxrpcTcpUtils { - public: - static bool Open(BlockTcpStream * stream, const char * ip, unsigned short port, int connect_timeout_ms, - const char * bind_addr, int bind_port, ClientMonitor & client_monitor ); - static bool Open(UThreadEpollScheduler * tt, UThreadTcpStream* stream, const char * ip, unsigned short port, - int connect_timeout_ms, ClientMonitor & client_monitor ); +class PhxrpcTcpUtils { + public: + static bool Open(BlockTcpStream *stream, const char *ip, + unsigned short port, int connect_timeout_ms, + const char *bind_addr, int bind_port, + ClientMonitor &client_monitor); + + static bool Open(UThreadEpollScheduler *tt, UThreadTcpStream *stream, + const char *ip, unsigned short port, + int connect_timeout_ms, ClientMonitor &client_monitor); }; -} + +} // namespace phxrpc + diff --git a/phxrpc/rpc/test_hsha_server.cpp b/phxrpc/rpc/test_hsha_server.cpp index e32d50a..56c9c57 100644 --- a/phxrpc/rpc/test_hsha_server.cpp +++ b/phxrpc/rpc/test_hsha_server.cpp @@ -1,44 +1,54 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ +#include + #include "phxrpc/rpc.h" -#include + using namespace phxrpc; -void Dispatch(const HttpRequest & request, HttpResponse * response, void * args) { + +void Dispatch(const BaseRequest *req, BaseResponse *resp, void *args) { printf("dispatch args %p\n", args); - response->AddHeader(HttpMessage::HEADER_X_PHXRPC_RESULT, 0); + resp->SetPhxRpcResult(0); } -int main(int argc, char ** argv) { +int main(int argc, char **argv) { HshaServerConfig config; config.SetBindIP("127.0.0.1"); config.SetPort(26161); config.SetMaxThreads(2); + //config.SetLogDir("~/log"); + //config.SetLogLevel(3); printf("args %p\n", &config); + phxrpc::openlog(argv[0], config.GetLogDir(), config.GetLogLevel()); + HshaServer server(config, Dispatch, &config); server.RunForever(); - + + phxrpc::closelog(); + return 0; } + diff --git a/phxrpc/rpc/test_client.cpp b/phxrpc/rpc/test_http_client.cpp similarity index 58% rename from phxrpc/rpc/test_client.cpp rename to phxrpc/rpc/test_http_client.cpp index 3c6610d..d6d508c 100644 --- a/phxrpc/rpc/test_client.cpp +++ b/phxrpc/rpc/test_http_client.cpp @@ -1,26 +1,28 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include #include + +#include + #include #include "monitor_factory.h" @@ -29,30 +31,33 @@ See the AUTHORS file for names of contributors. #include "phxrpc/network.h" #include "phxrpc/http.h" + using namespace phxrpc; -int main(int argc, char ** argv) { - for (size_t i = 0; i < 20; i++) { + +int main(int argc, char **argv) { + for (size_t i{0}; 20 > i; ++i) { phxrpc::BlockTcpStream socket; - if(phxrpc::BlockTcpUtils::Open(&socket, "127.0.0.1", 26161, 200, NULL, 0)) { + if(phxrpc::BlockTcpUtils::Open(&socket, "127.0.0.1", 26161, 200, nullptr, 0)) { socket.SetTimeout(5000); - HttpRequest request; - HttpResponse response; + HttpRequest req; + HttpResponse resp; - request.GetContent() = "hello grpc"; - request.SetURI("abc"); - request.AddHeader(HttpMessage::HEADER_CONTENT_LENGTH, request.GetContent().size()); - int ret = HttpClient::Post(socket, request, &response); + req.GetContent() = "hello grpc"; + req.SetURI("abc"); + req.AddHeader(HttpMessage::HEADER_CONTENT_LENGTH, req.GetContent().size()); + int ret{HttpClient::Post(socket, req, &resp)}; if (ret != 0) { printf("post fail, %zu, ret %d\n", i, ret); continue; } - const char * result = response.GetHeaderValue(HttpMessage::HEADER_X_PHXRPC_RESULT); - ret = atoi(NULL == result ? "-1" : result); + const char *result{resp.GetHeaderValue(HttpMessage::HEADER_X_PHXRPC_RESULT)}; + ret = atoi(nullptr == result ? "-1" : result); printf("post ret %d\n", ret); } } return 0; } + diff --git a/phxrpc/rpc/test_mqtt_client.cpp b/phxrpc/rpc/test_mqtt_client.cpp new file mode 100644 index 0000000..d1eafb3 --- /dev/null +++ b/phxrpc/rpc/test_mqtt_client.cpp @@ -0,0 +1,101 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include + +#include + +#include + +#include "monitor_factory.h" +#include "http_caller.h" + +#include "phxrpc/network.h" +#include "phxrpc/mqtt.h" + + +using namespace phxrpc; + + +int main(int argc, char **argv) { + // 1. connect + + for (size_t i{0}; 20 > i; ++i) { + phxrpc::BlockTcpStream socket; + if(phxrpc::BlockTcpUtils::Open(&socket, "127.0.0.1", 26161, 200, nullptr, 0)) { + socket.SetTimeout(5000); + MqttConnect req; + MqttConnack resp; + + int ret{MqttClient::Connect(socket, req, resp)}; + if (0 != ret) { + printf("try %zu connect fail ret %d\n", i, ret); + continue; + } + + printf("try %zu connect ret %d connect_return_code %d\n", + i, ret, resp.connect_return_code()); + } + } + + // 2. publish + + for (size_t i{0}; 20 > i; ++i) { + phxrpc::BlockTcpStream socket; + if(phxrpc::BlockTcpUtils::Open(&socket, "127.0.0.1", 26161, 200, nullptr, 0)) { + socket.SetTimeout(5000); + MqttPublish req; + MqttPuback resp; + req.set_topic_name("test_topic_1"); + req.set_packet_identifier(i); + + int ret{MqttClient::Publish(socket, req, resp)}; + if (0 != ret) { + printf("try %zu publish fail ret %d\n", i, ret); + continue; + } + + printf("try %zu publish ret %d packet_identifier %u\n", + i, ret, resp.packet_identifier()); + } + } + + // 3. disconnect + + for (size_t i{0}; 20 > i; ++i) { + phxrpc::BlockTcpStream socket; + if(phxrpc::BlockTcpUtils::Open(&socket, "127.0.0.1", 26161, 200, nullptr, 0)) { + socket.SetTimeout(5000); + MqttDisconnect req; + + int ret{MqttClient::Disconnect(socket, req)}; + if (0 != ret) { + printf("try %zu disconnect fail ret %d\n", i, ret); + continue; + } + + printf("try %zu disconnect ret %d\n", i, ret); + } + } + + return 0; +} + diff --git a/phxrpc/rpc/test_thread_queue.cpp b/phxrpc/rpc/test_thread_queue.cpp index 5d5dc0e..d0d1177 100644 --- a/phxrpc/rpc/test_thread_queue.cpp +++ b/phxrpc/rpc/test_thread_queue.cpp @@ -1,35 +1,38 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ +#include #include -#include -#include #include +#include + #include "thread_queue.h" + using namespace std; using namespace phxrpc; + class PluckThread { -public: + public: PluckThread(ThdQueue * thd_queue, const size_t thread_count) : thd_queue_(thd_queue) { for (size_t i = 0; i < thread_count; i++) { @@ -58,7 +61,7 @@ class PluckThread { } while (!thd_queue_->empty()); } -private: + private: ThdQueue * thd_queue_; vector thread_list_; }; @@ -74,3 +77,4 @@ int main(int argc, char ** argv) { return 0; } + diff --git a/phxrpc/rpc/thread_queue.h b/phxrpc/rpc/thread_queue.h index 8892014..822df6e 100644 --- a/phxrpc/rpc/thread_queue.h +++ b/phxrpc/rpc/thread_queue.h @@ -66,6 +66,18 @@ class ThdQueue { return true; } + bool pick(T & value) { + std::lock_guard lock(mutex_); + if (queue_.empty()) { + return false; + } + + size_--; + value = queue_.front(); + queue_.pop(); + return true; + } + void break_out() { std::lock_guard lock(mutex_); break_out_ = true; diff --git a/phxrpc/rpc/uthread_caller.cpp b/phxrpc/rpc/uthread_caller.cpp index 01ce222..16b045d 100644 --- a/phxrpc/rpc/uthread_caller.cpp +++ b/phxrpc/rpc/uthread_caller.cpp @@ -1,25 +1,25 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. */ -#include +#include #include "uthread_caller.h" #include "http_caller.h" @@ -27,18 +27,28 @@ See the AUTHORS file for names of contributors. #include "phxrpc/network.h" + namespace phxrpc { -UThreadCaller::UThreadCaller(UThreadEpollScheduler * uthread_scheduler, google::protobuf::MessageLite & request, - google::protobuf::MessageLite * response, ClientMonitor & client_monitor, const std::string & uri, int cmdid, - const Endpoint_t & ep, const int connect_timeout_ms, const int socket_timeout_ms, UThreadCallback callback, - void * args) + +using namespace std; + + +UThreadCaller::UThreadCaller(UThreadEpollScheduler *uthread_scheduler, + google::protobuf::MessageLite &request, + google::protobuf::MessageLite *response, + ClientMonitor &client_monitor, + const Protocol protocol, const string &uri, + const int cmd_id, const Endpoint_t &ep, + const int connect_timeout_ms, + const int socket_timeout_ms, + UThreadCallback callback, void *args) : uthread_scheduler_(uthread_scheduler), request_(&request), response_(response), client_monitor_(client_monitor), uri_(uri), - cmdid_(cmdid), + cmd_id_(cmd_id), ep_(ep), mconnect_timeout_ms(connect_timeout_ms), msocket_timeout_ms(socket_timeout_ms), @@ -50,27 +60,27 @@ UThreadCaller::UThreadCaller(UThreadEpollScheduler * uthread_scheduler, google:: UThreadCaller::~UThreadCaller() { } -google::protobuf::MessageLite & UThreadCaller::GetRequest() { +google::protobuf::MessageLite &UThreadCaller::GetRequest() { return *request_; } -google::protobuf::MessageLite * UThreadCaller::GetResponse() { +google::protobuf::MessageLite *UThreadCaller::GetResponse() { return response_; } -const std::string & UThreadCaller::GetURI() { +const string &UThreadCaller::GetURI() { return uri_; } int UThreadCaller::GetCmdID() { - return cmdid_; + return cmd_id_; } -UThreadEpollScheduler * UThreadCaller::Getuthread_scheduler() { +UThreadEpollScheduler *UThreadCaller::Getuthread_scheduler() { return uthread_scheduler_; } -Endpoint_t * UThreadCaller::GetEP() { +Endpoint_t *UThreadCaller::GetEP() { return &ep_; } @@ -83,27 +93,29 @@ void UThreadCaller::SetRet(const int ret) { } void UThreadCaller::Callback() { - if (NULL != callback_) { + if (nullptr != callback_) { callback_(this, args_); } } -void UThreadCaller::Call(void * args) { - UThreadCaller * uthread_caller = (UThreadCaller *) args; +void UThreadCaller::Call(void *args) { + UThreadCaller *uthread_caller = (UThreadCaller *)args; UThreadTcpStream socket; - Endpoint_t * ep = uthread_caller->GetEP(); - bool open_ret = phxrpc::UThreadTcpUtils::Open(uthread_caller->Getuthread_scheduler(), &socket, ep->ip, ep->port, - uthread_caller->mconnect_timeout_ms ); - if ( open_ret ) { + Endpoint_t *ep = uthread_caller->GetEP(); + bool open_ret = phxrpc::UThreadTcpUtils::Open( + uthread_caller->Getuthread_scheduler(), &socket, ep->ip, ep->port, + uthread_caller->mconnect_timeout_ms); + if (open_ret) { socket.SetTimeout(uthread_caller->msocket_timeout_ms); phxrpc::HttpCaller caller(socket, uthread_caller->client_monitor_); caller.GetRequest().SetURI(uthread_caller->GetURI().c_str()); - uthread_caller->SetRet(caller.Call(uthread_caller->GetRequest(), uthread_caller->GetResponse())); + uthread_caller->SetRet(caller.Call(uthread_caller->GetRequest(), + uthread_caller->GetResponse())); } else { uthread_caller->SetRet(-1); } - uthread_caller->client_monitor_.ClientConnect( open_ret ); + uthread_caller->client_monitor_.ClientConnect(open_ret); uthread_caller->Callback(); } @@ -119,8 +131,8 @@ UThreadMultiCaller::UThreadMultiCaller( ClientMonitor & client_monitor ) } UThreadMultiCaller::~UThreadMultiCaller() { - for (size_t i = 0; i < uthread_caller_list_.size(); i++) { - if (NULL != uthread_caller_list_[i]) { + for (size_t i{0}; i < uthread_caller_list_.size(); ++i) { + if (nullptr != uthread_caller_list_[i]) { delete uthread_caller_list_[i]; } } @@ -135,21 +147,27 @@ const int UThreadMultiCaller::GetRet(size_t index) { return uthread_caller_list_[index]->GetRet(); } -void UThreadMultiCaller::AddCaller(google::protobuf::MessageLite & request, google::protobuf::MessageLite * response, - const std::string & uri, int cmdid, const Endpoint_t & ep, const int connect_timeout_ms, - const int socket_timeout_ms, UThreadCallback callback, void * args) { - UThreadCaller * caller = new UThreadCaller(&uthread_scheduler_, request, response, client_monitor_, uri, cmdid, - ep, connect_timeout_ms, socket_timeout_ms, callback, args); - assert(NULL != caller); +void UThreadMultiCaller::AddCaller(google::protobuf::MessageLite &request, + google::protobuf::MessageLite *response, + const Protocol protocol, const string &uri, + const int cmd_id, const Endpoint_t &ep, + const int connect_timeout_ms, + const int socket_timeout_ms, + UThreadCallback callback, void *args) { + UThreadCaller *caller = new UThreadCaller(&uthread_scheduler_, + request, response, client_monitor_, protocol, uri, cmd_id, ep, + connect_timeout_ms, socket_timeout_ms, callback, args); + assert(nullptr != caller); uthread_caller_list_.push_back(caller); - uthread_scheduler_.AddTask(UThreadCaller::Call, (void *) caller); + uthread_scheduler_.AddTask(UThreadCaller::Call, (void *)caller); } void UThreadMultiCaller::MultiCall() { uthread_scheduler_.Run(); } + } diff --git a/phxrpc/rpc/uthread_caller.h b/phxrpc/rpc/uthread_caller.h index 579c288..e2db95a 100644 --- a/phxrpc/rpc/uthread_caller.h +++ b/phxrpc/rpc/uthread_caller.h @@ -1,19 +1,19 @@ /* -Tencent is pleased to support the open source community by making +Tencent is pleased to support the open source community by making PhxRPC available. -Copyright (C) 2016 THL A29 Limited, a Tencent company. +Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the BSD 3-Clause License (the "License"); you may -not use this file except in compliance with the License. You may +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may obtain a copy of the License at https://opensource.org/licenses/BSD-3-Clause -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions and limitations under the License. See the AUTHORS file for names of contributors. @@ -23,86 +23,110 @@ See the AUTHORS file for names of contributors. #include #include -#include "client_config.h" + +#include "phxrpc/msg/common.h" #include "phxrpc/network.h" +#include "client_config.h" + + namespace google { + namespace protobuf { + + class MessageLite; + + } -; + } -; + namespace phxrpc { + class UThreadEpollScheduler; class UThreadCaller; class ClientMonitor; -typedef void (*UThreadCallback)(UThreadCaller * caller, void * args); +class MqttConnect; +class MqttConnack; +class MqttPublish; +class MqttPuback; +class MqttDisconnect; + +typedef void (*UThreadCallback)(UThreadCaller *caller, void *args); class UThreadCaller { - public: - UThreadCaller(UThreadEpollScheduler * uthread_scheduler, google::protobuf::MessageLite & request, - google::protobuf::MessageLite * response, ClientMonitor & client_monitor, const std::string & uri, int cmdid, - const Endpoint_t & ep, const int connect_timeout_ms, const int socket_timeout_ms, UThreadCallback callback, void * args); + public: + UThreadCaller(UThreadEpollScheduler *uthread_scheduler, + google::protobuf::MessageLite &request, + google::protobuf::MessageLite *response, + ClientMonitor &client_monitor, + const Protocol protocol, const std::string &uri, + const int cmd_id, const Endpoint_t &ep, + const int connect_timeout_ms, const int socket_timeout_ms, + UThreadCallback callback, void *args); virtual ~UThreadCaller(); void Close(); - virtual google::protobuf::MessageLite & GetRequest(); - virtual google::protobuf::MessageLite * GetResponse(); - const std::string & GetURI(); + virtual google::protobuf::MessageLite &GetRequest(); + virtual google::protobuf::MessageLite *GetResponse(); + const std::string &GetURI(); int GetCmdID(); - UThreadEpollScheduler * Getuthread_scheduler(); - Endpoint_t * GetEP(); + UThreadEpollScheduler *Getuthread_scheduler(); + Endpoint_t *GetEP(); const int GetRet(); void SetRet(const int ret); void Callback(); - static void Call(void * args); - - private: - UThreadEpollScheduler * uthread_scheduler_; - google::protobuf::MessageLite * request_; - google::protobuf::MessageLite * response_; - ClientMonitor & client_monitor_; - std::string uri_; - int cmdid_; - Endpoint_t ep_; + static void Call(void *args); - public: int mconnect_timeout_ms; int msocket_timeout_ms; - private: + private: + UThreadEpollScheduler *uthread_scheduler_; + google::protobuf::MessageLite *request_; + google::protobuf::MessageLite *response_; + ClientMonitor &client_monitor_; + std::string uri_; + int cmd_id_; + Endpoint_t ep_; + int call_ret_; UThreadCallback callback_; - void * args_; + void *args_; }; /////////////////////////////////////////////////////// class UThreadMultiCaller { - public: - UThreadMultiCaller( ClientMonitor & client_monitor ); - ~UThreadMultiCaller(); + public: + UThreadMultiCaller(ClientMonitor &client_monitor); + virtual ~UThreadMultiCaller(); - void AddCaller(google::protobuf::MessageLite & request, google::protobuf::MessageLite * response, const std::string & uri, - int cmdid, const Endpoint_t & ep, const int connect_timeout_ms, const int socket_timeout_ms, - UThreadCallback callback = NULL, void * args = NULL); + void AddCaller(google::protobuf::MessageLite &request, + google::protobuf::MessageLite *response, + const Protocol protocol, const std::string &uri, + const int cmd_id, const Endpoint_t &ep, + const int connect_timeout_ms, const int socket_timeout_ms, + UThreadCallback callback = nullptr, void *args = nullptr); void MultiCall(); const int GetRet(size_t index); - private: + private: UThreadEpollScheduler uthread_scheduler_; std::vector uthread_caller_list_; ClientMonitor & client_monitor_; }; + } + diff --git a/plugin_boost/network/uthread_context_boost.cpp b/plugin_boost/network/uthread_context_boost.cpp index f55075c..14d01d2 100644 --- a/plugin_boost/network/uthread_context_boost.cpp +++ b/plugin_boost/network/uthread_context_boost.cpp @@ -36,29 +36,25 @@ UThreadContextBoostInit :: UThreadContextBoostInit() { } UThreadContextBoost :: UThreadContextBoost(size_t stack_size, UThreadFunc_t func, - void * args, UThreadDoneCallback_t callback) - : func_(func), args_(args), stack_(nullptr), stack_size_(stack_size), - protect_page_(0), callback_(callback) { - stack_ = (char *)calloc(1, stack_size_); - assert(stack_ != nullptr); - + void * args, UThreadDoneCallback_t callback, const bool need_stack_protect) + : func_(func), args_(args), stack_(stack_size, need_stack_protect), callback_(callback) { Make(func, args); } UThreadContextBoost :: ~UThreadContextBoost() { - free(stack_); } UThreadContext * UThreadContextBoost:: DoCreate(size_t stack_size, - UThreadFunc_t func, void * args, UThreadDoneCallback_t callback) { - return new UThreadContextBoost(stack_size, func, args, callback); + UThreadFunc_t func, void * args, UThreadDoneCallback_t callback, + const bool need_stack_protect) { + return new UThreadContextBoost(stack_size, func, args, callback, need_stack_protect); } void UThreadContextBoost :: Make(UThreadFunc_t func, void * args) { func_ = func; args_ = args; - void * stack_p = (void *)(stack_ + stack_size_); - context_ = boost::context::make_fcontext(stack_p, stack_size_, &UThreadFuncWrapper); + void * stack_p = (void *)((char *)stack_.top() + stack_.size()); + context_ = boost::context::make_fcontext(stack_p, stack_.size(), &UThreadFuncWrapper); } bool UThreadContextBoost :: Resume() { diff --git a/plugin_boost/network/uthread_context_boost.h b/plugin_boost/network/uthread_context_boost.h index 3816c10..a1b69cc 100644 --- a/plugin_boost/network/uthread_context_boost.h +++ b/plugin_boost/network/uthread_context_boost.h @@ -36,11 +36,13 @@ class UThreadContextBoostInit { class UThreadContextBoost : public UThreadContext { public: - UThreadContextBoost(size_t stack_size, UThreadFunc_t func, void * args, UThreadDoneCallback_t callback); + UThreadContextBoost(size_t stack_size, UThreadFunc_t func, void * args, + UThreadDoneCallback_t callback, const bool need_stack_protect); ~UThreadContextBoost(); static UThreadContext * DoCreate(size_t stack_size, - UThreadFunc_t func, void * args, UThreadDoneCallback_t callback); + UThreadFunc_t func, void * args, UThreadDoneCallback_t callback, + const bool need_stack_protect); void Make(UThreadFunc_t func, void * args) override; bool Resume() override; @@ -54,9 +56,7 @@ class UThreadContextBoost : public UThreadContext { boost::context::fcontext_t context_; UThreadFunc_t func_; void * args_; - char * stack_; - size_t stack_size_; - int protect_page_; + UThreadStackMemory stack_; UThreadDoneCallback_t callback_; }; diff --git a/plugin_darwin/Makefile b/plugin_darwin/Makefile new file mode 100644 index 0000000..43092c9 --- /dev/null +++ b/plugin_darwin/Makefile @@ -0,0 +1,16 @@ + +include ../phxrpc.mk + +LIB_OBJS = network/epoll-darwin.o + +TARGETS = libphxrpc_plugin_darwin.a + +all: $(TARGETS) + +libphxrpc_plugin_darwin.a: $(LIB_OBJS) + $(AR) $@ $^ + mkdir -p $(PHXRPC_ROOT)/lib; cp $@ $(PHXRPC_ROOT)/lib + +clean: + @( $(RM) $(TARGETS) ) + @( $(RM) *.o core.* $(LIB_OBJS) ) diff --git a/plugin_darwin/network/epoll-darwin.cpp b/plugin_darwin/network/epoll-darwin.cpp new file mode 100644 index 0000000..258bce7 --- /dev/null +++ b/plugin_darwin/network/epoll-darwin.cpp @@ -0,0 +1,84 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#include "epoll-darwin.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +int epoll_create(int size) +{ + return kqueue(); +} + +int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + struct kevent kev; + if (op == EPOLL_CTL_ADD) { + if (event->events == EPOLLIN) { + EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, event->data.ptr); + } else { + EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, event->data.ptr); + } + } else if (op == EPOLL_CTL_DEL) { + if (event->events == EPOLLIN) { + EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + } else { + EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); + } + } else { + errno = EINVAL; + return -1; + } + + return kevent(epfd, &kev, 1, NULL, 0, NULL); +} + +int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) +{ + struct kevent * evlist = (struct kevent*)malloc(sizeof(struct kevent)*maxevents); + + struct timespec to = {0, 0}; + if (timeout > 0) { + to.tv_sec = timeout / 1000; + to.tv_nsec = (timeout % 1000) * 1000 * 1000; + } + + int ret = kevent(epfd, NULL, 0, evlist, maxevents, timeout == -1 ? NULL : &to); + if (ret > 0) { + for (int i = 0; i < ret; ++i) { + events[i].events = ( evlist[i].filter == EVFILT_READ ) ? EPOLLIN : EPOLLOUT; + events[i].data.ptr = evlist[i].udata; + } + } + + free( evlist ); + + return ret; +} + diff --git a/plugin_darwin/network/epoll-darwin.h b/plugin_darwin/network/epoll-darwin.h new file mode 100644 index 0000000..38e8fa9 --- /dev/null +++ b/plugin_darwin/network/epoll-darwin.h @@ -0,0 +1,60 @@ +/* +Tencent is pleased to support the open source community by making +PhxRPC available. +Copyright (C) 2016 THL A29 Limited, a Tencent company. +All rights reserved. + +Licensed under the BSD 3-Clause License (the "License"); you may +not use this file except in compliance with the License. You may +obtain a copy of the License at + +https://opensource.org/licenses/BSD-3-Clause + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +See the AUTHORS file for names of contributors. +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define EPOLLIN 0x001 +#define EPOLLOUT 0x004 +#define EPOLLERR 0x008 +#define EPOLLHUP 0x010 + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 + +typedef union epoll_data { + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; +} epoll_data_t; + +struct epoll_event { + uint32_t events; + epoll_data_t data; +}; + +int epoll_create(int); +int epoll_ctl(int, int, int, struct epoll_event *); +int epoll_wait(int, struct epoll_event *, int, int); + +#ifdef __cplusplus +} +#endif + diff --git a/sample/regen.sh b/sample/regen.sh index a1aa26b..9909cbd 100755 --- a/sample/regen.sh +++ b/sample/regen.sh @@ -2,6 +2,6 @@ test -f Makefile && make clean rm -f *.h *.cc *.cpp Makefile *.conf -../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d . +../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d . -u diff --git a/sample/search.proto b/sample/search.proto index e6e01ce..4300787 100644 --- a/sample/search.proto +++ b/sample/search.proto @@ -1,4 +1,4 @@ -syntax = "proto2"; +syntax = "proto3"; package search; @@ -14,31 +14,35 @@ enum SiteType { VIDEO = 2; UNKNOWN = 3; } + message Site { - required string url = 1; - required string title = 2; - required SiteType type = 3; - optional string summary = 4; + string url = 1; + string title = 2; + SiteType type = 3; + string summary = 4; } message SearchRequest { - required string query = 1; + string query = 1; } + message SearchResult { repeated Site sites = 1; } -service Search{ - rpc Search( SearchRequest ) returns( SearchResult ) { - option( phxrpc.CmdID ) = 1; - option( phxrpc.OptString ) = "q:"; - option( phxrpc.Usage ) = "-q "; +service Search { + + rpc Search(SearchRequest) returns (SearchResult) { + option(phxrpc.CmdID) = 1; + option(phxrpc.OptString) = "q:"; + option(phxrpc.Usage) = "-q "; } - rpc Notify( google.protobuf.StringValue ) returns( google.protobuf.Empty ) { - option( phxrpc.CmdID ) = 2; - option( phxrpc.OptString ) = "m:"; - option( phxrpc.Usage ) = "-m "; + rpc Notify(google.protobuf.StringValue) returns (google.protobuf.Empty) { + option(phxrpc.CmdID) = 2; + option(phxrpc.OptString) = "m:"; + option(phxrpc.Usage) = "-m "; } + }