1 /*
2  *
3  * Copyright 2018 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <atomic>
20 
21 #include <grpc++/grpc++.h>
22 #include <jni.h>
23 
24 #include "helloworld.grpc.pb.h"
25 
26 using grpc::Channel;
27 using grpc::ClientContext;
28 using grpc::Server;
29 using grpc::ServerBuilder;
30 using grpc::ServerContext;
31 using grpc::Status;
32 using helloworld::Greeter;
33 using helloworld::HelloReply;
34 using helloworld::HelloRequest;
35 
36 std::atomic<bool> stop_server(false);
37 
38 // Logic and data behind the server's behavior.
39 class GreeterServiceImpl final : public Greeter::Service {
SayHello(ServerContext * context,const HelloRequest * request,HelloReply * reply)40   Status SayHello(ServerContext* context, const HelloRequest* request,
41                   HelloReply* reply) override {
42     std::string prefix("Hello ");
43     reply->set_message(prefix + request->name());
44     return Status::OK;
45   }
46 };
47 
StartServer(JNIEnv * env,jobject obj,jmethodID is_cancelled_mid,int port)48 void StartServer(JNIEnv* env, jobject obj, jmethodID is_cancelled_mid,
49                  int port) {
50   const int host_port_buf_size = 1024;
51   char host_port[host_port_buf_size];
52   snprintf(host_port, host_port_buf_size, "0.0.0.0:%d", port);
53 
54   GreeterServiceImpl service;
55   ServerBuilder builder;
56   // Listen on the given address without any authentication mechanism.
57   builder.AddListeningPort(host_port, grpc::InsecureServerCredentials());
58   // Register "service" as the instance through which we'll communicate with
59   // clients. In this case it corresponds to an *synchronous* service.
60   builder.RegisterService(&service);
61   // Finally assemble the server.
62   std::unique_ptr<Server> server(builder.BuildAndStart());
63   while (!stop_server.load()) {
64     // Check with the Java code to see if the user has requested the server stop or the app is no
65     // longer in the foreground.
66     jboolean is_cancelled = env->CallBooleanMethod(obj, is_cancelled_mid);
67     if (is_cancelled == JNI_TRUE) {
68       stop_server = true;
69     }
70   }
71 }
72 
73 class GreeterClient {
74  public:
GreeterClient(std::shared_ptr<Channel> channel)75   GreeterClient(std::shared_ptr<Channel> channel)
76       : stub_(Greeter::NewStub(channel)) {}
77 
78   // Assembles the client's payload, sends it and presents the response back
79   // from the server.
SayHello(const std::string & user)80   std::string SayHello(const std::string& user) {
81     // Data we are sending to the server.
82     HelloRequest request;
83     request.set_name(user);
84 
85     // Container for the data we expect from the server.
86     HelloReply reply;
87 
88     // Context for the client. It could be used to convey extra information to
89     // the server and/or tweak certain RPC behaviors.
90     ClientContext context;
91     // The actual RPC.
92     Status status = stub_->SayHello(&context, request, &reply);
93 
94     if (status.ok()) {
95       return reply.message();
96     } else {
97       return status.error_message();
98     }
99   }
100 
101  private:
102   std::unique_ptr<Greeter::Stub> stub_;
103 };
104 
105 // Send an RPC and return the response. Invoked from Java code.
106 extern "C" JNIEXPORT jstring JNICALL
Java_io_grpc_helloworldexample_cpp_HelloworldActivity_sayHello(JNIEnv * env,jobject obj_unused,jstring host_raw,jint port_raw,jstring message_raw)107 Java_io_grpc_helloworldexample_cpp_HelloworldActivity_sayHello(
108     JNIEnv* env, jobject obj_unused, jstring host_raw, jint port_raw,
109     jstring message_raw) {
110   const char* host_chars = env->GetStringUTFChars(host_raw, (jboolean*)0);
111   std::string host(host_chars, env->GetStringUTFLength(host_raw));
112 
113   int port = static_cast<int>(port_raw);
114 
115   const char* message_chars = env->GetStringUTFChars(message_raw, (jboolean*)0);
116   std::string message(message_chars, env->GetStringUTFLength(message_raw));
117 
118   const int host_port_buf_size = 1024;
119   char host_port[host_port_buf_size];
120   snprintf(host_port, host_port_buf_size, "%s:%d", host.c_str(), port);
121 
122   GreeterClient greeter(
123       grpc::CreateChannel(host_port, grpc::InsecureChannelCredentials()));
124   std::string reply = greeter.SayHello(message);
125 
126   return env->NewStringUTF(reply.c_str());
127 }
128 
129 // Start the server. Invoked from Java code.
130 extern "C" JNIEXPORT void JNICALL
Java_io_grpc_helloworldexample_cpp_HelloworldActivity_startServer(JNIEnv * env,jobject obj_this,jint port_raw)131 Java_io_grpc_helloworldexample_cpp_HelloworldActivity_startServer(
132     JNIEnv* env, jobject obj_this, jint port_raw) {
133   int port = static_cast<int>(port_raw);
134 
135   jclass cls = env->GetObjectClass(obj_this);
136   jmethodID is_cancelled_mid =
137       env->GetMethodID(cls, "isRunServerTaskCancelled", "()Z");
138 
139   stop_server = false;
140 
141   StartServer(env, obj_this, is_cancelled_mid, port);
142 }
143