diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..107caae --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.o +*.a +*.pb.* +*_dispatcher.* +!base_dispatcher.* +!http_dispatcher.* +!mqtt_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..26c5175 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,35 @@ **PhxRPC是微信后台团队推出的一个非常简洁小巧的RPC框架,编译生成的库只有450K。** -作者: Sifan Liu (stephenliu@tencent.com), Haochuan Cui (lynncui@tencent.com) 和 Duokai Huang (mariohuang@tencent.com) +作者: 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 网卡:千兆网卡 @@ -28,6 +40,7 @@ Worker线程数:20 ### 性能测试结果(qps) + #### 短连接 | ucontext类型/IO线程 | 1 | 3 | 8 | 20 | @@ -42,29 +55,37 @@ | system | 55k | 160k | 360k | 500k | | boost | 62k | 175k | 410k | 500k | -# 如何编译 -#### 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及以上版本.(可选) -#### 编译安装方法 +### 编译安装方法 + 进入PhxRPC根目录。 make (默认是-O2编译,如需编译debug版,执行 make debug=y) - make boost (可选,编译PhxRPC的boost优化插件,编译之前先准备放置好boost库) - -# 如何使用 -#### 编写proto文件 + 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 +97,172 @@ 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 . +../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d . -u + +两种生成模式,区别在于`-u`参数。 + +第一种生成默认的线程池worker模型。 + +第二种`-u`参数指定生成uthread worker模型,也就是工作线程池里面每个线程里面运行着多个协程。 调用完工具后,在生成代码放置目录下执行make,即可生成全部的RPC相关代码。 + +`-p mqtt`可生成支持MQTT协议的代码。 ``` -#### 选择是否启用boost优化 +### 选择是否启用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) +### 补充自己的代码 + +#### 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(); @@ -213,20 +282,22 @@ int SearchClient :: PhxBatchEcho( const google::protobuf::StringValue & req, 当然你可以借用这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/client_code_render.cpp b/codegen/client_code_render.cpp index 921784c..1dcb025 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 SyntaxFuncVector &mqtt_funcs, + FILE *write) { + char filename[128]{0}; name_render_.GetStubFileName(stree->GetName(), filename, sizeof(filename)); string buffer; @@ -60,41 +63,52 @@ 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 }; + char clasname[128]{0}; name_render_.GetStubClasname(stree->GetName(), clasname, sizeof(clasname)); { - 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", clasname); + fprintf(write, " public:\n"); + fprintf(write, " %s(phxrpc::BaseTcpStream &socket, phxrpc::ClientMonitor &client_monitor);\n", clasname); + fprintf(write, " virtual ~%s();\n", clasname); 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 (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + string buffer; + GetStubFuncDeclaration(stree, &(*mqtt_it), 1, &buffer); + fprintf(write, " %s;\n", buffer.c_str()); + } - std::string buffer; + 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 +117,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(SyntaxTree *stree, + const SyntaxFunc *const func, + int is_header, string *result) { + char clasname[128]{0}, type_name[128]{0}; name_render_.GetStubClasname(stree->GetName(), clasname, sizeof(clasname)); 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(", clasname, func->GetName()); } name_render_.GetMessageClasname(func->GetReq()->GetType(), type_name, sizeof(type_name)); - phxrpc::StrAppendFormat(result, "const %s & req,\n", 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_.GetMessageClasname(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 SyntaxFuncVector &mqtt_funcs, 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); @@ -146,61 +165,87 @@ void ClientCodeRender::GenerateStubCpp(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"); - char clasname[128] = { 0 }; + char clasname[128]{0}; name_render_.GetStubClasname(stree->GetName(), clasname, sizeof(clasname)); { - fprintf(write, "%s :: %s( phxrpc::BaseTcpStream & socket, phxrpc::ClientMonitor & client_monitor )\n", + fprintf(write, "%s::%s(phxrpc::BaseTcpStream &socket, phxrpc::ClientMonitor &client_monitor)\n", clasname, clasname); - 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", clasname, clasname); 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", clasname ); 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) { + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + GenerateMqttStubFunc(stree, &(*mqtt_it), write); + } + + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { GenerateStubFunc(stree, &(*fit), write); } + } } -void ClientCodeRender::GenerateStubFunc(SyntaxTree * stree, SyntaxFunc * func, FILE * write) { - std::string buffer; +void ClientCodeRender::GenerateMqttStubFunc(SyntaxTree *stree, const SyntaxFunc *const func, + FILE *write) { + string buffer; GetStubFuncDeclaration(stree, func, 0, &buffer); - fprintf(write, "%s\n", buffer.c_str()); + 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::MqttCaller caller(socket_, client_monitor_);\n"); + fprintf(write, " caller.SetCmdId(%d);\n", func->GetCmdID()); + if (0 == strcmp(func->GetName(), "PhxMqttDisconnect")) { + fprintf(write, " return caller.%sCall(req);\n", func->GetName()); + } else { + fprintf(write, " return caller.%sCall(req, resp);\n", func->GetName()); + } fprintf(write, "}\n"); fprintf(write, "\n"); } -void ClientCodeRender::GenerateClientHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ClientCodeRender::GenerateStubFunc(SyntaxTree *stree, const SyntaxFunc *const func, + FILE *write) { + string buffer; + + GetStubFuncDeclaration(stree, func, 0, &buffer); + + fprintf(write, "%s {\n", buffer.c_str()); + + 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, "}\n"); + fprintf(write, "\n"); +} + +void ClientCodeRender::GenerateClientHpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + 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 +257,90 @@ void ClientCodeRender::GenerateClientHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); - std::string declarations; + string declarations; + { - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; - GetClienfuncDeclaration(stree, &(*fit), 1, &buffer); + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + string buffer; + GetClienfuncDeclaration(stree, &(*mqtt_it), 1, &buffer, is_uthread_mode); - declarations.append(" ").append(buffer).append(";\n\n"); + declarations.append(" ").append(buffer).append(";\n"); + } + } + + { + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { + string buffer; + GetClienfuncDeclaration(stree, &(*fit), 1, &buffer, is_uthread_mode); - if (strcmp(fit->GetName(), "PHXEcho") == 0) { + 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 }; + 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)); name_render_.GetMessageFileName(stree->GetProtoFile(), message_file, sizeof(message_file)); - std::string content(PHXRPC_CLIENT_HPP_TEMPLATE); + 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 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 }; +void ClientCodeRender::GenerateClientCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, 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_.GetClientClasname(stree->GetName(), client_class, sizeof(client_class)); name_render_.GetClientClasnameLower(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_.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 +349,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 (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + string buffer; + GetClienfuncDeclaration(stree, &(*mqtt_it), 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(mqtt_it->GetName()); + const char *const resp_type{mqtt_it->GetResp()->GetType()}; + if (resp_type && 0 < strlen(resp_type)) { + func_string += "(req, resp)"; + } else { + func_string += "(req)"; + } + StrReplaceAll(&content, "$Func$", func_string); + + functions.append(content).append("\n\n"); + } + } - std::string content = PHXRPC_CLIENT_FUNC_TEMPLATE; + { + 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, "$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 clasname[128]{0}, type_name[128]{0}; name_render_.GetClientClasname(stree->GetName(), clasname, sizeof(clasname)); + string clasname_str = string(clasname); + if (is_uthread_mode) { + clasname_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(", clasname_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); + 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_.GetMessageClasname(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 +493,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() ); 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..8af144c 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 + 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 SyntaxFuncVector &mqtt_funcs, + FILE *write); - void GenerateStubCpp(SyntaxTree * stree, FILE * write); + void GenerateStubCpp(SyntaxTree *stree, const SyntaxFuncVector &mqtt_funcs, + FILE *write); - void GenerateClientHpp(SyntaxTree * stree, FILE * write); + void GenerateClientHpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write, const bool is_uthread_mode); - void GenerateClientCpp(SyntaxTree * stree, FILE * write); + void GenerateClientCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write, const bool is_uthread_mode); - void GenerateClientEtc(SyntaxTree * stree, FILE * write); + void GenerateClientEtc(SyntaxTree *stree, FILE *write); - private: + private: + void GetStubFuncDeclaration(SyntaxTree *stree, const SyntaxFunc *const func, + int is_header, std::string *result); - void GetStubFuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, std::string * result); + void GenerateMqttStubFunc(SyntaxTree *stree, const SyntaxFunc *const func, + FILE *write); - void GenerateStubFunc(SyntaxTree * stree, SyntaxFunc * func, FILE * write); + void GenerateStubFunc(SyntaxTree *stree, const SyntaxFunc *const func, + FILE *write); - void GetClienfuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, std::string * result); + void GetClienfuncDeclaration(SyntaxTree *stree, + const SyntaxFunc *const func, + int is_header, std::string *result, + const bool is_uthread_mode); - private: - NameRender & name_render_; + NameRender &name_render_; }; + } diff --git a/codegen/client_template.cpp b/codegen/client_template.cpp index c7f575a..56a6926 100644 --- a/codegen/client_template.cpp +++ b/codegen/client_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. @@ -25,16 +25,15 @@ const char * PHXRPC_CLIENT_HPP_TEMPLATE = #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$ }; @@ -43,51 +42,130 @@ class $ClientClass$ ////////////////////////////////////////////////////////////////////// +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 = R"( +#include "$ClientFile$.h" + +#include #include #include -#include #include -#include "$ClientFile$.h" #include "$StubFile$.h" #include "phxrpc/rpc.h" + 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$"; } return ret; } -$ClientClass$ :: $ClientClass$() -{ +$ClientClass$::$ClientClass$() { static std::mutex monitor_mutex; - if ( !global_$ClientClassLower$_monitor_.get() ) { + if (!global_$ClientClassLower$_monitor_.get()) { monitor_mutex.lock(); - if ( !global_$ClientClassLower$_monitor_.get() ) { + if (!global_$ClientClassLower$_monitor_.get()) { global_$ClientClassLower$_monitor_ = phxrpc::MonitorFactory::GetFactory() - ->CreateClientMonitor( GetPackageName() ); + ->CreateClientMonitor(GetPackageName()); } - global_$ClientClassLower$_config_.SetClientMonitor( global_$ClientClassLower$_monitor_ ); + global_$ClientClassLower$_config_.SetClientMonitor(global_$ClientClassLower$_monitor_); monitor_mutex.unlock(); } } -$ClientClass$ :: ~$ClientClass$() -{ +$ClientClass$::~$ClientClass$() { +} + +$ClientClassFuncs$ +)"; + +////////////////////////////////////////////////////////////////////// + +const char * PHXRPC_UTHREAD_CLIENT_CPP_TEMPLATE = + R"( + +#include "$ClientFile$_uthread.h" + +#include +#include +#include +#include + +#include "$StubFile$.h" + +#include "phxrpc/rpc.h" + + +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 = "$PackageName$"; + } + return ret; +} + +$ClientClass$::$ClientClass$(phxrpc::UThreadEpollScheduler *uthread_scheduler) { + uthread_scheduler_ = uthread_scheduler; + static std::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$ @@ -98,19 +176,43 @@ const char * $ClientClass$ :: GetPackageName() { 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 != nullptr) { + if (ep != nullptr) { phxrpc::BlockTcpStream socket; bool open_ret = phxrpc::PhxrpcTcpUtils::Open(&socket, ep->ip, ep->port, - global_$ClientClassLower$_config_.GetConnectTimeoutMS(), NULL, 0, + 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_CLIENT_FUNC_TEMPLATE = + R"( +{ + const phxrpc::Endpoint_t *ep = global_$ClientClassLower$_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_$ClientClassLower$_config_.GetConnectTimeoutMS(), *(global_$ClientClassLower$_monitor_.get())); - if ( open_ret ) { + 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; @@ -122,27 +224,27 @@ const char * PHXRPC_CLIENT_FUNC_TEMPLATE = const char * PHXRPC_BATCH_CLIENT_FUNC_TEMPLATE = R"( { - int ret = -1; + 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; } diff --git a/codegen/client_template.h b/codegen/client_template.h index 5f7e36b..0d6c1c7 100644 --- a/codegen/client_template.h +++ b/codegen/client_template.h @@ -22,7 +22,13 @@ 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_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..83ed7e6 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, ...) { } } + } 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..7540788 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::GetMessageClasname(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,13 @@ char * NameRender::ToUpper(register char *s) { return ret; } -const char * NameRender::GetStubClasname(const char * name, char *dest, int size) { +const char *NameRender::GetStubClasname(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::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 +106,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::GetClientClasname(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::GetClientClasnameLower(const char *name, char *dest, int size) { snprintf(dest, size, "%s%c%sClient", prefix_, toupper(*name), name + 1); ToLower(dest); @@ -118,7 +120,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 +128,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 +136,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::GetServerConfigClasname(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 +149,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 +157,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 +165,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::GetToolClasname(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 +179,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::GetToolImplClasname(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 +193,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 +201,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::GetServiceClasname(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 +232,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::GetServiceImplClasname(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 +246,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::GetDispatcherClasname(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..6c53518 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,80 @@ 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 *GetMessageClasname(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 *GetStubClasname(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 *GetClientClasname(const char *name, char *dest, int size); - virtual const char * GetClientClasnameLower(const char * name, char *dest, int size); + virtual const char *GetClientClasnameLower(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 *GetServiceClasname(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 *GetServiceImplClasname(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 *GetDispatcherClasname(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 *GetServerConfigClasname(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 *GetToolClasname(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 *GetToolImplClasname(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..018a9e8 100644 --- a/codegen/phxrpc_pb2client.cpp +++ b/codegen/phxrpc_pb2client.cpp @@ -1,29 +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" @@ -32,46 +33,78 @@ 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 *proto_file, + const char *dir_path, const vector &include_list, + const bool is_uthread_mode, const bool mqtt) { SyntaxTree syntax_tree; - int ret = ProtoUtils::Parse(proto_file, &syntax_tree, include_list); + int ret{ProtoUtils::Parse(proto_file, &syntax_tree, include_list)}; if (0 != ret) { printf("parse Proto file fail, please check error log\n"); return; } + // mqtt + SyntaxFuncVector mqtt_funcs; + + if (mqtt) { + SyntaxFunc connect_func; + connect_func.SetCmdID(-201); + connect_func.SetName("PhxMqttConnect"); + connect_func.GetReq()->SetType("phxrpc::MqttConnectPb"); + connect_func.GetResp()->SetType("phxrpc::MqttConnackPb"); + mqtt_funcs.push_back(connect_func); + + SyntaxFunc publish_func; + publish_func.SetCmdID(-202); + publish_func.SetName("PhxMqttPublish"); + publish_func.SetOptString("s:"); + publish_func.SetUsage("-s "); + publish_func.GetReq()->SetType("phxrpc::MqttPublishPb"); + publish_func.GetResp()->SetType("phxrpc::MqttPubackPb"); + mqtt_funcs.push_back(publish_func); + + SyntaxFunc disconnect_func; + disconnect_func.SetCmdID(-207); + disconnect_func.SetName("PhxMqttDisconnect"); + disconnect_func.GetReq()->SetType("phxrpc::MqttDisconnectPb"); + disconnect_func.GetResp()->SetType(""); + mqtt_funcs.push_back(disconnect_func); + } + 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, mqtt_funcs, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -82,25 +115,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, mqtt_funcs, 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, mqtt_funcs, 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, mqtt_funcs, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -118,8 +176,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, mqtt_funcs, 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, mqtt_funcs, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -134,28 +209,30 @@ 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 *proto_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}; + bool mqtt{false}; - while ((c = getopt(argc, argv, "f:d:I:v")) != EOF) { + while (EOF != (c = getopt(argc, argv, "f:d:I:p:uv"))) { switch (c) { case 'f': proto_file = optarg; @@ -169,6 +246,13 @@ int main(int argc, char * argv[]) { include_list.push_back(rp); } break; + case 'p': + if (0 == strcasecmp(optarg, "mqtt")) + mqtt = true; + break; + case 'u': + is_uthread_mode = true; + break; default: PrintHelp(argv[0]); exit(-1); @@ -176,7 +260,7 @@ int main(int argc, char * argv[]) { } } - if (NULL == proto_file || NULL == dir_path) { + if (nullptr == proto_file || nullptr == dir_path) { printf("Invalid arguments\n"); PrintHelp(argv[0]); @@ -189,13 +273,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], proto_file, path, include_list, is_uthread_mode, mqtt); printf("\n"); diff --git a/codegen/phxrpc_pb2server.cpp b/codegen/phxrpc_pb2server.cpp index 53430bf..908c6f8 100644 --- a/codegen/phxrpc_pb2server.cpp +++ b/codegen/phxrpc_pb2server.cpp @@ -1,33 +1,33 @@ /* -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 +35,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 +55,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 +69,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 +79,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 +95,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 +111,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 +127,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 +142,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 +178,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 +188,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 +201,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..dc89a97 100644 --- a/codegen/phxrpc_pb2service.cpp +++ b/codegen/phxrpc_pb2service.cpp @@ -1,30 +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 @@ -34,48 +35,83 @@ 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 bool mqtt) { + map parsed_file_map; SyntaxTree syntax_tree; - 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"); return; } - // printf( "parse(%s) = %d\n", pb_file, ret ); + // printf("parse(%s) = %d\n", pb_file, ret); + + // mqtt + SyntaxFuncVector mqtt_funcs; + + if (mqtt) { + SyntaxFunc connect_func; + connect_func.SetCmdID(-201); + connect_func.SetName("PhxMqttConnect"); + connect_func.GetReq()->SetType("phxrpc::MqttConnectPb"); + connect_func.GetResp()->SetType("phxrpc::MqttConnackPb"); + mqtt_funcs.push_back(connect_func); + + SyntaxFunc publish_func; + publish_func.SetCmdID(-202); + publish_func.SetName("PhxMqttPublish"); + publish_func.SetOptString("s:"); + publish_func.SetUsage("-s "); + publish_func.GetReq()->SetType("phxrpc::MqttPublishPb"); + publish_func.GetResp()->SetType("phxrpc::MqttPubackPb"); + mqtt_funcs.push_back(publish_func); + + SyntaxFunc disconnect_func; + disconnect_func.SetCmdID(-207); + disconnect_func.SetName("PhxMqttDisconnect"); + disconnect_func.GetReq()->SetType("phxrpc::MqttDisconnectPb"); + disconnect_func.GetResp()->SetType(""); + mqtt_funcs.push_back(disconnect_func); + } 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, mqtt_funcs, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -85,9 +121,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, mqtt_funcs, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -99,9 +135,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, mqtt_funcs, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -116,9 +152,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, mqtt_funcs, fp, is_uthread_mode); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -132,9 +168,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, mqtt_funcs, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -145,26 +181,28 @@ 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, mqtt_funcs, 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; + vector include_list; + char real_path[1024]{0}; + char *rp{nullptr}; + bool is_uthread_mode{false}; + bool mqtt{false}; - while ((c = getopt(argc, argv, "f:d:I:v")) != EOF) { + while (EOF != (c = getopt(argc, argv, "f:d:I:p:uv"))) { switch (c) { case 'f': pb_file = optarg; @@ -178,6 +216,13 @@ int main(int argc, char * argv[]) { include_list.push_back(rp); } break; + case 'p': + if (0 == strcasecmp(optarg, "mqtt")) + mqtt = true; + break; + case 'u': + is_uthread_mode = true; + break; default: PrintHelp(argv[0]); exit(-1); @@ -185,7 +230,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 +244,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, mqtt); printf("\n"); diff --git a/codegen/phxrpc_pb2tool.cpp b/codegen/phxrpc_pb2tool.cpp index e6e8438..59a0df4 100644 --- a/codegen/phxrpc_pb2tool.cpp +++ b/codegen/phxrpc_pb2tool.cpp @@ -1,30 +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,24 +34,28 @@ 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 bool mqtt) { SyntaxTree syntax_tree; int ret = ProtoUtils::Parse(pb_file, &syntax_tree, include_list); @@ -62,18 +67,46 @@ void Proto2Tool(const char * program, const char * pb_file, const char * dir_pat // printf( "parse(%s) = %d\n", pb_file, ret ); + // mqtt + SyntaxFuncVector mqtt_funcs; + + if (mqtt) { + SyntaxFunc connect_func; + connect_func.SetCmdID(-201); + connect_func.SetName("PhxMqttConnect"); + connect_func.GetReq()->SetType("phxrpc::MqttConnectPb"); + connect_func.GetResp()->SetType("phxrpc::MqttConnackPb"); + mqtt_funcs.push_back(connect_func); + + SyntaxFunc publish_func; + publish_func.SetCmdID(-202); + publish_func.SetName("PhxMqttPublish"); + publish_func.SetOptString("s:"); + publish_func.SetUsage("-s "); + publish_func.GetReq()->SetType("phxrpc::MqttPublishPb"); + publish_func.GetResp()->SetType("phxrpc::MqttPubackPb"); + mqtt_funcs.push_back(publish_func); + + SyntaxFunc disconnect_func; + disconnect_func.SetCmdID(-207); + disconnect_func.SetName("PhxMqttDisconnect"); + disconnect_func.GetReq()->SetType("phxrpc::MqttDisconnectPb"); + disconnect_func.GetResp()->SetType(""); + mqtt_funcs.push_back(disconnect_func); + } + 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, mqtt_funcs, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -84,9 +117,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, mqtt_funcs, fp); fclose(fp); printf("\n%s: Build %s file ... done\n", program, filename); @@ -98,14 +131,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, mqtt_funcs, 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 +148,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, mqtt_funcs, 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 +165,30 @@ 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; + vector include_list; + char real_path[1024]{0}; + char *rp{nullptr}; + bool mqtt{false}; - while ((c = getopt(argc, argv, "f:d:I:v")) != EOF) { + while (EOF != (c = getopt(argc, argv, "f:d:I:p:v"))) { switch (c) { case 'f': pb_file = optarg; @@ -168,6 +202,10 @@ int main(int argc, char * argv[]) { include_list.push_back(rp); } break; + case 'p': + if (0 == strcasecmp(optarg, "mqtt")) + mqtt = true; + break; default: PrintHelp(argv[0]); exit(-1); @@ -175,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]); @@ -188,13 +226,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, mqtt); printf("\n"); diff --git a/codegen/proto_utils.cpp b/codegen/proto_utils.cpp index 53fb379..75b6547 100644 --- a/codegen/proto_utils.cpp +++ b/codegen/proto_utils.cpp @@ -1,43 +1,45 @@ /* -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) { @@ -166,7 +168,7 @@ int ProtoUtils::AddEcho(SyntaxTree * stree) { // always add a echo function { SyntaxFunc echo_func; - echo_func.SetName("PHXEcho"); + echo_func.SetName("PhxEcho"); echo_func.GetReq()->SetName("request"); echo_func.GetReq()->SetType(name); echo_func.GetResp()->SetName("response"); diff --git a/codegen/proto_utils.h b/codegen/proto_utils.h index 8cc46d5..77614d3 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,20 +24,24 @@ 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: + 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: + private: static int LoadNormal(const char * file, phxrpc::SyntaxTree * stree, std::map * parsed_file_map, google::protobuf::compiler::DiskSourceTree & tree); @@ -47,11 +51,10 @@ class ProtoUtils { static int AddEcho(phxrpc::SyntaxTree * stree); - private: ProtoUtils(); - ~ProtoUtils(); + virtual ~ProtoUtils(); }; + } -; diff --git a/codegen/server_code_render.cpp b/codegen/server_code_render.cpp index af8523d..76448dc 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); @@ -55,7 +58,7 @@ void ServerCodeRender::GenerateServerConfigHpp(SyntaxTree * stree, FILE * write) char classname[128] = { 0 }; name_render_.GetServerConfigClasname(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,22 +81,22 @@ void ServerCodeRender::GenerateServerConfigCpp(SyntaxTree * stree, FILE * write) fprintf(write, "*/\n"); fprintf(write, "\n"); - char classname[128] = { 0 }; - char message_file[128] = {0}; + char classname[128]{0}; + char message_file[128]{0}; name_render_.GetServerConfigClasname(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 = "\"" + string(stree->GetPackageName()) + "\""; { - std::string message_name = ""; + string message_name; for( auto itr : *(stree->GetFuncList()) ) { - if ( std::string(itr.GetReq()->GetType()).find( stree->GetPackageName() ) != std::string::npos ) { + if ( string(itr.GetReq()->GetType()).find( stree->GetPackageName() ) != 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->GetPackageName() ) != string::npos ) { message_name = itr.GetResp()->GetType(); break; } @@ -100,7 +104,7 @@ void ServerCodeRender::GenerateServerConfigCpp(SyntaxTree * stree, FILE * write) 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 + package_name = "\n" + string(stree->GetPackageName()) + "::" + message_name + "::default_instance().GetDescriptor()->file()->package().c_str()"; } } @@ -114,13 +118,14 @@ void ServerCodeRender::GenerateServerConfigCpp(SyntaxTree * stree, FILE * write) 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,9 +133,9 @@ 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_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}; name_render_.GetDispatcherClasname(stree->GetName(), dispatcher_calss, sizeof(dispatcher_calss)); name_render_.GetDispatcherFileName(stree->GetName(), dispatcher_file, sizeof(dispatcher_file)); @@ -139,7 +144,12 @@ void ServerCodeRender::GenerateServerMainCpp(SyntaxTree * stree, FILE * write) { name_render_.GetServerConfigClasname(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); @@ -152,13 +162,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,7 +177,12 @@ 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() ); @@ -174,10 +190,12 @@ void ServerCodeRender::GenerateServerEtc(SyntaxTree * stree, FILE * write) { 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 +203,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 +223,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..7973150 100644 --- a/codegen/server_template.cpp +++ b/codegen/server_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. @@ -26,71 +26,180 @@ const char * PHXRPC_EPOLL_SERVER_MAIN_TEMPLATE = #include #include #include + #include "$DispatcherFile$.h" #include "$ServiceImplFile$.h" #include "$ServerConfigFile$.h" #include "phxrpc/rpc.h" -#include "phxrpc/http.h" +#include "phxrpc/msg.h" #include "phxrpc/file.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); + $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$::GetMqttFuncMap(), + $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::HshaServer server(config.GetHshaServerConfig(), Dispatch, &service_args); + server.RunForever(); + + phxrpc::closelog(); + + return 0; +} + +)"; + +////////////////////////////////////////////////////////////////////// + +const char * PHXRPC_EPOLL_UTHREAD_SERVER_MAIN_TEMPLATE = + R"( + +#include +#include +#include +#include + +#include "$DispatcherFile$.h" +#include "$ServiceImplFile$.h" +#include "$ServerConfigFile$.h" + +#include "phxrpc/rpc.h" +#include "phxrpc/msg.h" +#include "phxrpc/file.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); + $DispatcherClass$ dispatcher(service, args); - exit( 0 ); + phxrpc::BaseDispatcher<$DispatcherClass$> base_dispatcher( + dispatcher, $DispatcherClass$::GetMqttFuncMap(), + $DispatcherClass$::GetURIFuncMap()); + if (!base_dispatcher.Dispatch(request, response)) { + response->DispatchErr(); + } } -void LogImpl(int priority, const char * format, va_list args) { - //or implement your logmode here +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 = NULL; - extern char *optarg ; - int c ; - while( ( c = getopt( argc, argv, "c:v" ) ) != EOF ) { - switch ( c ) { +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; + 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::HshaServer server(config.GetHshaServerConfig(), Dispatch, &service_args); server.RunForever(); + + phxrpc::closelog(); + return 0; } @@ -103,18 +212,18 @@ const char * PHXRPC_EPOLL_SERVER_CONFIG_HPP_TEMPLATE = #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_; }; @@ -125,30 +234,28 @@ class $ServerConfigClass$ 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($PackageName$); } return ret; } -const phxrpc::HshaServerConfig & $ServerConfigClass$ :: GetHshaServerConfig() -{ +phxrpc::HshaServerConfig &$ServerConfigClass$::GetHshaServerConfig() { return ep_server_config_; } @@ -168,6 +275,38 @@ PackageName = $PackageName$ MaxConnections = 800000 MaxQueueLength = 20480 FastRejectThresholdMS = 20 +FastRejectAdjustRate = 5 + +[Log] +LogDir = ~/log +LogLevel = 3 + +[ServerTimeout] +SocketTimeoutMS = 5000 + +)"; + +////////////////////////////////////////////////////////////////////// + +const char * PHXRPC_EPOLL_UTHREAD_SERVER_ETC_TEMPLATE = + R"( + +[Server] +BindIP = 127.0.0.1 +Port = 16161 +MaxThreads = 16 +WorkerUThreadCount = 50 +WorkerUThreadStackSize = 65536 +IOThreadCount = 3 +PackageName = $PackageName$ +MaxConnections = 800000 +MaxQueueLength = 20480 +FastRejectThresholdMS = 20 +FastRejectAdjustRate = 5 + +[Log] +LogDir = ~/log +LogLevel = 3 [ServerTimeout] SocketTimeoutMS = 5000 @@ -183,19 +322,105 @@ 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 + +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 #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 +440,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 +448,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 +464,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 +476,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..80f063f 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 SyntaxFuncVector &mqtt_funcs, + 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); @@ -56,25 +62,31 @@ void ServiceCodeRender::GenerateServiceHpp(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"); - char clasname[128] = { 0 }; + char clasname[128]{0}; name_render_.GetServiceClasname(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) { - std::string buffer; + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + string buffer; + GetServiceFuncDeclaration(stree, &(*mqtt_it), 1, 0, 1, &buffer); + fprintf(write, " virtual %s;\n", buffer.c_str()); + } + + 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 +94,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 SyntaxFuncVector &mqtt_funcs, + 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 +109,58 @@ 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 }; + char clasname[128]{0}; name_render_.GetServiceClasname(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"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::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()); + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + string buffer; + GetServiceFuncDeclaration(stree, &(*mqtt_it), 0, 0, 0, &buffer); + fprintf(write, "%s {\n", buffer.c_str()); + fprintf(write, " phxrpc::log(LOG_ERR, \"ERROR: %s unimplemented\");\n", mqtt_it->GetName()); fprintf(write, " return -1;\n"); fprintf(write, "}\n"); fprintf(write, "\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, " phxrpc::log(LOG_ERR, \"ERROR: %s unimplemented\");\n", fit->GetName()); + fprintf(write, " return -1;\n"); + fprintf(write, "}\n"); + fprintf(write, "\n"); + } } -void ServiceCodeRender::GenerateServiceImplHpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServiceCodeRender::GenerateServiceImplHpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + 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); @@ -152,53 +177,77 @@ void ServiceCodeRender::GenerateServiceImplHpp(SyntaxTree * stree, FILE * write) name_render_.GetServiceFileName(stree->GetName(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); + if (is_uthread_mode) { + fprintf(write, "#include \"phxrpc/network.h\"\n"); + } + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }, base_name[128] = { 0 }, config_name[128] = { 0 }; + 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)); fprintf(write, "class %s;\n", config_name); fprintf(write, "\n"); + fprintf(write, "\n"); fprintf(write, "typedef struct tagServiceArgs {\n"); - fprintf(write, " %s * config;\n", config_name); + 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, "} ServiceArgs_t;\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, "class %s : public %s {\n", clasname, base_name); + fprintf(write, " public:\n"); + if (!is_uthread_mode) { + fprintf(write, " %s(ServiceArgs_t &app_args);\n", clasname); + } else { + fprintf(write, " %s(ServiceArgs_t &app_args,\n", clasname); + fprintf(write, " phxrpc::UThreadEpollScheduler *worker_uthread_scheduler);\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) { - std::string buffer; + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + string buffer; + GetServiceFuncDeclaration(stree, &(*mqtt_it), 1, 1, 1, &buffer); + fprintf(write, " virtual %s override;\n", buffer.c_str()); + } + fprintf(write, "\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;\n", buffer.c_str()); - fprintf(write, "\n"); + 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, " private:\n"); + fprintf(write, " ServiceArgs_t &args_;\n" ); + if (is_uthread_mode) { + fprintf(write, " phxrpc::UThreadEpollScheduler *worker_uthread_scheduler_;\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 SyntaxFuncVector &mqtt_funcs, + 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,53 +256,78 @@ void ServiceCodeRender::GenerateServiceImplCpp(SyntaxTree * stree, FILE * write) fprintf(write, "\n"); fprintf(write, "#include \"%s.h\"\n", filename); + fprintf(write, "\n"); + 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, "#include \"phxrpc/file.h\"\n"); + fprintf(write, "\n"); fprintf(write, "\n"); - char clasname[128] = { 0 }, config_name[128] = { 0 }; + 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, "%s :: %s( ServiceArgs_t * app_args )\n", clasname, clasname); - fprintf(write, " : config_( *(app_args->config) )\n"); - fprintf(write, "{\n"); + if (!is_uthread_mode) { + fprintf(write, "%s::%s(ServiceArgs_t &app_args)\n", clasname, clasname); + fprintf(write, " : args_(app_args) {\n"); + } else { + fprintf(write, "%s::%s(ServiceArgs_t &app_args,\n", clasname, clasname); + fprintf(write, " phxrpc::UThreadEpollScheduler *worker_uthread_scheduler)\n", clasname, clasname); + fprintf(write, " : args_(app_args), worker_uthread_scheduler_(worker_uthread_scheduler) {\n"); + } 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"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - std::string buffer; + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + string buffer; + GetServiceFuncDeclaration(stree, &(*mqtt_it), 0, 1, 1, &buffer); + fprintf(write, "%s {\n", buffer.c_str()); + + if (0 == strcmp("PhxMqttPublish", mqtt_it->GetName())) { + fprintf(write, " // TODO: process req.content()\n"); + fprintf(write, "\n"); + fprintf(write, " return -1;\n"); + } else { + fprintf(write, " return 0;\n"); + } + + fprintf(write, "}\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 clasname[128]{0}, type_name[128]{0}; if (is_impl) { name_render_.GetServiceImplClasname(stree->GetName(), clasname, sizeof(clasname)); @@ -262,25 +336,30 @@ void ServiceCodeRender::GetServiceFuncDeclaration(SyntaxTree * stree, SyntaxFunc } 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(", clasname, 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 */"); + 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_.GetMessageClasname(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 SyntaxFuncVector &mqtt_funcs, + 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); @@ -295,41 +374,48 @@ void ServiceCodeRender::GenerateDispatcherHpp(SyntaxTree * stree, FILE * write) 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 }; + 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, "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", clasname); - 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>::MqttFuncMap &GetMqttFuncMap();\n", clasname); + fprintf(write, " static const phxrpc::BaseDispatcher<%s>::URIFuncMap &GetURIFuncMap();\n", clasname); fprintf(write, "\n"); - fprintf(write, " ~%s();\n", clasname); + fprintf(write, " %s(%s &service, phxrpc::DispatcherArgs_t *dispatcher_args);\n", clasname, 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, "\n"); + fprintf(write, " virtual ~%s();\n", clasname); + fprintf(write, "\n"); + + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + fprintf(write, " int %s(const phxrpc::BaseRequest *const req, " + "phxrpc::BaseResponse *const resp);\n", + mqtt_it->GetName()); } - fprintf(write, "private:\n"); - fprintf(write, " %s & service_;\n", service_name); - fprintf(write, " phxrpc::DispatcherArgs_t * dispatcher_args_;\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, " private:\n"); + fprintf(write, " %s &service_;\n", service_name); + fprintf(write, " phxrpc::DispatcherArgs_t *dispatcher_args_;\n" ); fprintf(write, "\n"); fprintf(write, "};\n"); @@ -337,11 +423,13 @@ void ServiceCodeRender::GenerateDispatcherHpp(SyntaxTree * stree, FILE * write) fprintf(write, "\n"); } -void ServiceCodeRender::GenerateDispatcherCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ServiceCodeRender::GenerateDispatcherCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + 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,6 +440,9 @@ void ServiceCodeRender::GenerateDispatcherCpp(SyntaxTree * stree, FILE * write) fprintf(write, "#include \"%s.h\"\n", filename); fprintf(write, "\n"); + fprintf(write, "#include \n"); + fprintf(write, "\n"); + name_render_.GetMessageFileName(stree->GetProtoFile(), filename, sizeof(filename)); fprintf(write, "#include \"%s.h\"\n", filename); @@ -360,52 +451,101 @@ void ServiceCodeRender::GenerateDispatcherCpp(SyntaxTree * stree, FILE * write) 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 }; + 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"); - - fprintf(write, "{\n"); + 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"); 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"); + vector functions; + + if (0 < mqtt_funcs.size()) { + FunctionItem connect_item; + connect_item.protocol_name = "MQTT_CONNECT"; + connect_item.function_name = "PhxMqttConnect"; + functions.push_back(connect_item); + + FunctionItem publish_item; + publish_item.protocol_name = "MQTT_PUBLISH"; + publish_item.function_name = "PhxMqttPublish"; + functions.push_back(publish_item); + + FunctionItem disconnect_item; + disconnect_item.protocol_name = "MQTT_DISCONNECT"; + disconnect_item.function_name = "PhxMqttDisconnect"; + functions.push_back(disconnect_item); + } + + GenerateMqttFuncMap(stree, functions, write); + + fprintf(write, "\n"); + GenerateURIFuncMap(stree, write); fprintf(write, "\n"); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + GenerateMqttDispatcherFunc(stree, &(*mqtt_it), write); + } + + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { GenerateDispatcherFunc(stree, &(*fit), write); } +} - fprintf(write, "\n"); +void ServiceCodeRender::GenerateMqttFuncMap(SyntaxTree *stree, + const vector functions, + FILE *write) { + char clasname[128]{0}; + name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); + + fprintf(write, "const phxrpc::BaseDispatcher<%s>::MqttFuncMap &%s::GetMqttFuncMap() {\n", + clasname, clasname); + + fprintf(write, " static phxrpc::BaseDispatcher<%s>::MqttFuncMap mqtt_func_map = {\n", + clasname); + + for (auto it(functions.cbegin()); functions.cend() != it; ++it) { + if (it != functions.cbegin()) { + fprintf(write, ",\n"); + } + fprintf(write, " {phxrpc::BaseMessage::Protocol::%s, &%s::%s}", + it->protocol_name.c_str(), clasname, + it->function_name.c_str()); + } + fprintf(write, "};\n"); + + fprintf(write, " return mqtt_func_map;\n"); + + fprintf(write, "}\n"); } -void ServiceCodeRender::GenerateURIFuncMap(SyntaxTree * stree, FILE * write) { - char clasname[128] = { 0 }; +void ServiceCodeRender::GenerateURIFuncMap(SyntaxTree *stree, FILE *write) { + char clasname[128]{0}; name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); - 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", clasname, clasname); - fprintf(write, " static phxrpc::HttpDispatcher< %s >::URIFuncMap uri_func_map = {\n", clasname); + fprintf(write, " static phxrpc::BaseDispatcher<%s>::URIFuncMap uri_func_map = {\n", clasname); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { - if (fit != flist->begin()) { + 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}", stree->GetPackageName(), fit->GetName(), clasname, @@ -418,66 +558,130 @@ 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::GenerateMqttDispatcherFunc(SyntaxTree *stree, + const SyntaxFunc *const func, + FILE *write) { + char clasname[128]{0}, type_name[128]{0}; + + name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); + + fprintf(write, "int %s::%s(const phxrpc::BaseRequest *const req, " + "phxrpc::BaseResponse *const resp) {\n", + clasname, 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, "\n"); + name_render_.GetMessageClasname(func->GetReq()->GetType(), type_name, sizeof(type_name)); + fprintf(write, " %s req_pb;\n", type_name); + bool has_resp{func->GetResp()->GetType() && 0 < strlen(func->GetResp()->GetType())}; + if (has_resp) { + name_render_.GetMessageClasname(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, " {\n"); + 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, "\n"); + fprintf(write, " return -EINVAL;\n"); + fprintf(write, " }\n"); + fprintf(write, " }\n"); + fprintf(write, "\n"); + fprintf(write, " // logic process\n"); + fprintf(write, " {\n"); + fprintf(write, " if (0 == ret) {\n"); + if (has_resp) { + fprintf(write, " ret = service_.%s(req_pb, &resp_pb);\n", func->GetName()); + } else { + fprintf(write, " ret = service_.%s(req_pb);\n", func->GetName()); + } + fprintf(write, " }\n"); + fprintf(write, " }\n"); + fprintf(write, "\n"); + if (has_resp) { + fprintf(write, " // pack response\n"); + fprintf(write, " {\n"); + 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, "\n"); + fprintf(write, " return -ENOMEM;\n"); + fprintf(write, " }\n"); + fprintf(write, " }\n"); + fprintf(write, "\n"); + } + fprintf(write, " phxrpc::log(LOG_DEBUG, \"ret %%d\", ret);\n"); + fprintf(write, "\n"); + fprintf(write, " return ret;\n"); + fprintf(write, "}\n"); + + fprintf(write, "\n"); +} + +void ServiceCodeRender::GenerateDispatcherFunc(SyntaxTree *stree, + const SyntaxFunc *const func, + FILE *write) { + char clasname[128]{0}, type_name[128]{0}; name_render_.GetDispatcherClasname(stree->GetName(), clasname, sizeof(clasname)); - fprintf(write, "int %s :: %s( const phxrpc::HttpRequest & request, " - "phxrpc::HttpResponse * response )\n", + fprintf(write, "int %s::%s(const phxrpc::BaseRequest *const req, " + "phxrpc::BaseResponse *const resp) {\n", clasname, 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); + 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); + 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, " if (!req_pb.ParseFromString(req->GetContent())) {\n"); - fprintf(write, " phxrpc::log( LOG_ERR, \"ERROR: FromBuffer fail size %%zu ip %%s\",\n" - " request.GetContent().size(), request.GetClientIP() );\n"); + fprintf(write, " phxrpc::log(LOG_ERR, \"ERROR: FromBuffer fail size %%zu ip %%s\",\n" + " req->GetContent().size(), req->GetClientIP());\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, " if (!resp_pb.SerializeToString(&(resp->GetContent()))) {\n"); - fprintf(write, " phxrpc::log( LOG_ERR, \"ERROR: ToBuffer fail ip %%s\", request.GetClientIP() );\n"); + fprintf(write, " phxrpc::log(LOG_ERR, \"ERROR: ToBuffer fail ip %%s\", req->GetClientIP());\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..9e389d6 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,76 @@ 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 SyntaxFuncVector &mqtt_funcs, + FILE *write); + + virtual void GenerateServiceCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write); - virtual void GenerateServiceCpp(SyntaxTree * stree, FILE * write); + virtual void GenerateServiceImplHpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write, const bool is_uthread_mode); - virtual void GenerateServiceImplHpp(SyntaxTree * stree, FILE * write); + virtual void GenerateServiceImplCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write, const bool is_uthread_mode); - virtual void GenerateServiceImplCpp(SyntaxTree * stree, FILE * write); + virtual void GenerateDispatcherHpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write); - virtual void GenerateDispatcherHpp(SyntaxTree * stree, FILE * write); + virtual void GenerateDispatcherCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write); - virtual void GenerateDispatcherCpp(SyntaxTree * stree, FILE * write); + protected: + struct FunctionItem { + std::string protocol_name; + std::string function_name; + }; - protected: + virtual void GetServiceFuncDeclaration(SyntaxTree *stree, + const SyntaxFunc *const func, int is_header, int is_impl, + int need_param_name, std::string *result); - virtual void GetServiceFuncDeclaration(SyntaxTree * stree, SyntaxFunc * func, int is_header, int is_impl, - int need_param_name, std::string * result); + virtual void GenerateMqttDispatcherFunc(SyntaxTree *stree, + const SyntaxFunc *const func, + FILE *write); - virtual void GenerateDispatcherFunc(SyntaxTree * stree, SyntaxFunc * func, FILE * write); + virtual void GenerateDispatcherFunc(SyntaxTree *stree, + const SyntaxFunc *const func, + FILE *write); - virtual void GenerateURIFuncMap(SyntaxTree * stree, FILE * write); + virtual void GenerateMqttFuncMap(SyntaxTree *stree, + const std::vector functions, + FILE *write); - protected: - NameRender & name_render_; + virtual void GenerateURIFuncMap(SyntaxTree *stree, FILE *write); + + NameRender &name_render_; }; + } diff --git a/codegen/syntax_tree.cpp b/codegen/syntax_tree.cpp index 1f7fa0e..22eac92 100644 --- a/codegen/syntax_tree.cpp +++ b/codegen/syntax_tree.cpp @@ -1,33 +1,35 @@ /* -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 "syntax_tree.h" + using namespace phxrpc; + SyntaxNode::SyntaxNode() { memset(name_, 0, sizeof(name_)); } @@ -35,11 +37,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 +54,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 +73,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 int32_t cmdid) { cmdid_ = cmdid; } -int32_t SyntaxFunc::GetCmdID() { +int32_t SyntaxFunc::GetCmdID() const { return cmdid_; } @@ -125,43 +127,43 @@ 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 { +const char *SyntaxTree::GetPackageName() const { return package_name_; } -void SyntaxTree::SetPackageName(const char * package_name) { +void SyntaxTree::SetPackageName(const char *package_name) { strncpy(package_name_, package_name, sizeof(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 +173,8 @@ SyntaxFunc * SyntaxTree::FindFunc(const char * name) { return ret; } -char * SyntaxTree::ToLower(register char *s) { - register char *ret = s; +char *SyntaxTree::ToLower(char *s) { + char *ret = s; for (; *s != '\0'; ++s) *s = tolower(*s); @@ -180,8 +182,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); diff --git a/codegen/syntax_tree.h b/codegen/syntax_tree.h index 0d2edbe..1b3d769 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,61 +24,64 @@ 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 int32_t cmdid); + int32_t GetCmdID() const; - private: + private: SyntaxParam req_; SyntaxParam resp_; char opt_string_[_SYNTAX_DESC_LEN]; @@ -95,31 +98,30 @@ 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 SetPackageName(const char *sPBPackageName); + const char *GetPackageName() 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: + private: char proto_file_[128]; char prefix_[32]; char package_name_[128]; @@ -127,5 +129,6 @@ class SyntaxTree : public SyntaxNode { SyntaxFuncVector func_list_; }; + } diff --git a/codegen/tool_code_render.cpp b/codegen/tool_code_render.cpp index 4d69952..d861a7a 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,101 @@ 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 SyntaxFuncVector &mqtt_funcs, + 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, "#include \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 }; + char clasname[128]{0}; name_render_.GetToolClasname(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()); - fprintf(write, "\n"); + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + fprintf(write, " virtual int %s(phxrpc::OptMap &bigmap);\n", mqtt_it->GetName()); + } + + 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, "public:\n"); - fprintf(write, " typedef int (%s::*ToolFunc_t) ( phxrpc::OptMap & );\n", clasname); + 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 (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + fprintf(write, " {\"%s\", &%s::%s, \"c:f:v%s\",\n \"%s\"},\n", + mqtt_it->GetName(), clasname, + mqtt_it->GetName(), mqtt_it->GetOptString(), mqtt_it->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 +134,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 SyntaxFuncVector &mqtt_funcs, + 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 +154,53 @@ 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 }; + char clasname[128]{0}; name_render_.GetToolClasname(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 }; + char client_class[128]{0}; name_render_.GetClientClasname(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 (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + fprintf(write, "int %s::%s(phxrpc::OptMap &/* opt_map */) {\n", clasname, mqtt_it->GetName()); + fprintf(write, " printf(\"\\n *** %s unimplement ***\\n\");\n\n", mqtt_it->GetName()); + fprintf(write, " return -1;\n"); + fprintf(write, "}\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 SyntaxFuncVector &mqtt_funcs, + 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,38 +211,47 @@ void ToolCodeRender::GenerateToolImplHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); - fprintf(write, "#include \n"); + char toolfile[128]{0}; + name_render_.GetToolFileName(stree->GetName(), toolfile, sizeof(toolfile)); - fprintf(write, "\n"); + fprintf(write, "#include \"%s.h\"\n", toolfile); - char toolfile[128] = { 0 }; - name_render_.GetToolFileName(stree->GetName(), toolfile, sizeof(toolfile)); + fprintf(write, "\n"); - fprintf(write, "#include \"%s.h\"", toolfile); + fprintf(write, "#include \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 }; + char clasname[128]{0}; name_render_.GetToolClasname(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, "\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()); - fprintf(write, "\n"); + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + fprintf(write, " virtual int %s(phxrpc::OptMap &opt_map) override;\n", mqtt_it->GetName()); + } + + 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"); @@ -219,11 +259,13 @@ void ToolCodeRender::GenerateToolImplHpp(SyntaxTree * stree, FILE * write) { fprintf(write, "\n"); } -void ToolCodeRender::GenerateToolImplCpp(SyntaxTree * stree, FILE * write) { - char filename[128] = { 0 }; +void ToolCodeRender::GenerateToolImplCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + 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 +274,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 +282,88 @@ 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 }; + char clasname[128]{0}; name_render_.GetToolImplClasname(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 }; + char client_class[128]{0}, req_class[128]{0}, resp_class[128]{0}; name_render_.GetClientClasname(stree->GetName(), client_class, sizeof(client_class)); - SyntaxFuncVector * flist = stree->GetFuncList(); - SyntaxFuncVector::iterator fit = flist->begin(); - for (; flist->end() != fit; ++fit) { + for (auto mqtt_it(mqtt_funcs.cbegin()); mqtt_funcs.cend() != mqtt_it; + ++mqtt_it) { + name_render_.GetMessageClasname(mqtt_it->GetReq()->GetType(), req_class, sizeof(req_class)); + const char *const resp_type{mqtt_it->GetResp()->GetType()}; + if (resp_type && 0 < strlen(resp_type)) { + name_render_.GetMessageClasname(mqtt_it->GetResp()->GetType(), resp_class, sizeof(resp_class)); + } + + fprintf(write, "int %s::%s(phxrpc::OptMap &opt_map) {\n", clasname, mqtt_it->GetName()); + fprintf(write, " %s req;\n", req_class); + if (resp_type && 0 < strlen(resp_type)) { + fprintf(write, " %s resp;\n", resp_class); + } + fprintf(write, "\n"); + + if (0 == strcmp("PhxMqttPublish", mqtt_it->GetName())) { + fprintf(write, " if (nullptr == opt_map.Get('s')) return -1;\n\n"); + fprintf(write, " req.set_content(opt_map.Get('s'));\n"); + } + + fprintf(write, "\n"); + fprintf(write, " %s client;\n", client_class); + if (resp_type && 0 < strlen(resp_type)) { + fprintf(write, " int ret{client.%s(req, &resp)};\n", mqtt_it->GetName()); + } else { + fprintf(write, " int ret{client.%s(req)};\n", mqtt_it->GetName()); + } + fprintf(write, " printf(\"%%s return %%d\\n\", __func__, ret);\n"); + if (resp_type && 0 < strlen(resp_type)) { + 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, "\n"); + + SyntaxFuncVector *flist{stree->GetFuncList()}; + auto fit(flist->cbegin()); + for (; flist->cend() != fit; ++fit) { name_render_.GetMessageClasname(fit->GetReq()->GetType(), req_class, sizeof(req_class)); name_render_.GetMessageClasname(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 +371,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,9 +383,9 @@ 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_.GetToolFileName(stree->GetName(), tool_file, sizeof(tool_file)); @@ -313,7 +394,7 @@ void ToolCodeRender::GenerateToolMainCpp(SyntaxTree * stree, FILE * write) { name_render_.GetClientClasname(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 +406,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..9c6cfb9 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,45 @@ See the AUTHORS file for names of contributors. #pragma once -#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 SyntaxFuncVector &mqtt_funcs, + FILE *write); - void GenerateToolCpp(SyntaxTree * stree, FILE * write); + void GenerateToolCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write); - void GenerateToolImplHpp(SyntaxTree * stree, FILE * write); + void GenerateToolImplHpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + FILE *write); - void GenerateToolImplCpp(SyntaxTree * stree, FILE * write); + void GenerateToolImplCpp(SyntaxTree *stree, + const SyntaxFuncVector &mqtt_funcs, + 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..c916b66 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/hsha_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..6baee61 100644 --- a/phxrpc/file/file_utils.cpp +++ b/phxrpc/file/file_utils.cpp @@ -34,9 +34,17 @@ See the AUTHORS file for names of contributors. namespace phxrpc { bool FileUtils::ReadFile(const char * path, std::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)) { @@ -49,12 +57,12 @@ bool FileUtils::ReadFile(const char * path, std::string * content) { (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; 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..9bd8c59 100644 --- a/phxrpc/file/opt_map.cpp +++ b/phxrpc/file/opt_map.cpp @@ -62,7 +62,7 @@ size_t OptMap::GetNonOptCount() { } const char * OptMap::GetNonOpt(size_t index) { - if (index >= 0 && index < non_opt_.size()) { + if (index > 0 && index < non_opt_.size()) { return non_opt_[index].c_str(); } 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_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..75cc9c7 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) { + : HttpMessage(), BaseRequest(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) { + : HttpMessage(), BaseResponse(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..a7bdb7e --- /dev/null +++ b/phxrpc/mqtt.h @@ -0,0 +1,28 @@ +/* +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_dispatcher.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_client.cpp b/phxrpc/mqtt/mqtt_client.cpp new file mode 100644 index 0000000..a55943b --- /dev/null +++ b/phxrpc/mqtt/mqtt_client.cpp @@ -0,0 +1,135 @@ +/* +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, MqttClient::MqttStat &mqtt_stat) { + 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, + MqttPuback &resp, MqttClient::MqttStat &mqtt_stat) { + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Publish(BaseTcpStream &socket, const MqttPublish &req, + MqttPuback &resp) { + return static_cast(DoMethod(socket, &req, &resp)); +} + +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) { + return static_cast(DoMethod(socket, &req, &resp)); +} + +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, + MqttClient::MqttStat &mqtt_stat) { + MqttFakeDisconnack resp; + return static_cast(DoMethod(socket, &req, &resp, mqtt_stat)); +} + +int MqttClient::Disconnect(BaseTcpStream &socket, const MqttDisconnect &req) { + MqttFakeDisconnack 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..6920f9a --- /dev/null +++ b/phxrpc/mqtt/mqtt_client.h @@ -0,0 +1,91 @@ +/* +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 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, + MqttPuback &resp, MqttStat &mqtt_stat); + static int Publish(BaseTcpStream &socket, const MqttPublish &req, + MqttPuback &resp); + + // @return true: socket ok; false: socket error + 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); + + // @return true: socket ok; false: socket error + 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..e1513d8 --- /dev/null +++ b/phxrpc/mqtt/mqtt_msg.cpp @@ -0,0 +1,1099 @@ +/* +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::FixedHeader[]{ + '\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 +}; + +//const bool MqttMessage::NeedPacketIdentifier[]{ +// false, // FAKE_NONE +// false, // CONNECT +// false, // CONNACK +// true, // PUBLISH QoS 1 +// true, // PUBACK +// true, // PUBREC +// true, // PUBREL +// true, // PUBCOMP +// true, // SUBSCRIBE +// true, // SUBACK +// true, // UNSUBSCRIBE +// true, // UNSUBACK +// false, // PINGREQ +// false, // PINGRESP +// false, // DISCONNECT +// false, // 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() {} + +ReturnCode MqttMessage::SendFixedHeaderAndRemainingBuffer( + BaseTcpStream &out_stream, + const ControlPacketType control_packet_type, + const string &remaining_buffer) { + char fixed_header{FixedHeader[static_cast(control_packet_type)]}; + ReturnCode ret{SendChar(out_stream, fixed_header)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChar err %d", ret); + + return ret; + } else { + phxrpc::log(LOG_DEBUG, "SendChar type %d fixed_header %u", + static_cast(control_packet_type), + static_cast(fixed_header)); + } + + 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, ControlPacketType &control_packet_type, + string &remaining_buffer) { + char fixed_header{0x0}; + ReturnCode ret{RecvChar(in_stream, fixed_header)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + + uint8_t temp{static_cast(fixed_header)}; + temp >>= 4; + temp &= 0x0f; + // must convert to unsigned first + control_packet_type = static_cast(temp); + + phxrpc::log(LOG_DEBUG, "RecvChar type %d fixed_header %u", + static_cast(control_packet_type), + static_cast(fixed_header)); + + 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, control_packet_type(), 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; + } + + ret = SendPayload(out_stream); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendPayload err %d", ret); + + return ret; + } + + 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; + } + + return ret; +} + +ReturnCode MqttMessage::SendPacketIdentifier(ostringstream &out_stream) const { + //const int packet_type{static_cast(control_packet_type_)}; + //if (!NeedPacketIdentifier[packet_type]) { + // phxrpc::log(LOG_WARNING, "type %d ignored packet identifier", + // packet_type); + + // return ReturnCode::OK; + //} + + 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) { + //const int packet_type{static_cast(control_packet_type_)}; + //if (!NeedPacketIdentifier[packet_type]) { + // phxrpc::log(LOG_WARNING, "type %d ignored packet identifier", + // packet_type); + + // return ReturnCode::OK; + //} + + 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; +} + + +MqttConnect::MqttConnect() : MqttRequest(Protocol::MQTT_CONNECT) { + set_control_packet_type(ControlPacketType::CONNECT); + + proto_name_.resize(6); + proto_name_[0] = 0; + proto_name_[1] = 4; + proto_name_[2] = 'M'; + proto_name_[3] = 'Q'; + proto_name_[4] = 'T'; + proto_name_[5] = 'T'; +} + +ReturnCode MqttConnect::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttConnectPb connect; + + connect.set_clean_session(clean_session_); + connect.set_keep_alive(keep_alive_); + connect.set_client_identifier(client_identifier_); + connect.set_proto_name(proto_name_); + connect.set_proto_level(proto_level_); + + 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; + } + + clean_session_ = connect.clean_session(); + keep_alive_ = connect.keep_alive(); + client_identifier_ = connect.client_identifier(); + proto_name_ = connect.proto_name(); + proto_level_ = connect.proto_level(); + + return ReturnCode::OK; +} + +BaseResponse *MqttConnect::GenResponse() const { return new MqttConnack; } + +ReturnCode MqttConnect::SendVariableHeader(ostringstream &out_stream) const { + ReturnCode ret{SendChars(out_stream, proto_name_.data(), + proto_name_.size())}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "SendChars 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{0}; + connect_flags |= ((clean_session_ ? 1u : 0u) << 1); + 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) { + char proto_name[6]{0x0}; + ReturnCode ret{RecvChars(in_stream, proto_name, 6)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChars err %d", ret); + + return ret; + } + proto_name_.resize(6); + proto_name_[0] = proto_name[0]; + proto_name_[1] = proto_name[1]; + proto_name_[2] = proto_name[2]; + proto_name_[3] = proto_name[3]; + proto_name_[4] = proto_name[4]; + proto_name_[5] = proto_name[5]; + + ret = RecvChar(in_stream, proto_level_); + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvChar err %d", ret); + + return ret; + } + + 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_ = ((connect_flags & 0x2) >> 1); + + 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 { + return SendUnicode(out_stream, client_identifier_); +} + +ReturnCode MqttConnect::RecvPayload(istringstream &in_stream) { + return RecvUnicode(in_stream, client_identifier_); +} + + +MqttConnack::MqttConnack() : MqttResponse(Protocol::MQTT_CONNECT) { + set_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() : MqttRequest(Protocol::MQTT_PUBLISH) { + set_control_packet_type(ControlPacketType::PUBLISH); +} + +ReturnCode MqttPublish::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPublishPb publish; + + publish.set_topic_name(topic_name_); + publish.set_content(GetContent()); + publish.set_package_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; + } + + topic_name_ = publish.topic_name(); + SetContent(publish.content().data(), publish.content().length()); + set_packet_identifier(publish.package_identifier()); + + return ReturnCode::OK; +} + +BaseResponse *MqttPublish::GenResponse() const { return new MqttPuback; } + +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; + } + + 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; + } + + 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 SendUnicode(out_stream, GetContent()); +} + +ReturnCode MqttPublish::RecvPayload(istringstream &in_stream) { + return RecvUnicode(in_stream, GetContent()); +} + + +MqttPuback::MqttPuback() : MqttResponse(Protocol::MQTT_PUBLISH) { + set_control_packet_type(ControlPacketType::PUBACK); +} + +ReturnCode MqttPuback::ToPb(google::protobuf::Message *const message) const { + phxrpc::MqttPubackPb puback; + + puback.set_package_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.package_identifier()); + + return ReturnCode::OK; +} + +ReturnCode MqttPuback::SendVariableHeader(ostringstream &out_stream) const { + return SendPacketIdentifier(out_stream); +} + +ReturnCode MqttPuback::RecvVariableHeader(istringstream &in_stream) { + return RecvPacketIdentifier(in_stream); +} + + +MqttSubscribe::MqttSubscribe() : MqttRequest(Protocol::MQTT_SUBSCRIBE) { + set_control_packet_type(ControlPacketType::SUBSCRIBE); +} + +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) { + while (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); + } + + return ReturnCode::OK; +} + + +MqttSuback::MqttSuback() : MqttResponse(Protocol::MQTT_SUBSCRIBE) { + set_control_packet_type(ControlPacketType::SUBACK); +} + +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() : MqttRequest(Protocol::MQTT_UNSUBSCRIBE) { + set_control_packet_type(ControlPacketType::UNSUBSCRIBE); +} + +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) { + while (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); + } + + return ReturnCode::OK; +} + + +MqttUnsuback::MqttUnsuback() : MqttResponse(Protocol::MQTT_UNSUBSCRIBE) { + set_control_packet_type(ControlPacketType::UNSUBACK); +} + +ReturnCode MqttUnsuback::SendVariableHeader(ostringstream &out_stream) const { + return SendPacketIdentifier(out_stream); +} + +ReturnCode MqttUnsuback::RecvVariableHeader(istringstream &in_stream) { + return RecvPacketIdentifier(in_stream); +} + + +MqttPingreq::MqttPingreq() : MqttRequest(Protocol::MQTT_PING) { + set_control_packet_type(ControlPacketType::PINGREQ); +} + +BaseResponse *MqttPingreq::GenResponse() const { return new MqttPingresp; } + + +MqttPingresp::MqttPingresp() : MqttResponse(Protocol::MQTT_PING) { + set_control_packet_type(ControlPacketType::PINGRESP); +} + + +MqttDisconnect::MqttDisconnect() : MqttRequest(Protocol::MQTT_DISCONNECT) { + set_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 MqttFakeDisconnack; } + + +MqttFakeDisconnack::MqttFakeDisconnack() + : MqttResponse(Protocol::MQTT_FAKE_DISCONNACK) { + set_control_packet_type(ControlPacketType::FAKE_DISCONNACK); + set_fake(true); +} + + +} // namespace phxrpc + diff --git a/phxrpc/mqtt/mqtt_msg.h b/phxrpc/mqtt/mqtt_msg.h new file mode 100644 index 0000000..65d497c --- /dev/null +++ b/phxrpc/mqtt/mqtt_msg.h @@ -0,0 +1,548 @@ +/* +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_DISCONNACK, + FAKE_MAX, + }; + + static const char FixedHeader[]; + + //static const bool NeedPacketIdentifier[]; + + 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); + + // control packet type and flags + static ReturnCode SendFixedHeaderAndRemainingBuffer( + BaseTcpStream &out_stream, + const ControlPacketType control_packet_type, + const std::string &remaining_buffer); + static ReturnCode RecvFixedHeaderAndRemainingBuffer( + BaseTcpStream &in_stream, + ControlPacketType &control_packet_type, + 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); + + ControlPacketType control_packet_type() const { + return control_packet_type_; + } + + int remaining_length() const { return remaining_length_; } + + uint16_t packet_identifier() const { return packet_identifier_; } + + void set_packet_identifier(const uint16_t packet_identifier) { + packet_identifier_ = packet_identifier; + } + + protected: + void set_control_packet_type(const ControlPacketType control_packet_type) { + control_packet_type_ = control_packet_type; + } + + void set_remaining_length(const int remaining_length) { + remaining_length_ = remaining_length; + } + + private: + ControlPacketType control_packet_type_{ControlPacketType::FAKE_NONE}; + uint16_t packet_identifier_{0x0}; + int remaining_length_{0}; +}; + + +class MqttRequest : public MqttMessage, public BaseRequest { + public: + MqttRequest(const Protocol protocol) : BaseRequest(protocol) {} + virtual ~MqttRequest() = default; + + private: +}; + + +class MqttResponse : public MqttMessage, public BaseResponse { + public: + MqttResponse(const Protocol protocol) : BaseResponse(protocol) {} + 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 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 + char proto_level() const { return proto_level_; } + + private: + bool clean_session_{false}; + uint16_t keep_alive_{0}; + std::string client_identifier_; + std::string proto_name_; + char proto_level_{4}; +}; + + +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 MqttRequest { + 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 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 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 MqttSubscribe final : public MqttRequest { + public: + MqttSubscribe(); + virtual ~MqttSubscribe() = 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 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 MqttSuback final : public MqttResponse { + public: + MqttSuback(); + virtual ~MqttSuback() = 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; + 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 { + return ReturnCode::ERROR_UNIMPLEMENT; + } + + virtual ReturnCode FromPb(const google::protobuf::Message &message) override { + return ReturnCode::ERROR_UNIMPLEMENT; + } + + 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 { + 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; + 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 { + return ReturnCode::ERROR_UNIMPLEMENT; + } + + virtual ReturnCode FromPb(const google::protobuf::Message &message) override { + return ReturnCode::ERROR_UNIMPLEMENT; + } + + 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 { + 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 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; + } +}; + + +class MqttFakeDisconnack final : public MqttResponse { + public: + MqttFakeDisconnack(); + virtual ~MqttFakeDisconnack() = 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; + } +}; + + +} // namespace phxrpc + diff --git a/phxrpc/mqtt/mqtt_protocol.cpp b/phxrpc/mqtt/mqtt_protocol.cpp new file mode 100644 index 0000000..1840860 --- /dev/null +++ b/phxrpc/mqtt/mqtt_protocol.cpp @@ -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. +*/ + +#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; + + +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->control_packet_type(), 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 MqttProtocol::RecvMessage(BaseTcpStream &socket, + MqttMessage *const msg) { + MqttMessage::ControlPacketType control_packet_type{ + MqttMessage::ControlPacketType::FAKE_NONE}; + string remaining_buffer; + ReturnCode ret{MqttMessage::RecvFixedHeaderAndRemainingBuffer(socket, + control_packet_type, remaining_buffer)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvFixedHeaderAndRemainingBuffer err %d", ret); + + return ret; + } + + istringstream ss(remaining_buffer); + + if (msg->control_packet_type() == control_packet_type) { + return msg->RecvRemaining(ss); + } + phxrpc::log(LOG_ERR, "msg_type %d != recv_type %d", + static_cast(msg->control_packet_type()), + static_cast(control_packet_type)); + + return ReturnCode::ERROR; +} + +ReturnCode MqttProtocol::ServerRecv(BaseTcpStream &socket, BaseRequest *&req) { + MqttMessage::ControlPacketType control_packet_type{ + MqttMessage::ControlPacketType::FAKE_NONE}; + string remaining_buffer; + ReturnCode ret{MqttMessage::RecvFixedHeaderAndRemainingBuffer(socket, + control_packet_type, remaining_buffer)}; + if (ReturnCode::OK != ret) { + phxrpc::log(LOG_ERR, "RecvFixedHeaderAndRemainingBuffer err %d", ret); + + return ret; + } + + istringstream ss(remaining_buffer); + + if (MqttMessage::ControlPacketType::CONNECT == control_packet_type) { + MqttConnect *connect{new MqttConnect}; + req = connect; + return connect->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::PUBLISH == control_packet_type) { + MqttPublish *publish{new MqttPublish}; + req = publish; + return publish->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::SUBSCRIBE == control_packet_type) { + MqttSubscribe *subscribe{new MqttSubscribe}; + req = subscribe; + return subscribe->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::UNSUBSCRIBE == control_packet_type) { + MqttUnsubscribe *unsubscribe{new MqttUnsubscribe}; + req = unsubscribe; + return unsubscribe->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::PINGREQ == control_packet_type) { + MqttPingreq *pingreq{new MqttPingreq}; + req = pingreq; + return pingreq->RecvRemaining(ss); + } else if (MqttMessage::ControlPacketType::DISCONNECT == control_packet_type) { + MqttDisconnect *disconnect{new MqttDisconnect}; + req = disconnect; + return disconnect->RecvRemaining(ss); + } + phxrpc::log(LOG_ERR, "type %d not supported", static_cast(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..9148b46 --- /dev/null +++ b/phxrpc/mqtt/mqtt_protocol.h @@ -0,0 +1,52 @@ +/* +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; + + static ReturnCode SendMessage(BaseTcpStream &socket, + const MqttMessage *const msg); + static ReturnCode RecvMessage(BaseTcpStream &socket, + MqttMessage *const msg); + + virtual ReturnCode ServerRecv(BaseTcpStream &socket, + BaseRequest *&req) override; +}; + + +} + 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..81372c9 --- /dev/null +++ b/phxrpc/mqtt/test_mqtt_protocol.cpp @@ -0,0 +1,151 @@ +/* +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, 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); +} + +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; + TraceMsg(MqttConnect()); + + cout << "Resp:" << endl; + TraceMsg(MqttConnack()); + } else if (0 == strcasecmp(method, "PUBLISH")) { + cout << "Req:" << endl; + MqttPublish publish; + publish.set_topic_name("test_topic_1"); + 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..f01fb03 --- /dev/null +++ b/phxrpc/msg/base_dispatcher.h @@ -0,0 +1,90 @@ +/* +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 "base_msg.h" + + +namespace phxrpc { + + +template +class BaseDispatcher { + public: + typedef int (Dispatcher::*MqttFunc_t)(const BaseRequest *const req, + BaseResponse *const resp); + typedef int (Dispatcher::*URIFunc_t)(const BaseRequest *const req, + BaseResponse *const resp); + + typedef std::map MqttFuncMap; + typedef std::map URIFuncMap; + + BaseDispatcher(Dispatcher &dispatcher, const MqttFuncMap &mqtt_func_map, + const URIFuncMap &uri_func_map) + : dispatcher_(dispatcher), mqtt_func_map_(mqtt_func_map), + uri_func_map_(uri_func_map) { + } + + virtual ~BaseDispatcher() = default; + + bool Dispatch(const BaseRequest *const req, BaseResponse *const resp) { + int ret{-1}; + + if (BaseMessage::Protocol::HTTP_POST == req->protocol() || + BaseMessage::Protocol::HTTP_GET == req->protocol() || + BaseMessage::Protocol::HTTP_HEAD == req->protocol()) { + 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; + } else { + typename MqttFuncMap::const_iterator iter(mqtt_func_map_.find(req->protocol())); + + if (mqtt_func_map_.end() != iter) { + ret = (dispatcher_.*iter->second)(req, resp); + } + + resp->SetPhxRpcResult(ret); + + return mqtt_func_map_.end() != iter; + } + + return ret; + } + + private: + Dispatcher &dispatcher_; + const MqttFuncMap &mqtt_func_map_; + 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..fc904e9 --- /dev/null +++ b/phxrpc/msg/base_msg.cpp @@ -0,0 +1,114 @@ +/* +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(const BaseMessage::Protocol protocol) { + set_direction(BaseMessage::Direction::REQUEST); + set_protocol(protocol); +} + +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(const BaseMessage::Protocol protocol) { + set_direction(BaseMessage::Direction::RESPONSE); + set_protocol(protocol); +} + +BaseResponse::~BaseResponse() {} + + +} + diff --git a/phxrpc/msg/base_msg.h b/phxrpc/msg/base_msg.h new file mode 100644 index 0000000..ca62d63 --- /dev/null +++ b/phxrpc/msg/base_msg.h @@ -0,0 +1,139 @@ +/* +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_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, + }; + + 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(const Protocol protocol); + 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(const Protocol protocol); + 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..111c517 --- /dev/null +++ b/phxrpc/msg/common.h @@ -0,0 +1,65 @@ +/* +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_OVERFLOW = -103, + ERROR_SOCKET_STREAM_TIMEOUT = -202, + ERROR_SOCKET_STREAM_NORMAL_CLOSED = -303, + 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..2f88013 100644 --- a/phxrpc/network/timer.cpp +++ b/phxrpc/network/timer.cpp @@ -29,6 +29,7 @@ See the AUTHORS file for names of contributors. #include "uthread_epoll.h" #include #include +#include using namespace std; @@ -41,9 +42,15 @@ const uint64_t Timer::GetTimestampMS() { } const uint64_t Timer::GetSteadyClockMS() { + auto now_time = chrono::system_clock::now(); + uint64_t now = (chrono::duration_cast(now_time.time_since_epoch())).count(); + return now; + + /* auto now_time = chrono::steady_clock::now(); uint64_t now = (chrono::duration_cast(now_time.time_since_epoch())).count(); return now; + */ } void Timer :: MsSleep(const int time_ms) { 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..aa18a21 100644 --- a/phxrpc/network/uthread_epoll.cpp +++ b/phxrpc/network/uthread_epoll.cpp @@ -22,7 +22,6 @@ See the AUTHORS file for names of contributors. #include #include #include -#include #include #include #include @@ -34,6 +33,12 @@ See the AUTHORS file for names of contributors. #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" @@ -90,7 +95,7 @@ void EpollNotifier :: Func() { 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__); } } @@ -102,10 +107,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 +123,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,8 +131,6 @@ UThreadEpollScheduler::UThreadEpollScheduler(size_t stack_size, int max_task) : } UThreadEpollScheduler::~UThreadEpollScheduler() { - delete runtime_; - close(epoll_fd_); } @@ -135,6 +139,10 @@ UThreadEpollScheduler * UThreadEpollScheduler :: Instance() { return &obj; } +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)); } @@ -143,16 +151,20 @@ void UThreadEpollScheduler :: SetActiveSocketFunc(UThreadActiveSocket_t active_s 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, @@ -181,8 +193,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(); } @@ -203,7 +215,7 @@ 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); } } @@ -229,26 +241,33 @@ bool UThreadEpollScheduler::Run() { struct epoll_event * events = (struct epoll_event*) calloc(max_task_, sizeof(struct epoll_event)); - int next_timeout = timer_.GetNextTimeout(); - - for (; (run_forever_) || (!runtime_->IsAllDone());) { - int nfds = epoll_wait(epoll_fd_, events, max_task_, 4); + for (; (run_forever_) || (!runtime_.IsAllDone());) { + int next_timeout = timer_.GetNextTimeout(); + int timeout = 4; + if(next_timeout > 0 && next_timeout < timeout) + timeout = next_timeout; + int nfds = epoll_wait(epoll_fd_, events, max_task_, timeout); 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_(); } @@ -298,7 +317,7 @@ void UThreadEpollScheduler::DealwithTimeout(int & next_timeout) { UThreadSocket_t * socket = timer_.PopTimeout(); socket->waited_events = UThreadEpollREvent_Timeout; - runtime_->Resume(socket->uthread_id); + runtime_.Resume(socket->uthread_id); } } @@ -423,31 +442,33 @@ int UThreadAccept(UThreadSocket_t & socket, struct sockaddr *addr, socklen_t *ad } ssize_t UThreadRead(UThreadSocket_t & socket, void * buf, size_t len, int flags) { - int ret = read(socket.socket, buf, len); + //int ret = read(socket.socket, buf, len); + int ret = -1; - if (ret < 0 && EAGAIN == errno) { + //if (ret < 0 && EAGAIN == errno) { int revents = 0; if (UThreadPoll(socket, EPOLLIN, &revents, socket.socket_timeout_ms) > 0) { ret = read(socket.socket, buf, len); } else { ret = -1; } - } + //} return ret; } ssize_t UThreadRecv(UThreadSocket_t & socket, void * buf, size_t len, int flags) { - int ret = recv(socket.socket, buf, len, flags); + //int ret = recv(socket.socket, buf, len, flags); + int ret = -1; - if (ret < 0 && EAGAIN == errno) { + //if (ret < 0 && EAGAIN == errno) { int revents = 0; if (UThreadPoll(socket, EPOLLIN, &revents, socket.socket_timeout_ms) > 0) { ret = recv(socket.socket, buf, len, flags); } else { ret = -1; } - } + //} return ret; } @@ -503,22 +524,22 @@ 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, 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..48ffb49 100644 --- a/phxrpc/network/uthread_epoll.h +++ b/phxrpc/network/uthread_epoll.h @@ -24,8 +24,6 @@ See the AUTHORS file for names of contributors. #include #include #include - -#include #include #include "uthread_runtime.h" @@ -40,7 +38,8 @@ 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< void() > UThreadHandlerAcceptedFdFunc_t; +typedef std::function< void() > UThreadHandlerNewRequest_t; class EpollNotifier { public: @@ -58,11 +57,13 @@ class EpollNotifier { class UThreadEpollScheduler { public: - UThreadEpollScheduler(size_t stack_size, int max_task); + UThreadEpollScheduler(size_t stack_size, int max_task, const bool need_stack_protect = true); ~UThreadEpollScheduler(); static UThreadEpollScheduler * Instance(); + bool IsTaskFull(); + void AddTask(UThreadFunc_t func, void * args); UThreadSocket_t * CreateSocket(int fd, int socket_timeout_ms = 5000, @@ -70,7 +71,9 @@ class UThreadEpollScheduler { 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(); @@ -95,7 +98,7 @@ class UThreadEpollScheduler { void StatEpollwaitEvents(const int event_count); private: - UThreadRuntime * runtime_; + UThreadRuntime runtime_; int max_task_; TaskQueue todo_list_; int epoll_fd_; @@ -105,7 +108,9 @@ class UThreadEpollScheduler { bool run_forever_; 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_; @@ -126,6 +131,7 @@ class __uthread { }; #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(); @@ -162,13 +168,13 @@ UThreadSocket_t * NewUThreadSocket(); 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, int timeout_ms); -void UthreadLazyDestory(UThreadSocket_t & socket); +void UThreadLazyDestory(UThreadSocket_t & socket); -bool IsUthreadDestory(UThreadSocket_t & socket); +bool IsUThreadDestory(UThreadSocket_t & socket); }; 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..64e67e4 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. @@ -28,7 +28,9 @@ See the AUTHORS file for names of contributors. #include "rpc/socket_stream_phxrpc.h" #include "rpc/uthread_caller.h" #include "rpc/http_caller.h" +#include "rpc/mqtt_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/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/hsha_server.cpp b/phxrpc/rpc/hsha_server.cpp index 4ab4fdc..364d962 100644 --- a/phxrpc/rpc/hsha_server.cpp +++ b/phxrpc/rpc/hsha_server.cpp @@ -1,55 +1,60 @@ /* -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 "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() { } -DataFlow :: ~DataFlow() { +DataFlow::~DataFlow() { } -void DataFlow :: PushRequest(void * args, HttpRequest * request) { +void DataFlow::PushRequest(void * args, BaseRequest * request) { in_queue_.push(make_pair(QueueExtData(args), request)); } -int DataFlow :: PluckRequest(void *& args, HttpRequest *& request) { - pair rp; +int DataFlow::PluckRequest(void *& args, BaseRequest *& request) { + pair rp; bool succ = in_queue_.pluck(rp); if (!succ) { return 0; @@ -61,12 +66,25 @@ int DataFlow :: PluckRequest(void *& args, HttpRequest *& request) { return now_time > rp.first.enqueue_time_ms ? now_time - rp.first.enqueue_time_ms : 0; } -void DataFlow :: PushResponse(void * args, HttpResponse * response) { +int DataFlow::PickRequest(void *& args, BaseRequest *& request) { + pair rp; + bool succ = in_queue_.pick(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, BaseResponse * response) { out_queue_.push(make_pair(QueueExtData(args), response)); } -int DataFlow :: PluckResponse(void *& args, HttpResponse *& response) { - pair rp; +int DataFlow::PluckResponse(void *& args, BaseResponse *& response) { + pair rp; bool succ = out_queue_.pluck(rp); if (!succ) { return 0; @@ -76,39 +94,39 @@ int DataFlow :: PluckResponse(void *& args, HttpResponse *& response) { 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) { +bool DataFlow::CanPushRequest(const int max_queue_length) { return in_queue_.size() < (size_t)max_queue_length; -} +} -bool DataFlow :: CanPluckResponse() { +bool DataFlow::CanPluckResponse() { return !out_queue_.empty(); } -void DataFlow :: BreakOut() { +void DataFlow::BreakOut() { in_queue_.break_out(); out_queue_.break_out(); } //////////////////////////////////////// -HshaServerStat :: TimeCost :: TimeCost() { +HshaServerStat::TimeCost::TimeCost() { now_time_ms_ = Timer::GetSteadyClockMS(); } -HshaServerStat :: TimeCost :: ~TimeCost() { +HshaServerStat::TimeCost::~TimeCost() { } -int HshaServerStat :: TimeCost :: Cost() { +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), +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; @@ -170,16 +188,19 @@ HshaServerStat :: HshaServerStat(const HshaServerConfig * config, ServerMonitorP 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() { +HshaServerStat::~HshaServerStat() { break_out_ = true; cv_.notify_all(); thread_.join(); } -void HshaServerStat :: MonitorReport() { +void HshaServerStat::MonitorReport() { //accept hsha_server_monitor_->Accept( accept_qps_ ); hsha_server_monitor_->AcceptFail( accept_fail_qps_ ); @@ -203,10 +224,10 @@ void HshaServerStat :: MonitorReport() { hsha_server_monitor_->WrokerInQueueTimeout( worker_drop_reqeust_qps_ ); } -void HshaServerStat :: CalFunc() { +void HshaServerStat::CalFunc() { while (!break_out_) { - std::unique_lock lock(mutex_); - cv_.wait_for(lock, std::chrono::seconds(1)); + unique_lock lock(mutex_); + cv_.wait_for(lock, chrono::seconds(1)); //acceptor accept_qps_ = static_cast(accepted_fds_); @@ -252,16 +273,26 @@ void HshaServerStat :: CalFunc() { //time cost rpc_time_cost_per_period_ = 0; if (rpc_time_costs_count_ >= RPC_TIME_COST_CAL_RATE) { - rpc_avg_time_cost_per_second_ = + 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_ = + 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; @@ -271,7 +302,7 @@ void HshaServerStat :: CalFunc() { 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_ = + 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; @@ -291,15 +322,15 @@ void HshaServerStat :: CalFunc() { 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_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_, + 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_, + enqueue_fast_reject_qps_, static_cast(worker_idles_), worker_drop_reqeust_qps_, io_read_fail_qps_, io_write_fail_qps_ ); } @@ -307,32 +338,32 @@ void HshaServerStat :: CalFunc() { //////////////////////////////////////// -HshaServerQos :: HshaServerQos(const HshaServerConfig * config, HshaServerStat * hsha_server_stat) - : config_(config), hsha_server_stat_(hsha_server_stat), +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() { +HshaServerQos::~HshaServerQos() { break_out_ = true; cv_.notify_all(); thread_.join(); } -bool HshaServerQos :: CanAccept() { +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)); +bool HshaServerQos::CanEnqueue() { + static default_random_engine e_rand((int)time(nullptr)); return ((int)(e_rand() % 100)) >= enqueue_reject_rate_; } -void HshaServerQos :: CalFunc() { +void HshaServerQos::CalFunc() { while (!break_out_) { - std::unique_lock lock(mutex_); - cv_.wait_for(lock, std::chrono::seconds(1)); + 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_ @@ -341,13 +372,14 @@ void HshaServerQos :: CalFunc() { 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_ + 5 > 99 ? 99 : enqueue_reject_rate_ + 5; + 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_ - 5 < 0 ? 0 : enqueue_reject_rate_ - 5; + enqueue_reject_rate_ = enqueue_reject_rate_ - rate < 0 ? 0 : enqueue_reject_rate_ - rate; } } inqueue_avg_wait_time_costs_per_second_cal_last_seq_ = @@ -363,20 +395,30 @@ void HshaServerQos :: CalFunc() { //////////////////////////////////////// -Worker :: Worker(WorkerPool * pool) - : pool_(pool), shut_down_(false), thread_(&Worker::Func, this) { +Worker::Worker(WorkerPool *pool, const int uthread_count, int utherad_stack_size) + : pool_(pool), uthread_count_(uthread_count), utherad_stack_size_(utherad_stack_size), shut_down_(false), + worker_scheduler_(nullptr), thread_(&Worker::Func, this) { } -Worker :: ~Worker() { +Worker::~Worker() { thread_.join(); + delete worker_scheduler_; } -void Worker :: Func() { +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; - HttpRequest * request = nullptr; + BaseRequest * request = nullptr; int queue_wait_time_ms = pool_->data_flow_->PluckRequest(args, request); if (request == nullptr) { //break out @@ -384,173 +426,251 @@ void Worker :: Func() { } 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_++; + WorkerLogic(args, request, queue_wait_time_ms); + } +} - 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_++; +void Worker::UThreadMode() { + worker_scheduler_ = new UThreadEpollScheduler(utherad_stack_size_, uthread_count_, true); + assert(worker_scheduler_ != nullptr); + worker_scheduler_->SetHandlerNewRequestFunc(bind(&Worker::HandlerNewRequestFunc, this)); + worker_scheduler_->RunForever(); +} - pool_->scheduler_->NotifyEpoll(); +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 == nullptr) { + 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; - delete request; + DispatcherArgs_t dispatcher_args(pool_->hsha_server_stat_->hsha_server_monitor_, + worker_scheduler_, pool_->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_++; } + pool_->data_flow_->PushResponse(args, resp); + pool_->hsha_server_stat_->outqueue_push_responses_++; + + pool_->scheduler_->NotifyEpoll(); + + delete req; } -void Worker :: Shutdown() { +void Worker::Notify() { + if (uthread_count_ == 0) { + return; + } + + worker_scheduler_->NotifyEpoll(); +} + +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), +WorkerPool::WorkerPool( + UThreadEpollScheduler * scheduler, + int thread_count, + int uthread_count_per_thread, + int utherad_stack_size, + 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); + args_(args), last_notify_idx_(0) { + for (int i = 0; i < thread_count; i++) { + auto worker = new Worker(this, uthread_count_per_thread, utherad_stack_size); assert(worker != nullptr); worker_list_.push_back(worker); } } -WorkerPool :: ~WorkerPool() { +WorkerPool::~WorkerPool() { for (auto & worker : worker_list_) { worker->Shutdown(); delete worker; } } +void WorkerPool::Notify() { + lock_guard lock(mutex_); + if (last_notify_idx_ == worker_list_.size()) { + last_notify_idx_ = 0; + } + + worker_list_[last_notify_idx_++]->Notify(); +} + //////////////////////////////////////// -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(int idx, UThreadEpollScheduler * 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), /* listen_fd_(-1), */ 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; + + // TODO: unique_ptr not support dervied class dtor? + 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_->Notify(); 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 sockettimeoutms %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; + void *args = nullptr; + BaseResponse *response = nullptr; int queue_wait_time_ms = data_flow_->PluckResponse(args, response); if (response == nullptr) { //break out @@ -559,8 +679,8 @@ UThreadSocket_t * HshaServerIO :: ActiveSocketFunc() { 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); @@ -576,47 +696,57 @@ UThreadSocket_t * HshaServerIO :: ActiveSocketFunc() { 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) : +HshaServerUnit::HshaServerUnit( + HshaServer *hsha_server, + int idx, + int worker_thread_count, + int worker_uthread_count_per_thread, + int worker_utherad_stack_size, + 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), +#ifndef __APPLE__ + scheduler_(8 * 1024, 1000000, false), +#else + scheduler_(32 * 1024, 1000000, false), +#endif + worker_pool_(&scheduler_, worker_thread_count, worker_uthread_count_per_thread, + worker_utherad_stack_size, &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() { +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); } ///////////////////////////////////////////////// -HshaServerAcceptor :: HshaServerAcceptor(HshaServer * hsha_server) - : hsha_server_(hsha_server), idx_(0) { +HshaServerAcceptor::HshaServerAcceptor(HshaServer * hsha_server) + : hsha_server_(hsha_server), idx_(0) { } -HshaServerAcceptor :: ~HshaServerAcceptor() { +HshaServerAcceptor::~HshaServerAcceptor() { } -void HshaServerAcceptor :: LoopAccept(const char * bind_ip, const int port) { +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); @@ -625,6 +755,7 @@ 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); @@ -633,6 +764,7 @@ void HshaServerAcceptor :: LoopAccept(const char * bind_ip, const int port) { if (ret != 0) { printf("sched_setaffinity fail\n"); } +#endif while (true) { struct sockaddr_in addr; @@ -666,41 +798,49 @@ void HshaServerAcceptor :: LoopAccept(const char * bind_ip, const int port) { //////////////////////////////////////// -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, + 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) { 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_utherad_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 hsha_server_unit = new HshaServerUnit(this, i, worker_thread_count_per_io, dispatch, args); + auto hsha_server_unit = + new HshaServerUnit(this, i, (int)worker_thread_count_per_io, + config.GetWorkerUThreadCount(), worker_utherad_stack_size, 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; } } -void HshaServer :: RunForever() { +void HshaServer::RunForever() { hsha_server_acceptor_.LoopAccept(config_->GetBindIP(), config_->GetPort()); } -} //namespace phxrpc + +} //namespace phxrpc + diff --git a/phxrpc/rpc/hsha_server.h b/phxrpc/rpc/hsha_server.h index dfc683d..c5fc519 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,40 +21,44 @@ See the AUTHORS file for names of contributors. #pragma once -#include -#include -#include #include #include +#include +#include #include +#include #include + #include "server_config.h" #include "thread_queue.h" #include "phxrpc/network.h" -#include "phxrpc/http.h" +#include "phxrpc/msg.h" #include "server_base.h" #include "server_monitor.h" + namespace phxrpc { + class WorkerPool; -class DataFlow { -public: +class DataFlow final { + 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); + void PushRequest(void * args, BaseRequest * request); + int PluckRequest(void *& args, BaseRequest *& request); + int PickRequest(void *& args, BaseRequest *& request); + void PushResponse(void * args, BaseResponse * response); + int PluckResponse(void *& args, BaseResponse *& response); bool CanPushRequest(const int max_queue_length); bool CanPluckResponse(); void BreakOut(); -private: + private: struct QueueExtData { QueueExtData() { enqueue_time_ms = 0; @@ -67,20 +71,20 @@ class DataFlow { uint64_t enqueue_time_ms; void * args; }; - ThdQueue > in_queue_; - ThdQueue > out_queue_; + ThdQueue > in_queue_; + ThdQueue > out_queue_; }; ///////////////////////////////// -#define RPC_TIME_COST_CAL_RATE 1000 -#define QUEUE_WAIT_TIME_COST_CAL_RATE 1000 +#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 +#define MAX_ACCEPT_QUEUE_LENGTH 102400 -class HshaServerStat { -public: - HshaServerStat(const HshaServerConfig * config, ServerMonitorPtr hsha_server_monitor); +class HshaServerStat final { + public: + HshaServerStat(const HshaServerConfig *config, ServerMonitorPtr hsha_server_monitor); ~HshaServerStat(); void CalFunc(); @@ -94,7 +98,7 @@ class HshaServerStat { uint64_t now_time_ms_; }; -private: + private: void MonitorReport(); friend class HshaServerIO; @@ -102,7 +106,7 @@ class HshaServerStat { friend class Worker; friend class HshaServerQos; friend class HshaServerAcceptor; - const HshaServerConfig * config_; + //const HshaServerConfig *config_; std::mutex mutex_; std::condition_variable cv_; std::thread thread_; @@ -170,15 +174,19 @@ class HshaServerStat { 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 { -public: +class HshaServerQos final { + public: HshaServerQos(const HshaServerConfig * config, HshaServerStat * hsha_server_stat); ~HshaServerQos(); @@ -186,7 +194,7 @@ class HshaServerQos { bool CanAccept(); bool CanEnqueue(); -private: + private: const HshaServerConfig * config_; HshaServerStat * hsha_server_stat_; std::mutex mutex_; @@ -199,46 +207,67 @@ class HshaServerQos { ////////////////////////////////// -class Worker { -public: - Worker(WorkerPool * pool); +class Worker final { + public: + Worker(WorkerPool *pool, int uthread_count, int utherad_stack_size); ~Worker(); - void Func(); + void Func(); void Shutdown(); -private: - WorkerPool * pool_; + 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 Notify(); + + private: + WorkerPool *pool_; + int uthread_count_; + int utherad_stack_size_; bool shut_down_; + UThreadEpollScheduler *worker_scheduler_; 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); +typedef std::function Dispatch_t; + +class WorkerPool final { + public: + WorkerPool(UThreadEpollScheduler * scheduler, + int thread_count, + int uthread_count_per_thread, + int utherad_stack_size, + DataFlow * data_flow, + HshaServerStat * hsha_server_stat, + Dispatch_t dispatch, + void * args); ~WorkerPool(); -private: + void Notify(); + + private: friend class Worker; UThreadEpollScheduler * scheduler_; DataFlow * data_flow_; HshaServerStat * hsha_server_stat_; Dispatch_t dispatch_; - DispatcherArgs_t dispatcher_args_; + void * args_; std::vector worker_list_; + size_t last_notify_idx_; + std::mutex mutex_; }; ///////////////////////////////// -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(int idx, UThreadEpollScheduler * scheduler, const HshaServerConfig * config, + DataFlow * data_flow, HshaServerStat * hsha_server_stat, HshaServerQos * hsha_server_qos, + WorkerPool * worker_pool); ~HshaServerIO(); void RunForever(); @@ -249,16 +278,17 @@ class HshaServerIO { void IOFunc(int accept_fd); - UThreadSocket_t * ActiveSocketFunc(); + UThreadSocket_t *ActiveSocketFunc(); -private: - int idx_; + private: + //int idx_; UThreadEpollScheduler * scheduler_; const HshaServerConfig * config_; DataFlow * data_flow_; - int listen_fd_; + //int listen_fd_; HshaServerStat * hsha_server_stat_; HshaServerQos * hsha_server_qos_; + WorkerPool * worker_pool_; std::queue accepted_fd_list_; std::mutex queue_mutex_; @@ -267,42 +297,48 @@ class HshaServerIO { ///////////////////////////////// class HshaServer; -class HshaServerUnit { -public: - HshaServerUnit(HshaServer * hsha_server, int idx, int worker_thread_count, Dispatch_t dispatch, void * args); +class HshaServerUnit final { + public: + HshaServerUnit(HshaServer *hsha_server, + int idx, + int worker_thread_count, + int worker_uthread_count_per_thread, + int worker_utherad_stack_size, + Dispatch_t dispatch, + void *args); ~HshaServerUnit(); void RunFunc(); bool AddAcceptedFd(int accepted_fd); -private: - HshaServer * hsha_server_; + private: + HshaServer *hsha_server_; UThreadEpollScheduler scheduler_; DataFlow data_flow_; - HshaServerIO hsha_server_io_; WorkerPool worker_pool_; + HshaServerIO hsha_server_io_; std::thread thread_; }; ///////////////////////////////// -class HshaServerAcceptor { -public: +class HshaServerAcceptor final { + public: HshaServerAcceptor(HshaServer * hsha_server); ~HshaServerAcceptor(); void LoopAccept(const char * bind_ip, const int port); -private: + private: HshaServer * hsha_server_; size_t idx_; }; ///////////////////////////////// -class HshaServer { -public: - HshaServer(const HshaServerConfig & config, Dispatch_t dispatch, void * args); +class HshaServer final { + public: + HshaServer(const HshaServerConfig &config, Dispatch_t dispatch, void *args); ~HshaServer(); void RunForever(); @@ -316,4 +352,6 @@ class HshaServer { std::vector server_unit_list_; }; -} //namespace phxrpc + +} //namespace phxrpc + diff --git a/phxrpc/rpc/http_caller.cpp b/phxrpc/rpc/http_caller.cpp index c177ee8..f2a9205 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 *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..bb1341f 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 *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..249f615 --- /dev/null +++ b/phxrpc/rpc/mqtt_caller.cpp @@ -0,0 +1,199 @@ +/* +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() { +} + +MqttConnect &MqttCaller::GetConnect() { + return connect_; +} + +MqttPublish &MqttCaller::GetPublish() { + return publish_; +} + +MqttDisconnect &MqttCaller::GetDisconnect() { + return disconnect_; +} + +MqttConnack &MqttCaller::GetConnack() { + return connack_; +} + +MqttPuback &MqttCaller::GetPuback() { + return puback_; +} + +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 &connect, + phxrpc::MqttConnackPb *connack) { + int ret{-1}; + + // unpack request + { + ret = static_cast(connect_.FromPb(connect)); + 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(connack)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "ToPb ret %d", ret); + + return ret; + } + } + + return ret; +} + +int MqttCaller::PhxMqttPublishCall(const phxrpc::MqttPublishPb &publish, + phxrpc::MqttPubackPb *puback) { + int ret{-1}; + + // unpack request + { + ret = static_cast(publish_.FromPb(publish)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "FromPb err %d", ret); + + return ret; + } + } + + uint64_t call_begin{Timer::GetSteadyClockMS()}; + MqttClient::MqttStat mqtt_stat; + publish_.set_packet_identifier(packet_identifier_++); + ret = MqttClient::Publish(socket_, publish_, puback_, mqtt_stat); + MonitorReport(client_monitor_, mqtt_stat.send_error_, + mqtt_stat.recv_error_, publish_.GetContent().size(), + puback_.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(puback_.ToPb(puback)); + if (0 != ret) { + phxrpc::log(LOG_ERR, "ToPb ret %d", ret); + + return ret; + } + } + + return ret; +} + +int MqttCaller::PhxMqttDisconnectCall(const phxrpc::MqttDisconnectPb &disconnect) { + int ret{-1}; + + // unpack request + { + ret = static_cast(disconnect_.FromPb(disconnect)); + 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::SetCmdId(const int cmd_id) { + cmd_id_ = cmd_id; +} + + +} // namespace phxrpc + diff --git a/phxrpc/rpc/mqtt_caller.h b/phxrpc/rpc/mqtt_caller.h new file mode 100644 index 0000000..7b5e10d --- /dev/null +++ b/phxrpc/rpc/mqtt_caller.h @@ -0,0 +1,89 @@ +/* +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 MessageLite; + + +} + +} + + +namespace phxrpc { + + +class BaseTcpStream; + +class MqttCaller { + public: + MqttCaller(BaseTcpStream &socket, ClientMonitor &client_monitor); + + virtual ~MqttCaller(); + + MqttConnect &GetConnect(); + MqttPublish &GetPublish(); + MqttDisconnect &GetDisconnect(); + + MqttConnack &GetConnack(); + MqttPuback &GetPuback(); + + int PhxMqttConnectCall(const phxrpc::MqttConnectPb &connect, + phxrpc::MqttConnackPb *connack); + int PhxMqttPublishCall(const phxrpc::MqttPublishPb &publish, + phxrpc::MqttPubackPb *puback); + int PhxMqttDisconnectCall(const phxrpc::MqttDisconnectPb &disconnect); + + void SetCmdId(const int cmd_id); + + 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_; + + MqttConnect connect_; + MqttConnack connack_; + MqttPublish publish_; + MqttPuback puback_; + MqttDisconnect disconnect_; + + uint16_t packet_identifier_{1}; +}; + + +} // namespace phxrpc + diff --git a/phxrpc/rpc/phxrpc.proto b/phxrpc/rpc/phxrpc.proto index d9853e8..b25d1a6 100644 --- a/phxrpc/rpc/phxrpc.proto +++ b/phxrpc/rpc/phxrpc.proto @@ -1,12 +1,40 @@ -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 { + bool clean_session = 1; + uint32 keep_alive = 2; + string client_identifier = 3; + string proto_name = 4; + uint32 proto_level = 5; +} + +message MqttConnackPb { + bool session_present = 1; + uint32 connect_return_code = 2; +} + +message MqttPublishPb { + uint32 package_identifier = 1; + string topic_name = 2; + string content = 3; +} + +message MqttPubackPb { + uint32 package_identifier = 1; +} + +message MqttDisconnectPb { } diff --git a/phxrpc/rpc/server_base.cpp b/phxrpc/rpc/server_base.cpp new file mode 100644 index 0000000..8d00f75 --- /dev/null +++ b/phxrpc/rpc/server_base.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 "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..95a1719 100644 --- a/phxrpc/rpc/server_base.h +++ b/phxrpc/rpc/server_base.h @@ -22,19 +22,27 @@ See the AUTHORS file for names of contributors. #pragma once #include "server_monitor.h" +#include "phxrpc/network.h" namespace phxrpc { typedef struct tagDispatcherArgs { phxrpc::ServerMonitorPtr server_monitor; + phxrpc::UThreadEpollScheduler * server_worker_uthread_scheduler; void * service_args; tagDispatcherArgs() : service_args(NULL) { } - tagDispatcherArgs( phxrpc::ServerMonitorPtr monitor, void * args ) : - server_monitor(monitor), service_args(args) { + tagDispatcherArgs(phxrpc::ServerMonitorPtr monitor, + phxrpc::UThreadEpollScheduler * uthread_scheduler, void * args) : + server_monitor(monitor), server_worker_uthread_scheduler(uthread_scheduler), service_args(args) { } -}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..108aa71 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,8 +24,10 @@ 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; @@ -37,7 +39,7 @@ ServerConfig::ServerConfig() { 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; @@ -48,6 +50,9 @@ bool ServerConfig::Read(const char * config_file) { succ &= config.ReadItem("Server", "Port", &port_); succ &= config.ReadItem("Server", "PackageName", package_name_, sizeof(package_name_)); config.ReadItem("Server", "MaxThreads", &max_threads_, 20); + // 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_, 5000); if (succ) { @@ -58,15 +63,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_; } @@ -94,64 +99,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..35a8a45 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,23 +21,26 @@ 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; @@ -48,23 +51,31 @@ class ServerConfig { 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 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); void SetMaxConnections(const int max_connections); int GetMaxConnections() const; @@ -75,15 +86,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..3330178 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,29 @@ 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), + protocol_(protocol), uri_(uri), - cmdid_(cmdid), + cmd_id_(cmd_id), ep_(ep), mconnect_timeout_ms(connect_timeout_ms), msocket_timeout_ms(socket_timeout_ms), @@ -50,27 +61,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 +94,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 +132,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 +148,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..8458186 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,111 @@ 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_; + Protocol protocol_; + 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 "; } + }