I am implementing a thrift-based (0.4.0) service in C++ at the moment and encountered a question:
Is there a way to get the client's IP address from inside a service method implementation? I am using a TNonblockingServer.
Thanks in advance!
In TNonblockingServer, When TProcessor::process() is called the TProtocol.transport is a TMemoryBuffer, so aquiring client ip address is impossible.
But We can extend class TServerEventHandler, method TServerEventHandler::processContext() is called when a client is about to call the processor.
static boost::thread_specific_ptr<std::string> thrift_client_ip; // thread specific
class MyServerEventHandler : public TServerEventHandler
{
virtual void processContext(void* serverContext, boost::shared_ptr<TTransport> transport)
{
TSocket *sock = static_cast<TSocket *>(transport.get());
if (sock)
{
//thrift_client_ip.reset(new string(sock->getPeerAddress())); // 0.9.2, reused TNonblockingServer::TConnection return dirty address, see https://issues.apache.org/jira/browse/THRIFT-3270
sock->getCachedAddress(); // use this api instead
}
}
};
// create nonblocking server
TNonblockingServer server(processor, protocolFactory, port, threadManager);
boost::shared_ptr<MyServerEventHandler> eventHandler(new MyServerEventHandler());
server.setServerEventHandler(eventHandler);
Ticket THRIFT-1053 describes a similar request for Java. The solution is basically to allow access to the inner (endpoint) transport and retrieve the data from it. Without having it really tested, building a similar solution for C++ should be easy. Since you are operating on Thrift 0.4.0, I'd strongly recommend to look at current trunk (0.9.3) first. The TBufferedTransport, TFramedTransport and TShortReadTransport already implement
boost::shared_ptr<TTransport> getUnderlyingTransport();
so the patch mentioned above may not be necessary at all.
Your TProcessor-derived class gets a hold of both transports when process() gets called. If you overwrite that method you should be able to manage access to the data you are interested in:
/**
* A processor is a generic object that acts upon two streams of data, one
* an input and the other an output. The definition of this object is loose,
* though the typical case is for some sort of server that either generates
* responses to an input stream or forwards data from one pipe onto another.
*
*/
class TProcessor {
public:
// more code
virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
boost::shared_ptr<protocol::TProtocol> out,
void* connectionContext) = 0;
// more code
#ifndef NONBLOCK_SERVER_EVENT_HANDLER_H
#define NONBLOCK_SERVER_EVENT_HANDLER_H
#include <thrift/transport/TSocket.h>
#include <thrift/server/TServer.h>
namespace apache{
namespace thrift{
namespace server{
class ServerEventHandler:public TServerEventHandler{
void* createContext(boost::shared_ptr<TProtocol> input, boost::shared_ptr<TProtocol> output){
(void)input;
(void)output;
return (void*)(new char[32]);//TODO
}
virtual void deleteContext(void* serverContext,
boost::shared_ptr<TProtocol>input,
boost::shared_ptr<TProtocol>output) {
delete [](char*)serverContext;
}
virtual void processContext(void *serverContext, boost::shared_ptr<TTransport> transport){
TSocket *tsocket = static_cast<TSocket*>(transport.get());
if(socket){
struct sockaddr* addrPtr;
socklen_t addrLen;
addrPtr = tsocket->getCachedAddress(&addrLen);
if (addrPtr){
getnameinfo((sockaddr*)addrPtr,addrLen,(char*)serverContext,32,NULL,0,0) ;
}
}
}
};
}
}
}
#endif
boost::shared_ptr<ServerEventHandler> serverEventHandler(new ServerEventHandler()
server.setServerEventHandler(serverEventHandler);
Related
I'm trying to add proton::work function (opening a new sender) inside the work queue of the proton::connection object. I have a pointer to the working queue, but my problem is how to bind the open_sender function correctly.
I'm aware of the real problem here : the parameter of the function :
sender open_sender(const std::string& addr);
As the string is passed by reference, I have to de-reference it. I'm ok with that, but how to do it with the proton tools ?
Here my line of code :
proton::work w = proton::make_work( &proton::connection::open_sender, &m_connection, p_url);
Note :
Of course I'm not using C++11 in my project, it would be too simple
to ask ;) !
Of course I cannot change to C++11
If you have a better idea on how to create a new sender in a multi-threaded program let me know.
Usually you will use the proton::open_sender API from within the handler for connection open or container start so you will not have to use proton::make_work in most cases. If you look at the Proton C++ examples, a good place to start is simple_send.cpp.
Abbreviated code might look like this:
class simple_send : public proton::messaging_handler {
private:
proton::sender sender;
const std::string url;
const std::string addr;
...
public:
simple_send(...) :
url(...),
addr(...)
{}
...
// This handler is called when the container starts
void on_container_start(proton::container &c) {
c.connect(url);
}
// This handler is called when the connection is open
void on_connection_open(proton::connection& c) {
sender = c.open_sender(addr);
}
...
}
int main() {
...
simple_send send(...);
proton::container(send).run();
...
}
There are other examples that come with Proton C++, that should help you figure out other ways to use Proton C++. See https://github.com/apache/qpid-proton/tree/master/examples/cpp.
There is also API documentation you can find at http://qpid.apache.org/releases/qpid-proton-0.20.0/proton/cpp/api/index.html (for the current release as of February 2018).
I'm currently trying to add some functionality to a basic server application by injecting a DLL and detouring several functions and I'm having a problem with a stored IP address getting corrupted in-between 2 calls.
First I detour 'accept' and parse some values then enter them into a connection class and add it to a list.
Accept detour function:
std::list<Connection*> ConnectionsList;
SOCKET WINAPI MyAccept(SOCKET s, sockaddr *addr, int *addrlen)
{
...
ConnectionsList.push_back(new Connection(ClientSocket, ipstr));
...
}
connection class:
SOCKET s;
char * ipAddress;
char * playerName;
Connection::Connection(SOCKET sock, char * address)
{
s = sock;
ipAddress = address;
}
I've also detoured 'closesocket' at which point I'd like to remove the socket from the list of connections. If I breakpoint on this function the IP address appears to be corrupted.
Does anyone know why this is happening?
ipAddress = address; will just copy the pointer. If something else changes what it points to, you will be in trouble.
Since this is C++ it might be safest to use a std::string.
std::string ipAdreess;
...
ipAddress = address;
Otherwise, stdcpy into a buffer big enough.
BTW, what deletes all the Connection* from the list?
try to protect your ConnectionList etc static/global variable with a lock.
I'm relatively new to the MySQL++ connector in C++, and have an really annoying issue with it already!
I've managed to get stored procedures working, however i'm having issues with the delete statements. I've looked high and low and have found no documentation with examples.
First I thought maybe the code needs to free the query/connection results after calling the stored procedure, but of course MySQL++ doesn't have a free_result method... or does it?
Anyways, here's what I've got:
#include <iostream>
#include <stdio.h>
#include <queue>
#include <deque>
#include <sys/stat.h>
#include <mysql++/mysql++.h>
#include <boost/thread/thread.hpp>
#include "RepositoryQueue.h"
using namespace boost;
using namespace mysqlpp;
class RepositoryChecker
{
private:
bool _isRunning;
Connection _con;
public:
RepositoryChecker()
{
try
{
this->_con = Connection(false);
this->_con.set_option(new MultiStatementsOption(true));
this->_con.set_option(new ReconnectOption(true));
this->_con.connect("**", "***", "***", "***");
this->ChangeRunningState(true);
}
catch(const Exception& e)
{
this->ChangeRunningState(false);
}
}
/**
* Thread method which runs and creates the repositories
*/
void CheckRepositoryQueues()
{
//while(this->IsRunning())
//{
std::queue<RepositoryQueue> queues = this->GetQueue();
if(queues.size() > 0)
{
while(!queues.empty())
{
RepositoryQueue &q = queues.front();
char cmd[256];
sprintf(cmd, "svnadmin create /home/svn/%s/%s/%s", q.GetPublicStatus().c_str(),
q.GetUsername().c_str(), q.GetRepositoryName().c_str());
if(this->DeleteQueuedRepository(q.GetQueueId()))
{
printf("query deleted?\n");
}
printf("Repository created!\n");
queues.pop();
}
}
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
//}
}
protected:
/**
* Gets the latest queue of repositories from the database
* and returns them inside a cool queue defined with the
* RepositoryQueue class.
*/
std::queue<RepositoryQueue> GetQueue()
{
std::queue<RepositoryQueue> queues;
Query query = this->_con.query("CALL sp_GetRepositoryQueue();");
StoreQueryResult result = query.store();
RepositoryQueue rQ;
if(result.num_rows() > 0)
{
for(unsigned int i = 0;i < result.num_rows(); ++i)
{
rQ = RepositoryQueue((unsigned int)result[i][0],
(unsigned int)result[i][1],
(String)result[i][2],
(String)result[i][3],
(String)result[i][4],
(bool)result[i][5]);
queues.push(rQ);
}
}
return queues;
}
/**
* Allows the thread to be shut off.
*/
void ChangeRunningState(bool isRunning)
{
this->_isRunning = isRunning;
}
/**
* Returns the running value of the active thread.
*/
bool IsRunning()
{
return this->_isRunning;
}
/**
* Deletes the repository from the mysql queue table. This is
* only called once it has been created.
*/
bool DeleteQueuedRepository(unsigned int id)
{
char cmd[256];
sprintf(cmd, "DELETE FROM RepositoryQueue WHERE Id = %d LIMIT 1;", id);
Query query = this->_con.query(cmd);
return (query.exec());
}
};
I've removed all the other methods as they're not needed...
Basically it's the DeleteQueuedRepository method which isn't working, the GetQueue works fine.
PS: This is on a Linux OS (Ubuntu server)
Many thanks,
Shaun
MySQL++ doesn't have a free_result method... or does it?
It doesn't need one. When the result object goes out of scope at the end of GetQueue(), all memory associated with it is automatically freed.
this->_con = Connection(false);
Three problems here:
When you create the RepositoryChecker object, you already have created a Connection object. If you need to pass different parameters to its constructor, you'd do that in the initialization list of the RepositoryChecker constructor, not in its body. Read your C++ book.
What you've done here instead is a) create a default Connection object, then b) create a different Connection object with exceptions turned off, then c) overwrite the first with the second. If that works, it's highly inefficient. MySQL++ Connection objects have had problems with their copy ctors in the past, so if you're using an old version of the library, it could explain your problems.
You're telling the Connection object (and every object it creates, even indirectly, which means pretty much everything in MySQL++) you don't want it to throw exceptions, but then you wrap it in a big try block. Pick one.
I'd suggest using exceptions — the default in MySQL++ — given the way your code is currently structured. If there is a query error way down in DeleteQueuedRepository(), there's no way to see what happened because you'd just pass false up to the caller, which is ignored because there is no else clause on the call. If you do this, log the e.what() message in your catch block. You're just throwing that information away right now.
There are several places where you're using constructs that look more like Python (or perhaps JavaScript) than C++. This makes me wonder if your problem isn't damage caused by some other misuse of C++.
On this line in particular, you're using the this pointer explicitly, for which there is no need in C++. This code does exactly the same thing:
_con = Connection(false);
Though again, the line should be replaced entirely, using the RepositoryChecker ctor initializer list instead.
Moving on...
sprintf(cmd, "DELETE FROM RepositoryQueue WHERE Id = %d LIMIT 1;", id);
As others have commented, you'd be better off using the Query stream interface:
Query q = _con.query();
q << "DELETE FROM RepositoryQueue WHERE Id = " << id << " LIMIT 1";
This has several advantages:
Fixes the type safety problem implied by the one who suggested changing your %d to %u. C++ IOStreams take care of that for you.
Automatic quoting of data inserted into the stream, if needed. (Which it isn't, in this case.)
Prevents any possibility of running off the end of the buffer. You could use the nonportable snprintf() instead here, but why?
If you're really happy with printf(), there's the template query interface instead.
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
Have you read the threads chapter in the user manual? You don't get thread safety for free in MySQL++. Your problem could be due to memory corruption.
Warren Young, MySQL++ Maintainer
Try changing "%d" to "%u" in sprintf.
I have a template class with a static function (see Connect function below). This template class is part of a 3rd Party lib (call it LibA). My code uses this lib and includes the header below since I need to use the template class. When I compile my lib without inline functions (-fno-default-inline with gcc) I get no problems. When I compile in release (-O2), my application crashes.
I was wondering what the implications are of having a static function in a template and how inlining may affect this.
template<class T>
class TCPConnector
: public IOHandler {
private:
string _ip;
uint16_t _port;
vector<uint32_t> _protocolChain;
bool _closeSocket;
Variant _customParameters;
public:
TCPConnector(int32_t fd, string ip, uint16_t port,
vector<uint32_t>& protocolChain, const Variant& customParameters)
: IOHandler(fd, IOHT_TCP_CONNECTOR) {
_ip = ip;
_port = port;
_protocolChain = protocolChain;
_closeSocket = true;
_customParameters = customParameters;
}
virtual ~TCPConnector() {
//FINEST("Close socket: %d", _closeSocket);
if (_closeSocket) {
close(_fd);
//FINEST("Socket closed!");
}
}
static bool Connect(string ip, uint16_t port,
vector<uint32_t>& protocolChain, Variant& customParameters) {
protoent *pProtocol = getprotobyname("IP");
if (pProtocol == NULL) {
FATAL("Unable to resolve protocol number for IP");
return 0;
}
int32_t fd = (int32_t) socket(PF_INET, SOCK_STREAM, pProtocol->p_proto);
if (fd <= 0) {
FATAL("Unable to create fd");
return 0;
}
if (!SetFdNonBlock(fd)) {
FATAL("Unable to put socket in non-blocking mode");
return false;
}
TCPConnector<T> *pTCPConnector = new TCPConnector(fd, ip, port,
protocolChain, customParameters);
if (!pTCPConnector->Connect()) {
IOHandlerManager::EnqueueForDelete(pTCPConnector);
FATAL("Unable to connect");
return false;
}
return true;
}
};
I don't think the crash is related to the fact that you use templates, statics or inlining. At least in this particular case.
You should try to find out the cause of the crash, e.g. by analyzing the dump.
You hint that you think the library contains that function. Check if it does. If so, it is definitely an error.
Check that you have the right version of the headers for your library file.
Failing that, the fix to be able to use the library would probably be to erase the definition from the header so it isn't inline any more. That would effectively make it an extern (not export) templated function, so you would only be able to use specialization(s) in the library .o.
As for what you're wondering, a static member function is linked much the same as a free function. If it's inline, it is not possible to call from the library file. Otherwise, static essentially means the same as extern: that there is only one copy, anywhere.
I agree with David Alfonso that the crash can be unrelated to the fact you use this 'library'.
Also this 'library' contains several problems not related to the crash:
It's unclear the purpose of the template parameter T. It doesn't used anywhere.
There are multiple memory and resource leaks in the Connect() method:
pProtocol and pTCPConnector are never deleted;
fd is never closed, because pTCPConnector isn't deleted.
It should not matter. A class static function is about whether you need an instance of the class to call the function or not. Effectively, the primary difference between a non-static method and a static method is the former has an extra 'hidden' function parameter.
Since you are experiencing a crash, have you identified what part of the code is actually causing the crash?
According to the Google Protocol Buffers documentation under 'Defining Services' they say,
it's also possible to use protocol buffers with your own RPC implementation.
To my understanding, Protocol Buffers does not implement RPC natively. Instead, they provide a series of abstract interfaces that must be implemented by the user (Thats me!). So I want to implement these abstract interfaces utilizing ZeroMQ for network communication.
I'm trying to create an RPC implementation using ZeroMQ because the project i'm working on already implements ZeroMQ for basic messaging (Hence why I'm not using gRPC, as the documentation recommends).
After reading through the proto documentation thoroughly, i found that I have to implement the abstract interfaces RpcChannel and RpcController for my own implementation.
I've constructed a minimalized example of where I'm currently at with my RPC Implementation
.proto file: Omitted SearchRequest and SearchResponse schema for brevity
service SearchService {
rpc Search (SearchRequest) returns (SearchResponse);
}
SearchServiceImpl.h:
class SearchServiceImpl : public SearchService {
public:
void Search(google::protobuf::RpcController *controller,
const SearchRequest *request,
SearchResponse *response,
google::protobuf::Closure *done) override {
// Static function that processes the request and gets the result
SearchResponse res = GetSearchResult(request);
// Call the callback function
if (done != NULL) {
done->Run();
}
}
}
};
MyRPCController.h:
class MyRPCController : public google::protobuf::RpcController {
public:
MyRPCController();
void Reset() override;
bool Failed() const override;
std::string ErrorText() const override;
void StartCancel() override;
void SetFailed(const std::string &reason) override;
bool IsCanceled() const override;
void NotifyOnCancel(google::protobuf::Closure *callback) override;
private:
bool failed_;
std::string message_;
};
MyRPCController.cpp - Based off of this
void MyRPCController::Reset() { failed_ = false; }
bool MyRPCController::Failed() const { return failed_; }
std::string MyRPCController::ErrorText() const { return message_; }
void MyRPCController::StartCancel() { }
void MyRPCController::SetFailed(const std::string &reason) {
failed_ = true;
message_ = reason;
}
bool MyRPCController::IsCanceled() const { return false; }
void MyRPCController::NotifyOnCancel(google::protobuf::Closure *callback) { }
MyRPCController::ChiRpcController() : RpcController() { Reset(); }
MyRpcChannel.h:
class MyRPCChannel: public google::protobuf::RpcChannel {
public:
void CallMethod(const google::protobuf::MethodDescriptor *method, google::protobuf::RpcController *controller,
const google::protobuf::Message *request, google::protobuf::Message *response,
google::protobuf::Closure *done) override;
};
Questions I have with my example thus far:
Where do I fit ZeroMQ into this?
It seems like it should be going into RPCChannel, because in the examples i see (See 3rd code block here), they pass a string that has the ports to bind to (i.e. MyRpcChannel channel("rpc:hostname:1234/myservice");)
I'm concerned with my RPCController implementation, it seems too simple. Should more be going here?
How do i implement RPCChannel, it seems very similar to the SearchServiceImpl. The 1 virtual function in these classes has a very similar method signature, except it's generic.
Here's some other Stack Overflow questions I came across that had some helpful information on the topic:
Protobuf-Net: implementing server, rpc controller and rpc channel - This is where i found the example for the RPCController implementation.
Using Protocol Buffers for implementing RPC in ZeroMQ - This answer is interesting because in the top answer, is seems that they're recommending against using Protobufs built in RPC formatting for the .proto file.
I also noticed this same notion in this file, in a repository called libpbrpc which seemed like a good source for example code
Can I/Should I be using an existing implementation such as RPCZ?
Thank you for your help. I hope I gave enough information and was clear in what I'm looking for. Please let me know if something is unclear or lacking in information. I'd be happy to edit the question accordingly.
ZeroMQ provides a low-level API for network communication based on messages that can contain any data.
ProtoBuffers is a library that encodes structured data as compressed binary data and decodes such data.
gRPC is a RPC framework that generates code for network communication based RPC services with functions that exchange data as ProtoBuffers data.
Both ZeroMQ and gRPC provides support for network communication but in different ways. You have to chose either ZeroMQ, either gRPC for network communication.
If you choose ZeroMQ, messages can be encoded using ProtoBuffers exchanging binary structured data.
The main point is ProtoBuffers library allows variant records (similar to C/C++ unions) to be encoded and decoded that can fully emulate the functionality provided by RPC services having functions exchanging ProtoBuffers messages.
So the options are:
Use ZeroMQ with send and receive primitives and ProtoBuffers encoded variant messages that can contain various sub-messages, like
union Request
{
byte msgType;
MessageType1 msg1;
MessageType2 msg2;
MessageType3 msg3;
}
union Response
{
byte msgType;
MessageType3 msg1;
MessageType4 msg2;
MessageType5 msg3;
}
send(Request request);
receive(Response response);
Use gRPC generating a service with functions, like
service MyService
{
rpc function1(MessageType1) returns (Response);
rpc function2(MessageType2) returns (Response);
rpc function3(MessageType3) returns (Response);
rpc functionN(MessageType3) returns (MessageType5);
}
(here it's possible to use many many combinations)
Use just a single-function gRPC service, like
service MyService
{
rpc function(Request) returns (Response);
}
The option could depend on
preferred target for client: ZeroMQ or gRPC based client
performance reasons comparing ZeroMQ vs gRPC based service
specific features like how subscription is used/handled in ZeroMQ vs gRPC based service and client (see How to design publish-subscribe pattern properly in grpc?)
For the 1st option, you have to do a lot of stuff comparing to 2nd option. You have to match the type of message sent with the types of expected messages to be received.
The 2nd option would allow an easier/faster understanding of functionality of the service provided if the somebody else will develop the client.
For developing a RPC service on top on ZeroMQ I would define such .proto file specifying the functions, parameters (all possible input and output parameters) and errors like this:
enum Function
{
F1 = 0;
F2 = 1;
F3 = 2;
}
enum Error
{
E1 = 0;
E2 = 1;
E3 = 2;
}
message Request
{
required Function function = 1;
repeated Input data = 2;
}
message Response
{
required Function function = 1;
required Error error = 2;
repeated Output data = 3;
}
message Input
{
optional Input1 data1 = 1;
optional Input2 data2 = 2;
...
optional InputN dataN = n;
}
message Output
{
optional Output1 data1 = 1;
optional Output2 data2 = 2;
...
optional OutputN dataN = n;
}
message Message
{
repeated Request requests;
repeated Response responses;
}
and depending on function id, at run-time the number and the types of parameters have to be checked.