I'm modifying the stock quoter example from the wustl CORBA release. The assignment is to implement a reply handler for the StockFactory class that handles calls to get_stock()
Here's my FactoryHandler implementation:
FactoryHandler_i.h:
#ifndef TAO_TUTORIALS_QUOTER_AMI_CLIENT_FACTORYHANDLER_I_H
#define TAO_TUTORIALS_QUOTER_AMI_CLIENT_FACTORYHANDLER_I_H
#include "QuoterS.h"
class Stock_Factory_Handler_i : public POA_Quoter::AMI_Stock_FactoryHandler
{
public:
Stock_Factory_Handler_i (int *response_count, ::Quoter::Stock_var& result);
void get_stock (::Quoter::Stock_ptr ami_return_val);
void get_stock_excep (::Messaging::ExceptionHolder * excep_holder);
private:
int *response_count_;
::Quoter::Stock_var& result_;
};
#endif /* TAO_TUTORIALS_QUOTER_AMI_CLIENT_HANDLER_I_H */
FactoryHandler_i.cpp:
#include "FactoryHandler_i.h"
#include "ace/streams.h"
Stock_Factory_Handler_i::
Stock_Factory_Handler_i (int *response_count, ::Quoter::Stock_var& result)
: response_count_ (response_count), result_ (result)
{
}
void
Stock_Factory_Handler_i::get_stock (::Quoter::Stock_ptr ami_return_val)
{
cout << "storing result" << endl;
result_ = ami_return_val;
(*this->response_count_)++;
}
void
Stock_Factory_Handler_i::get_stock_excep (::Messaging::ExceptionHolder * excep_holder)
{
// We ignore the exception, but this counts as a response, otherwise
// the application would not finish.
cerr << "Exception raised while getting stock"
<< endl;
(*this->response_count_)++;
}
And the client.cpp, from just before the part where changes have been made:
// ...
// Create and activate the handler...
int response_count = 0;
Single_Query_Stock_Handler_i handler_i (&response_count);
Quoter::AMI_Single_Query_StockHandler_var handler =
handler_i._this ();
// Create and activate the factory handler...
Quoter::Stock_var result;
Stock_Factory_Handler_i factory_handler_i (&response_count, result);
Quoter::AMI_Stock_FactoryHandler_var factory_handler =
factory_handler_i._this();
// Send all the requests, careful with error handling
int request_count = 0;
for (int i = 2; i != argc+1; ++i) {
try {
// Get the stock object
cout << "looking up stock symbol " << argv[i] << endl;
factory->sendc_get_stock (factory_handler.in (), argv[i]);
sleep(3); // wait for a response
cout << "converting result" << endl;
Quoter::Single_Query_Stock_var stock =
Quoter::Single_Query_Stock::_narrow (result.in ());
cout << "checking result" << endl;
CORBA::Any any;
any <<= stock;
CORBA::TypeCode_var tc = any.type();
cout << tc->kind() << endl;
if (CORBA::is_nil (stock.in ())) {
cerr << "Cannot get single query interface for <"
<< argv[i] << ">" << endl;
continue;
}
cout << "reading result" << endl;
stock->sendc_get_price_and_names (handler.in ());
request_count++;
}
catch (Quoter::Invalid_Stock_Symbol &) {
cerr << "Invalid stock symbol <"
<< argv[i] << ">" << endl;
}
}
while (response_count < 2 * request_count // multiply by 2 because both handlers increment response_count
&& orb->work_pending ()) {
orb->perform_work ();
}
// ...
When running the client, the output is:
looking up stock symbol MSFT
converting result
checking result
14
Cannot get single query interface for <MSFT>
(The 14 is the typecode for Stock, that's only for debugging)
Notably missing from the above is the "storing result" message that's supposed to be printed in the FactoryHandler's get_stock() callback method. I'm at a loss as to why, since the sendc_get_stock() method doesn't produce any (immediate) errors and is basically just a copy of the StockHandler's code, and from there it's the responsibility of the AMI/ORB interface to make the callback. But the original example (with a StockHandler only) works fine.
What am I doing wrong (and how do I fix it)?
EDIT: another bit of information: on the server side, StockFactory's get_stock() method does get called.
Sorry, I've no aswer for you. But a hint, ask your question at TOA's maling list at http://www.cs.wustl.edu/~schmidt/ACE-mail.html
HTH
I think that your problem is that work_pending returns true only if the ORB has immediate work to do, so it returns false in the time after your client sent his request and before the server sends his reply.
To validate that, simply remove the && orb->work_pending() condition from the loop, and use the version of perform_work that takes a timeout argument.
Related
i am trying to generate a class for reading from a specific serial device.
For the start process it is necessary to send a char '1', then i have to wait for a response (254 and 255).
Within a period of 10 milliseconds i must sent the next command to the device, but this time the command length is 5 char.
When the communication hasn´t been send in the correct time, the device will run into a timeout and is sending me 255,255,255,2,4.
So i need different sizes of reading and the most importing thing for me is a timeout for the communication, cause otherwise the system will stop working by missing some values.
Therefore i have tried to generate a class using boost::asio::async_read.
It is working in the correct way, i can define the timeout,also the size of bytes to be read. When the device isn´t sending the correct size, the routine is going to be left.
But only the first time, when i try it a second time, the device isn´t sending me something. I have tried to use .open again, but it isn´t solving the issue. Also deactivating the close-function isn´t solving the issue, then the routine is running into an error.
Can someone give me a small tip for my issue. Maybe i am to blind to see my problem.... Bernd
ConnectionWithTimeout::ConnectionWithTimeout(int timeout_)
: timer_(io_service_, boost::posix_time::milliseconds(timeout_))
, serial_port_(io_service_) {
}
void ConnectionWithTimeout::ReadNumberOfChars(int numberOfCharactersToRead_)
{
buffer_.resize(numberOfCharactersToRead_);
for (int i = 0; i < numberOfCharactersToRead_; ++i) {
std::cout << "Clear Buffer[" << i << "]" << std::endl;
buffer_[i] = 0;
}
timer_.async_wait(boost::bind(&::ConnectionWithTimeout::Stop, this));
//async read from serial port
boost::asio::async_read(serial_port_, boost::asio::buffer(buffer_),
boost::bind(&ConnectionWithTimeout::ReadHandle, this,
boost::asio::placeholders::error));
io_service_.run();
}
void ConnectionWithTimeout::Stop() {
std::cout << "Connection is being closed." << std::endl;
serial_port_.close();
std::cout << "Connection has been closed." << std::endl;
}
void ConnectionWithTimeout::ReadHandle(const boost::system::error_code& ec) {
if (ec) {
std::cout << "The amount of data is to low: " << ec << std::endl;
for (std::vector<char>::iterator it = buffer_.begin();
it != buffer_.end(); ++it)
{
std::cout << int(*it) << std::endl;
}
}
else {
std::cout << "The amount of data is correct: " << ec << std::endl;
for (std::vector<char>::iterator it = buffer_.begin(); it !=
buffer_.end(); ++it)
{
std::cout << int(*it) << std::endl;
}
}
}
I'm trying to exchange messages using multiple covert channels.
So, basically, first i need to select the channel that i want to use for communication and then select the "destination_ip" of the user that i want to chat with and after that the
processMessage()
is called. Now, to move from one channel to another I have to close the existing connection and then open a new connection with the new channel that i want to use. My code below is modified to keep using the same channel after closing the connection and contain only the things that you need.
#include <channelmanager.hpp>
#include <thread>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <openssl/hmac.h>
struct CommunicationFixture {
CommunicationFixture() {
channelmanager.setErrorStream(&cout);
channelmanager.setOutputStream(&cout);
destination_ip = "";
channel_id = channelmanager.getChannelIDs()[0];
}
library::ChannelManager channelmanager;
vector<string> last_adapters;
string destination_ip;
string channel_id = "";
int processMessage(string message) {
if (message.compare("exit") == 0) {
channelmanager.closeConnection(destination_ip);
return 1;
}
vector<string> arguments;
boost::split(arguments, message, boost::is_any_of(" "), boost::token_compress_on);
if (arguments[0].compare("argument") == 0) {
if (arguments.size() < 2) {
cout << "Not enough arguments" << endl;
return 0;
}
string argument_list = arguments[1];
for (unsigned int i = 2; i < arguments.size(); i++) {
argument_list += " " + arguments[i];
}
channelmanager.setChannelArguments(destination_ip, argument_list);
cout << "Set channel argument to '" << argument_list << "'." << endl;
return 0;
}
if (message.compare("help") == 0) {
cout << "Help not available in chat mode. Close chat first with 'exit'" << endl;
return 0;
}
channelmanager.openConnection(destination_ip, channel_id);
channelmanager.sendMessage(destination_ip, message);
return 0;
}
int close(string destination){
cout << "closing.." << endl;
channelmanager.closeConnection(destination); //I believe i have the error because of this!
return 0;
}
};
BOOST_FIXTURE_TEST_SUITE(communication, CommunicationFixture)
BOOST_AUTO_TEST_CASE(basic_communication) {
selectAdapterId(0);
cout << "Test" << endl << endl;
printCommands();
cout << "Enter your command:" << endl;
string command;
int code = 0;
while (code != 2) {
std::getline(cin, command);
code = processCommand(command);
if (code == 1) {
// chat
cout << "chat started.." << endl;
int chatCode = 0;
while (chatCode != 1) {
std::getline(cin, message);
close(destination_ip);
chatCode = processMessage(message);
channelmanager.setErrorStream(&cout);
}
cout << "chat ended." << endl;
}
}
}
BOOST_AUTO_TEST_SUITE_END()
Note that, i think that the error happens due to the
function close()
because without it i don't get any errors. and the error doesn't happen immediately but after exchanging some messages. Here's the error:
unknown location(0): fatal error: in
"communication/basic_communication": memory access violation at
address: 0x00000024: no mapping at fault address
communicationTest.cpp(325): last checkpoint: "basic_communication"
test entry
Memory access violation happen when you are trying to access to an unitialized variable, in this case the channelmanager.
I can only see that you initialize channelmanager in the processMessage() method and you are closing the connection before initializing the channelmanager as it happen in:
close(destination_ip);
chatCode = processMessage(message);
Either you change the initialization or do not close it before the processMessage() method.
Memory access violation is also called a segmentation fault (or segfault), occurs when the program tries to access a memory location that doesn't exist, or is otherwise inaccessible. We call this trying to access an illegal memory location. That memory is either non-existent or we aren't aren't allowed to touch it.
If the first input from user is 'exit', which is going to call
if (message.compare("exit") == 0) {
channelmanager.closeConnection(destination_ip);
return 1;
}
In this case, destination_ip isn't initialised.
I have two Libraries: IDA and XIDA.
XIDA handles the event loop, and there is for each application/process, one single event loop.
And these libraries are "connected" via an callback function.
This is working with events inside one single app/process...
Now I noticed that I could send an event from one app to an other. What it needs was a window handle from another app. So I coded a DBus message, with what I can receive one...
This is working too, but it looks like that the receiver of XSendEvent() can only use functions and its parameters, no member variables!
In the hpp:
Window mSection;
Window Section(){
return 0; // This is working
}
Window Section_A(){
return this->mSection; // This raises a memory access error
}
int CheckEvents( IDA_A *vIDA_A, XEvent vEvent);
static int Section_EventCallback(void* this_ptr, XEvent vEvent){
IDA_A* nIDA_A = NULL;
int nRet = 1;
try{
nIDA_A = static_cast < IDA_A* > (this_ptr);
} catch (...) { return 0; }
cout << "TEST " << nIDA_A->Section() << endl; // This is working, also with any other function
cout << "TEST " << nIDA_A->mSection << endl; // This raises a memory access error, also with any other member variable
cout << "TEST " << nIDA_A->Section_A() << endl; // This also raises a memory access error
nRet = nIDA_A->CheckEvents(nIDA_A, vEvent);
nIDA_A = NULL;
return nRet;
}
In the cpp:
int IDA_A::CheckEvents(IDA_A *vIDA_A, XEvent vEvent) {
Window nWindow = vEvent.xany.window;
cout << "TEST " << " -- " << nWindow << endl; // This is working
cout << "TEST " << " -- " << this->mSection << endl; // This raises a memory access error
return 1;
}
What does it needs to use also member variables?
Regards
Earlybite
------------------------ EDIT: ----------------------------
This is the part of XIDA where XSendEvents() arrives (after calling from inside the event loop):
int XIDA_A::Send_To_Callback(XEvent vEvent){
for(int i = 0; i < (int) this->mVecEvCallback.size(); i++){
if( *this->mVecEvCallback[i].pWindow == vEvent.xany.window ){
if( vEvent.type == ClientMessage ) {
cout << "THIS XIDA CLIENT " << this->mIdent << endl;
}
s_EventCallback nEvCallback;
nEvCallback = this->mVecEvCallback[i];
nEvCallback.Callback (nEvCallback.this_Ptr, vEvent);
return 1;
}
}
return 0;
}
And to this point, it is working, also member variables. But nevermore in IDA, where the Callback is going to.
But it is the same process!
And e.g. with DBus it is working...
I really would like to know the reason!
SOLVED.
I found the error...
This
cIDAMessage nMsg;
nMsg.Msg_Type = IDAMsg_EventCallback;
nMsg.Lng_Send[0] = 0;
nMsg.Para_Void[0] = (void*) &this->mSection;
nMsg.Para_ThisPtr = (void*) this;
nMsg.Para_CallbackPtr = (void*) &this->Section_EventCallback;
this->XIDA_Callback(this->mXIDA_A_Ptr, &nMsg);
is a part of the init.
And I had forgotten to set
nMsg.Para_ThisPtr = (void*) this;
But what I still do not understand...
static int Section_EventCallback(void* this_ptr, XEvent vEvent){
IDA_A* nIDA_A = NULL;
int nRet = 1;
try{
nIDA_A = static_cast < IDA_A* > (this_ptr);
} catch (...) { return 0; }
nRet = nIDA_A->CheckEvents(nIDA_A, vEvent);
nIDA_A = NULL;
return nRet;
}
Here comes/came the pointer with NULL.
Why wasn't nIDA_A not NULL, or why wasn't there raised an error, because static_cast cannot cast with NULL?
And why were functions working, but not member variables?
You know what I mean?
I have a library written in C++. The library has a function which accepts commands as a string and executes them. If an error is encountered (either in the command or while running the command) an "error function" is called which does some cleanup and finally calls exit(1). I am now trying to implement a graphical user interface (using Qt) to the library. The problem is that when an error is encountered, exit is called and my application crashes. I have access to the library source code but I would like to keep modifying the source code to minimum.
I am thinking of rewriting the error function such that it just stops executing code and stays in an idle state until another command is passed to the library from the user-interface. The problem is I am not sure how to go about doing it. I am basically looking for a function call equivalent to exit system call (so that the error function never returns to the code which generated the error) except that I do not want the application to exit but instead just go to an idle state and wait for calls from the user interface.
If there is another way to implement this please let me know. Please also let me know if you need more details.
Thanks in advance,
Here is some code which shows what my problem is
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
void error_func(string error);
void create_sphere(float radius);
void create_rect(float length, float width);
int main()
{
string command;
while(1) {
cout << "Enter command: ";
cin >> command;
if(command.compare("create_sphere") == 0) {
float radius;
cout << "Enter radius: ";
cin >> radius;
create_sphere(radius);
}
else if(command.compare("create_rect") == 0) {
float l, w;
cout << "Enter length and width: ";
cin >> l >> w;
create_rect(l, w);
}
else if(command.compare("quit") == 0)
break;
}
}
void create_sphere(float radius)
{
if(radius < 0)
error_func(string("Radius must be positive"));
cout << "Created sphere" << endl;
}
void create_rect(float length, float width)
{
if(length < 0)
error_func(string("Length must be positive"));
if(width < 0)
error_func(string("Width must be positive"));
cout << "Created rectangle" << endl;
}
void error_func(string error)
{
// do some cleanup
cout << "ERROR: " << error << endl;
exit(1);
}
Assume that create_sphere, create_rect and error_func are provided by the library. I can modify error_func as required but not the other functions (since there are many such functions).
Now when an error is encountered, I would like to go back to the while loop in main so that I can keep accepting other commands.
I am basically looking for a function call equivalent to exit system call (so that the error function never returns to the code which generated the error) except that I do not want the application to exit but instead just go to an idle state and wait for calls from the user interface.
Basically, you are looking for an event loop. The typical minimal Qt program is as follows:
#include <QApplication>
#include <QMainWindow>
int main(int argc, char **argv)
{
QApplication(argc, argv);
QMainWindow w;
w.show();
return application.exec(); // What you want instead of exit
}
Now, you could replace QMainWindow with your own class, and declare a slot in that which gets called when you are trying to handle a command from the user interface.
#include <QWidget>
...
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent) : QWidget(parent)
{
connect(sender, SIGNAL(mySignal()), SLOT(handleCommand()));
}
public slots:
void handleCommand()
{
// Handle your command here.
// Print the error code.
qDebug() << error_func(string("Radius must be positive"));
// or simply:
qDebug() << "Radius must be positive";
} // Leaving the scope, and getting back to the event loop
}
As for the bogus library, well, if it exits, it does. There is not much you can do about that without fixint the library. It is a very bad behavior from most of the libraries.
The modification would be not to exit, but return an error code - which is a general practice in Qt software - and leave it with the application when to exit if they wish.
The application would not quit in your case. Again, It is a very bad idea for a library function to exit. Even Qt does not do except 1-2 times in a few million LOC.
I would suggest not to throw an exception. It is generally not common in Qt software, and you could make your software consistent by just using error codes like the rest of Qt does for you.
Invent an error state (idle state) and make the function never fail. The error state should become visible and be resolvable by some means.
If you can not reach a resolvable error state, it might be possible to rollback to some prior (initial) state.
If the options above are not possible you have some serious failure (software, hardware, data) and you might terminate the program.
All above can be achieved with return values or a getter function (indicating the current state) and a setter manipulating the current state - an exit call is a poor solution in a library. If you have an unresolvable state or can not rollback to a prior state you might throw an exception, catch it in the user interface and terminate the program after displaying the issue.
You should install a message handler which will automatically reduce a lot of your work.
Additionally it will help in reducing your debugging too. Here is my message handler for my Qt5 application. It will need a little tweaking if you are using Qt4:
QFile *logFile = NULL;//The file in which you will output the debug info to
QTextStream *logStream = NULL;//text stream for your log file
QMutex *mutex = NULL;//Always use mutex if you are multi threading your application
bool *debugMode = NULL;//it just a flag in case you want to turn off debugging
bool errorMsg = false;//use the value of this variable after QApplication::exec() if you need to show an error message
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
if(((logFile != NULL) && (debugMode != NULL)))
{
mutex->lock();
switch (type)
{
case QtDebugMsg:
if(!*debugMode)
{
mutex->unlock();
return;
}
*logStream << msg;
logStream->flush();
break;
case QtWarningMsg:
if(!((QString)context.function).contains("setGeometry"))
{
*logStream << "\n*** Warning ***\n";
*logStream << msg << endl;
*logStream << "Category: " << context.category << endl;
*logStream << "File: " << context.file << endl;
*logStream << "Function: " << context.function << endl;
*logStream << "Line: " << context.line << endl;
*logStream << "Version: " << context.version;
*logStream << "\n*** Warning Complete ***\n";
logStream->flush();
errorMsg = true;
SessionManager::get_obj()->saveCurrentSession();
}
break;
case QtCriticalMsg:
*logStream << "\n*** Critical ***\n";
*logStream << msg << endl;
*logStream << "Category: " << context.category << endl;
*logStream << "File: " << context.file << endl;
*logStream << "Function: " << context.function << endl;
*logStream << "Line: " << context.line << endl;
*logStream << "Version: " << context.version;
*logStream << "\n*** Critical Complete ***\n";
logStream->flush();
errorMsg = true;
SessionManager::get_obj()->saveCurrentSession();
break;
case QtFatalMsg:
*logStream << "\n*** Fatal ***\n";
*logStream << msg << endl;
*logStream << "Category: " << context.category << endl;
*logStream << "File: " << context.file << endl;
*logStream << "Function: " << context.function << endl;
*logStream << "Line: " << context.line << endl;
*logStream << "Version: " << context.version;
*logStream << "\n*** Fatal Complete ***\n";
logStream->flush();
errorMsg = false;
SessionManager::get_obj()->saveCurrentSession();
ShowErrorMsg(SessionManager::getSessionName());
exit(0);
}
mutex->unlock();
}
}
To install a message handler add the following code in the main() of your GUI.
qInstallMessageHandler(myMessageOutput);
You can ignore the check for setGeometry if you want to but I find that this warning is emitted unnecessarily. So you can keep it.
Also you may want to have a Session Manager which will automatically save the current session whenever an error is encountered.
When you have done this, you can safely call qFatal() when you want to terminate your application, or else use qCritical() if you want some other functionality.
Has any been able to successfully run with a client using the WSO2/C++ web services package? I've tried just about everything I can think of yet every time I try to run a very simple client I get a crash. Here's some sample code from one of their example programs...
#include <stdio.h>
#include <WSRESTClient.h>
#include <OMElement.h>
#include <iostream>
#include <AxisFault.h>
using namespace std;
using namespace wso2wsf;
int _tmain(int argc, _TCHAR* argv[])
{
WSRESTClient * sc = new WSRESTClient("http://localhost:9090/axis2/services/echo/echoString");
try
{
sc->initializeClient("echo_rest.log", AXIS2_LOG_LEVEL_TRACE);
}
catch (AxisFault & e)
{
cout << endl << "Error: " << e << endl;
return 0;
}
Options * op = sc->getOptions();
op->setHTTPMethod(AXIS2_HTTP_GET);
sc->setOptions(op);
{
OMNamespace * ns = new OMNamespace("http://ws.apache.org/axis2/services/echo", "ns1");
OMElement * payload = new OMElement(NULL,"echoString", ns);
OMElement * child = new OMElement(payload,"text", NULL);
child->setText("Hello World!");
cout << endl << "Request: " << payload << endl;
OMElement * response;
try
{
response = sc->request(payload, "http://ws.apache.org/axis2/c/samples/echo/soap_action");
if (response)
{
cout << endl << "Response: " << response << endl;
}
}
catch (AxisFault & e)
{
cout << endl << "Error: " << e << endl;
}
delete payload;
}
delete sc;
return 0;
}
I get a crash every time at the point of the WRESTClient object construction. It appears to be an issue somewhere in the WSO2 code but I don't get any error message indicating what the exact problem is. My next step will be to build against the source for WSO2 and step through the code which is crashing but I'm hoping someone has encountered this issue before and has some immediate feedback.
Have you considered putting a try/catch-all block around the WRESTClient object construction? If you're core dumping on this line then the chances are that it's throwing an exception, and if you catch it then you might be able to get more useful error information out of that exception.
Other than that, time to break out the debugger as you suggested.