This is my Java code.
class NativePrompt {
private native String getInput(String prompt); //native method
static //static initializer code
{
System.loadLibrary("NativePrompt");
}
public static void main(String[] args)
{
NativePrompt NP = new NativePrompt();
String sName = NP.getInput("Enter your name: ");
System.out.println("Hello " + sName);
}
}
I'm using jdk1.7.0_17 .
This is my c++ code
#include "NativePrompt.h"
#include "jni.h"
#include "string"
#include "iostream"
#include "vector"
using namespace std;
/*
* Class: NativePrompt
* Method: getInput
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_NativePrompt_getInput
(JNIEnv *env, jobject obj, jstring prompt){
string sEntry;
const char *str;
str = env->GetStringUTFChars(prompt, NULL);
if (str == NULL) {
return env->NewStringUTF("");
}
else{
cout << str;
//Frees native string resources
env->ReleaseStringUTFChars(prompt, str);
//reads n-consecutive words from the
//keyboard and store them in string
getline(cin, sEntry);
return env->NewStringUTF(sEntry.c_str());
}
}
I run this program using the below comments.
javac NativePrompt.java
javah NativePrompt
g++ -o NativePrompt.so -shared -I /usr/lib/jvm/jdk1.7.0_17/include -I
/usr/lib/jvm/jdk1.7.0_17/include/linux NativePrompt.cpp
export LD_LIBRARY_PATH='/home/user/jniwork/'
java NativePrompt
Now I'm getting the below error. I don't know how to resolve it .
Exception in thread "main" java.lang.UnsatisfiedLinkError: no
NativePrompt in java.library.path at
java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860) at
java.lang.Runtime.loadLibrary0(Runtime.java:845) at
java.lang.System.loadLibrary(System.java:1084) at
NativePrompt.(NativePrompt.java:5)
try launching your application like this:
java -Djava.library.path=/home/user/jniwork/ NativePrompt
and also before, rename your library from NativePrompt.so to libNativePrompt.so
Hope this helps you out.
Related
I am writing a gRPC code which is going to converted to .so file and using that shared library I am going to call the service from a mySQl UDF. This is my client.cc:
#include <grpcpp/grpcpp.h>
#include <string>
#include "stringreverse.grpc.pb.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using stringreverse::StringReply;
using stringreverse::StringRequest;
using stringreverse::StringReverse;
class StringReverseClient {
public:
StringReverseClient(std::shared_ptr<Channel> channel)
: stub_(StringReverse::NewStub(channel)) {}
// Assembles client payload, sends it to the server, and returns its response
std::string sendRequest(std::string a) {
// Data to be sent to server
StringRequest request;
request.set_original(a);
// Container for server response
StringReply reply;
// Context can be used to send meta data to server or modify RPC behaviour
ClientContext context;
// Actual Remote Procedure Call
Status status = stub_->sendRequest(&context, request, &reply);
// Returns results based on RPC status
if (status.ok()) {
return reply.reversed();
} else {
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC Failed";
}
}
private:
std::unique_ptr<StringReverse::Stub> stub_;
};
extern "C" std::string RunClient() {
std::string target_address("0.0.0.0:50051");
// Instantiates the client
StringReverseClient client(
// Channel from which RPCs are made - endpoint is the target_address
grpc::CreateChannel(target_address,
// Indicate when channel is not authenticated
grpc::InsecureChannelCredentials()));
std::string response;
std::string a = "grpc is cool!";
// RPC is created and response is stored
response = client.sendRequest(a);
// Prints results
std::cout << "Original string: " << a << std::endl;
std::cout << "Reversed string: " << response << std::endl;
return response;
}
extern "C" int main(int argc, char* argv[]) {
RunClient();
return 0;
}
this is my stringreverse.proto
syntax = "proto3";
package stringreverse;
// The string reversal service definition.
service StringReverse {
// Function invoked to send the request
rpc sendRequest (StringRequest) returns (StringReply) {}
}
// The request message containing the original string
message StringRequest {
string original = 1;
}
// The response message containing the reversed string
message StringReply {
string reversed = 1;
}
and this is my UDF.cc
extern "C" std::string stringreverse(UDF_INIT *initid, UDF_ARGS *args,
std::string result, unsigned long *length,
char *is_null, char *error)
{
void* handle = dlopen("./libclient_lib.so", RTLD_LAZY);
if (handle == NULL)
{
fprintf(stderr, " %s\n", dlerror());
}
// load the symbol
typedef std::string (*RunClient_t)();
RunClient_t RunClient = (RunClient_t) dlsym(handle, "RunClient");
result=RunClient();
dlclose(handle);
return result;
}
extern "C" bool stringreverse_init (UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return 0;
}
extern "C" void stringreverse_init_deinit (UDF_INIT *initid)
{
return;
}
This is server.cc:
#include <grpcpp/grpcpp.h>
#include <string>
#include "stringreverse.grpc.pb.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using stringreverse::StringReply;
using stringreverse::StringRequest;
using stringreverse::StringReverse;
// Server Implementation
class ReverseServiceImplementation final : public
StringReverse::Service {
Status sendRequest(ServerContext* context, const StringRequest*
request,
StringReply* reply) override {
// Obtains the original string from the request
std::string a = request->original();
// String reversal
int n = a.length();
for (int i = 0; i < n / 2; i++) std::swap(a[i], a[n - i - 1]);
reply->set_reversed(a);
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
ReverseServiceImplementation service;
ServerBuilder builder;
// Listen on the given address without any authentication mechanism
builder.AddListeningPort(server_address,
grpc::InsecureServerCredentials());
// Register "service" as the instance through which
// communication with client takes place
builder.RegisterService(&service);
// Assembling the server
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on port: " << server_address <<
std::endl;
server->Wait();
}
int main(int argc, char** argv) {
RunServer();
return 0;
}
and this is CMAkelists.txt:
# Minimum CMake required
cmake_minimum_required(VERSION 3.15)
# Project
project(stringreverse)
# Protobuf
set(protobuf_MODULE_COMPATIBLE TRUE)
find_package(Protobuf CONFIG REQUIRED)
message(STATUS "Using protobuf ${protobuf_VERSION}")
# Protobuf-compiler
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
# gRPC
find_package(gRPC CONFIG REQUIRED)
message(STATUS "Using gRPC ${gRPC_VERSION}")
set(_GRPC_GRPCPP gRPC::grpc++)
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
# Proto file
get_filename_component(hw_proto "stringreverse.proto" ABSOLUTE)
get_filename_component(hw_proto_path "${hw_proto}" PATH)
# Generated sources
set(hw_proto_srcs
"${CMAKE_CURRENT_BINARY_DIR}/stringreverse.pb.cc")
set(hw_proto_hdrs
"${CMAKE_CURRENT_BINARY_DIR}/stringreverse.pb.h")
set(hw_grpc_srcs
"${CMAKE_CURRENT_BINARY_DIR}/stringreverse.grpc.pb.cc")
set(hw_grpc_hdrs
"${CMAKE_CURRENT_BINARY_DIR}/stringreverse.grpc.pb.h")
add_custom_command(
OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}"
"${hw_grpc_srcs}" "${hw_grpc_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
-I "${hw_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${hw_proto}"
DEPENDS "${hw_proto}")
# Include generated *.pb.h files
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
include_directories("/home/sama/grpc/include")
# Targets (client|server)
foreach(_target
client server)
add_executable(${_target} "${_target}.cc"
${hw_proto_srcs}
${hw_grpc_srcs})
target_link_libraries(${_target}
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF})
endforeach()
add_library(client_lib SHARED client.cc)
target_link_libraries(client_lib
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF}})
First I create libclient_lib.so from my client.cc then use it in my UDF, but I get error ./libclient_lib.so: undefined symbol: _ZTVN13stringreverse13StringReverse4Stub5asyncE Segmentation fault (core dumped)
Could you please tell me how can I sole the problem with stringreverse.grpc.pb.h.
client_lib looks like a shared-object which should have complete symbols. You can try to add ${hw_proto_srcs} to client_lib.
First of all I'm not very experienced with C++, so maybe I'm overseeing something here.
I'm trying to dynamically generate protobuf Messages from .proto files with the following code:
int init_msg(const std::string & filename, protobuf::Arena* arena, protobuf::Message** new_msg){
using namespace google::protobuf;
using namespace google::protobuf::compiler;
DiskSourceTree source_tree;
source_tree.MapPath("file", filename);
MuFiErCo error_mist;
Importer imp(&source_tree, &error_mist);
printf("Lade Datei:%s \n", filename.c_str());
const FileDescriptor* f_desc = imp.Import("file");
const Descriptor* desc = f_desc->FindMessageTypeByName("TestNachricht");
const Message* new_msg_proto = dmf.GetPrototype(desc);
*new_msg = new_msg_proto->New(arena);
//Debug
cout << (*new_msg)->GetTypeName() << endl;
return 0;
}
int main(int argc, char* argv[]){
protobuf::Arena arena;
protobuf::Message *adr2, *adr1;
init_msg("schema-1.proto", &arena, &adr1);
init_msg("schema-1.proto", &arena, &adr2);
printf("MSG_Pointer: %p, %p\n", adr1, adr2);
cout << adr1->GetTypeName() << endl;
arena.Reset();
return 0;
}
I thought if i use Arena, the new Message is also available outside the scope of the function.
But there is always a segfault if i try to access the Message.
I guess it's a simple error, but I couldn't figure out, how to solve this.
Here is the ouput:
Lade Datei:schema-1.proto
packet.TestNachricht
Lade Datei:schema-1.proto
packet.TestNachricht
MSG_Pointer: 0x1b293b0, 0x1b287f0
Speicherzugriffsfehler (Speicherabzug geschrieben)
The problem, I think, is that FileDescriptor et al are destroyed when
init_msg returns, leaving the newly created message with no way to
interrogate its .proto definition. You'd need to move Importer
instance to main and keep it alive. This has nothing to do with
arenas. – Igor Tandetnik
That was the solution.
Here is some working example code
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <memory>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/arena.h>
using namespace std;
using namespace google::protobuf;
class MuFiErCo : public compiler::MultiFileErrorCollector
{
public:
void AddError(const string & filename, int line, int column, const string & message){
printf("Err: %s\n", message.c_str());
}
void AddWarning(const string & filename, int line, int column, const string & message){
printf("Warn: %s\n", message.c_str());
}
};
compiler::Importer* init_proto_dir(Arena* arena, const std::string &root_dir){
using namespace compiler;
static DiskSourceTree source_tree;
source_tree.MapPath("", root_dir);
static MuFiErCo error_mist;
static Importer* imp = Arena::Create<Importer>(arena, &source_tree, &error_mist);
return imp;
}
void init_proto_def(compiler::Importer* imp, const std::string &proto_file){
using namespace compiler;
imp->Import(proto_file);
return;
}
Message* init_msg(compiler::Importer* imp, Arena* arena, const std::string &msg_name){
const DescriptorPool* pool = imp->pool();
static DynamicMessageFactory dmf;
const Descriptor* desc = pool->FindMessageTypeByName(msg_name);
const Message* msg_proto = dmf.GetPrototype(desc);
return msg_proto->New(arena);
}
int set_value(Message* msg, const char* value_name, unsigned long int value){
const Message::Reflection* reflec = msg->GetReflection();
const Descriptor* desc = msg->GetDescriptor();
const FieldDescriptor* fdesc = desc->FindFieldByName(value_name);
reflec->SetUInt64(msg, fdesc, value);
return 0;
}
int main(int argc, char* argv[]){
Arena arena;
compiler::Importer* imp = init_proto_dir(&arena, "");
init_proto_def(imp, "schema-1.proto");
Message* msg = init_msg(imp, &arena, "packet.TestNachricht");
set_value(msg, "zahl", 23434);
cout << msg->DebugString() << endl;
return 0;
}
I have just started using visualgdb
#include <string.h>
#include <jni.h>
#include <stdio.h>
int s_ButtonPressCounter = 0;
jstring
Java_com_visualgdb_example_AndroidProject1_AndroidProject1_stringFromJNI( JNIEnv* env,
jobject thiz )
{
char szBuf[512];
sprintf(szBuf, "You have pressed this huge button %d times", s_ButtonPressCounter++);
jstring str = (*env)->NewStringUTF(env, szBuf);
return str;
}
I have my intelissense show error log
Expression must have pointer type.
I tried to change it to env.NewStringUTF(szBuf) but the build comes to error.
Maybe, you should replace
jstring str = (*env)->NewStringUTF(env, szBuf);
with
jstring str = env->NewStringUTF(env, szBuf);
or with
jstring str = (*env).NewStringUTF(env, szBuf);
It's me again probably asking noob C++ questions
I had MAJOR headaches making the darn (sorry for the language) MySQL C++ connector work. I don't know if it is poorly written or something, but for my experience yet I've never had so much trouble making something to work.
Anyhow I got it to connect and throw exceptions on failed connect/query which for me is quite big thing :U :P . The actual problem comes out of me obtaining the result of the query. Regardless of what I do my application always crashes :S
I used the 32-bit installer and the libmysql.dll/lib from the 32-bit MySQL server (since i'm compiling a 32-bit application i figured this is the right thing to do)
Here's some code so you could imagine what I'm talking about
DBManager.h
#ifndef DBMANAGER_H
#define DBMANAGER_H
#define CPPCONN_PUBLIC_FUNC
#define CPPCONN_LIB_BUILD True
#include <string>
#include "mysql_connection.h"
#include "mysql_driver.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
class DBManager
{
public:
static DBManager* Instance();
bool Query(const char* Query);
void Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName);
bool ValidCredentials(const char* Username, const char* Password);
void ManageException(sql::SQLException &e);
~DBManager();
protected:
static DBManager* pInstance;
private:
DBManager() {};
DBManager(DBManager const&){};
DBManager& operator=(DBManager const&){};
sql::mysql::MySQL_Driver* driver;
sql::Connection *Con;
sql::PreparedStatement *pstmt;
sql::ResultSet *res;
sql::Statement *stmt;
bool isConnected;
};
#endif
And now the cpp file DBManager.cpp
#include "DBManager.h"
DBManager* DBManager::pInstance = NULL;
DBManager* DBManager::Instance()
{
if (!pInstance)
{
pInstance = new DBManager();
}
return pInstance;
}
bool DBManager::Query(const char* Query)
{
return true;
}
DBManager::~DBManager()
{
delete Con;
delete pstmt;
delete res;
delete stmt;
}
void DBManager::ManageException(sql::SQLException& e)
{
if (e.getErrorCode() != 0) {
std::cout << "# ERR: SQLException in " << __FILE__;
std::cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << std::endl;
std::cout << "# ERR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl;
}
}
void DBManager::Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName)
{
try {
driver = sql::mysql::get_mysql_driver_instance();
std::string connDSN = "tcp://" + std::string(DbHost) + ":3306";
Con = driver->connect(connDSN, sql::SQLString(DbUser), sql::SQLString(DbPass));
Con->setSchema(sql::SQLString(DbName));
isConnected = true;
std::cout<<"Database connection successul."<<std::endl;
} catch(sql::SQLException &e) {
ManageException(e);
isConnected = false;
return;
}
}
bool DBManager::ValidCredentials(const char* Username, const char* Password)
{
bool cred = false;
try {
pstmt = Con->prepareStatement("SELECT * FROM account WHERE account_name=? LIMIT 1"); // Smart use of indexing
pstmt->setString(1, Username);
res = pstmt->executeQuery();
while(res->next())
{
if (res->getString("password") == Password)
{
cred = true;
}
}
}
catch(sql::SQLException &e) {
ManageException(e);
return false;
}
return cred;
}
Basically, It compiles without a problem, Connects without a problem, Executes queries without a problem, but the second I try to retrieve data some breakpoint exception is thrown in a file "xutils.cpp". I really have no idea what I'm doing wrong. I'm using the DEBUG libraries while compiling for debug. Hmm libmysql.dll should be release since I extracted it from the server bundle, but I don't seem to find it as a source to compile my own.
I really have no idea why it crashes and burn like that :/
PS: Don't mind the no hashing of the password, it really is just a proof of concept to me in the way of ... getting it to work first, then securing it :U
PS: I also have Boost libraries compiled and ready in the project, if that would help :U
EDIT: Main function
bool ServerRunning = true;
int main(int argc, char** argv)
{
#ifdef _WIN32
std::string title = TEXT("Window Title Change");
SetConsoleTitle(title.c_str());
#endif;
std::cout<<"Loading Configuration File..."<<std::endl<<std::endl;
std::string path = boost::filesystem::path(boost::filesystem::current_path()).string();
path += "\\Config.ini";
INIParser* Config = new INIParser(path.c_str()); //MinINI
// Sockets data
std::string listenIP = Config->GetString("Network", "ListenIP", "127.0.0.1");
unsigned short listenPort = Config->GetInt("Network", "ListenPort", 5000);
// Database data
std::string dbHost = Config->GetString("Database", "Host", "localhost");
std::string dbUser = Config->GetString("Database", "User", "root");
std::string dbPass = Config->GetString("Database", "Password", "");
std::string dbName = Config->GetString("Database", "Database", "authserv");
unsigned short dbPort = Config->GetInt("Database", "Post", 1000);
// General settings
int sessionTimeout = Config->GetInt("Settings", "SessionTimeout", 10);
int maxClients = Config->GetInt("Settings", "MaxClients", 10);
int serverTimeout = Config->GetInt("Settings", "GameserverTimeout", 1);
// Begin Initialization
DBManager::Instance()->Connect(dbHost.c_str(), dbPort, dbUser.c_str(), dbPass.c_str(), dbName.c_str());
bool loginSuccess = DBManager::Instance()->ValidCredentials("Username", "Password");
char c;
while (ServerRunning)
{
std::cin>>c;
if (c == 'q')
{
ServerRunning = false;
}
}
return 0;
}
Assuming the password field is defined as varchar in the database, you cannot use getString() to retrieve it. You must instead use the blob function, getBlob().
This is how the while loop would look:
while(res->next())
{
std::istream * retrievedPassword_stream = res->getBlob("password");
if (retrievedPassword_stream)
{
char pws[PASSWORD_LENGTH+1]; // PASSWORD_LENGTH defined elsewhere; or use other functions to retrieve it
retrievedPassword_stream->getline(pws, PASSWORD_LENGTH);
std::string retrievedPassword(pws); // also, should handle case where Password length > PASSWORD_LENGTH
if (retrievedPassword == std::string(Password))
{
cred = true;
}
}
}
Side comments: Note that there are some other issues with the code.
The statement handle must be deleted, so you should do a delete pstmt; at the appropriate place in the ValidCredentials() function (rather than in the destructor). (But, why use a prepared statement in that case anyways? Better to initialize the prepared statement in the constructor (or somewhere else outside the function the query is called), as well as delete in the destructor or elsewhere, if you do use a prepared statement. Instead of a prepared statement, though, note that prepared statements are most useful for very high-use and high-CPU intensive queries, so using it for password validation might not be important here (you could just execute a regular query, instead of a prepared statement).)
Likewise, the ResultSet needs to be deleted (delete res) at the end of the try block, rather than in the destructor.
Be sure to check for NULL before using pstmt, res, or Con.
stmt appears to be unused and should not be deleted.
download mysql c++ connector
compile mysqlcppconn-static project use mt or mtd
your project add CPPCONN_LIB_BUILD
your project add (2) built static library
I am writing a simple client / server program to mess around with socket programming. I made two classes, one for the client and one for the server. I can run my server with no problems and also my client can connect. But now I am attempting to modify my client so it accepts the hostname and port number in the constructor.
Here is what I have so far (client.h class only the constructor and attributes):
#ifndef CLIENT_H
#define CLIENT_H
class Client
{
public:
Client(char *in_hostname, int in_port)
: hostname(&in_hostname), port(in_port)
{
}
~Client() {}
private:
char *hostname;
int port;
};
#endif
I am having a hard time setting the char * hostname from the constructor. I am obviously having a little trouble with pointers and references. Can someone help me out here, coding mostly in PHP for the past 5 years has made my C++ rusty...
Here is the C++ file I use the client.h class.
#include <iostream>
#include "client.h"
using namespace std;
int main (int argc, char * const argv[])
{
char * hostname;
int port;
if(argc == 3)
{
hostname = argv[1];
port = argv[2];
Client *client = new Client(hostname, port);
delete(client);
}
else
{
cout << "Usage: ./client hostname port" << endl;
}
return 0;
}
Thanks!
If you're going to be coding in C++ may I suggest using std::string instead of char pointers?
class Client
{
public:
Client(const string& in_hostname, int in_port)
: hostname(in_hostname), port(in_port)
{
}
~Client() {}
private:
std::string hostname;
int port;
};
Edit:
In response to your comment. If you have to pass the pointer around to another function you can get it from std::string::c_str
std::string stuff;
stuff.c_str();
I am having a hard time setting the char * hostname from the constructer.
Change &in_hostname to in_hostname
Client(char *in_hostname, int in_port)
: hostname(in_hostname), port(in_port)
{
}
However if you want your code to be clean you should use std::string (C++ style string) instead of (char *) i.e C style string
class Mahasiswa{
public:
char nama[1000];
double tinggi,berat,imb;
Mahasiswa *next;
Mahasiswa(char* nama,double tinggi,double berat){
Mahasiswa::nama = nama;
Mahasiswa::tinggi = tinggi;
Mahasiswa::berat = berat;
}
double HasilBmi(){
double tinggi_meter = tinggi / 100;
imb = berat/(tinggi_meter*tinggi_meter);
return imb;
}
char* Getname(char* nama){
return nama;
}
};