How can I make the login part in QuickFIX in c++?
I found tons of tutorials and articles on how to do this on c# or java, but nothing on c++.
I have a server (acceptor), and a client (initiator). The username and password of the client are stored in the settings file, and are hardcoded in the server program.
From what I've read in the client I set the username and password in fromAdmin() and read and check the in the server in the toAdmin(), but how do I do that?
Here's what I've tried so far:
cast the message to a FIX44::Logon& object using:
FIX44::Logon& logon_message = dynamic_cast<FIX44::Logon&>(message);
Set the Username and password to the logon object like this:
if(session_settings.has("Username"))
{
FIX::Username username = session_settings.getString("Username");
logon_message.set(username);
}
And send the message like this:
FIX::Message messageToSend = logon_message;
FIX::Session::sendToTarget(messageToSend);
But I get this error on the cast:
cannot dynamic_cast 'message' (of type 'class FIX::Message') to type 'struct FIX44::Logon&' (target is not pointer or reference to complete type)
What I've tried I got inspired from http://niki.code-karma.com/2011/01/quickfix-logon-support-for-username-password/comment-page-1/.
I'm still not clear on how to make the client and the server.
Can anyone help me?
Possible mistakes:
I think you have fromAdmin()/toAdmin() backward. toAdmin() is called on outgoing admin messages, fromAdmin() is called on incoming. For the Initiator, you must set the fields within the toAdmin() callback. Your Acceptor will check the user/pass in fromAdmin().
Are you trying to dynamic_cast without first checking to see if it was a Logon message? The toAdmin() callback handles all admin messages; the message could be a Heartbeat, Logon, Logout, etc. That might explain your cast error.
As to what the code should look like, my C++ is rusty, but the basic pattern is this:
void YourMessageCracker::toAdmin( FIX::Message& message, const FIX::SessionID& sessionID)
{
if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType))
{
FIX44::Logon& logon_message = dynamic_cast<FIX44::Logon&>(message);
logon_message.setField(FIX::Username("my_username"));
logon_message.setField(FIX::Password("my_password"));
}
}
From there, I think you can see how you'd write a similar fromAdmin() where you'd get the fields instead of setting them.
The above uses hard-coded user/pass, but you probably want to pull it from the config file. I think your calls to session_settings.getString(str) are correct for that.
(Please forgive any coding errors. I'm much more fluent in the Java/C# versions of the QF engine, though the basic principles are the same.)
I see that your first web reference uses the FIELD_GET_REF macro. It may be better than message.getHeader().getField(), but I'm not familiar with it.
Related
I'm having an unexpected issue with a c++ quickfix client application using FIX 4.4. I form marketdatarequest and populate it and then call send which returns true. The message is not found in the message or event log files.
No error seems to be reported - what could be happening?
FIX44::MarketDataRequest request(FIX::MDReqID(tmp)
, FIX::SubscriptionRequestType('1')
, FIX::MarketDepth(depth)); // 0 is full depth
FIX::SubscriptionRequestType subType(FIX::SubscriptionRequestType_SNAPSHOT);
FIX44::MarketDataRequest::NoRelatedSym symbolGroup;
symbolGroup.set(FIX::Symbol(I.subID));
request.addGroup(symbolGroup);
FIX::Header &header = request.getHeader();
header.setField(FIX::SenderCompID(sessionSenderID));
header.setField(FIX::TargetCompID(sessionTargetID));
if (FIX::Session::sendToTarget(request) == false)
return false;
My FixConfig looks like:
[DEFAULT]
HeartBtInt=30
ResetOnLogout=Y
ResetOnLogon=Y
ResetOnDisconnect=Y
ConnectionType=initiator
UseDataDictionary=Y
FileLogPath=logs
[SESSION]
FileLogPath=logs
BeginString=FIX.4.4
DataDictionary=XXXXX
ConnectionType=initiator
ReconnectInterval=60
TargetCompID=tCompID
SenderCompID=sCompID
SocketConnectPort=123456
SocketConnectHost=XX.XX.XXX.XX
SocketConnectProtocol=TCP
StartTime=01:05:00
EndTime=23:05:30
FileLogPath=logs
FileStorePath=logs
SocketUseSSL=N
thanks for any help,
Mark
Mark, just couple of notes not really related to your question but which you may found useful:
you dont have to explicitly set TargetCompId/SenderCompId for each message, engine will do it for you.
Do not place logic into callbacks(like you did with market data subscription in onLogon). Better create additional thread which will consume events from you listener, make decisions and take an action.
I'm new to OTRS (3.2) and also new to PERL but I have been given the task of setting up OTRS so that it will make a call to our remote webservice so a record can be created on our end when a ticket is set as "Closed".
I set up various dynamic fields so the customer service rep can fill in additional data that will be passed into the webservice call along with ticket details.
I couldn't get the webservice call to trigger when the ticket was "Closed" but I did get it to trigger when the "priority" was changed so I'm just using that now to test the webservice.
I'm just using the Test.pm and TestSimple.pm files that were included with OTRS.
When I look at the Debugger for the Webserice, I can see that the calls were being made:
$VAR1 = {
'TicketID' => '6'
};
My webservice currently just has one method "create" which just returns true for testing.
however I get the following from the Test.pm
"Got no TicketNumber (2014-09-02 09:20:42, error)"
and the following from the TestSimple.pm
"Error in SOAP call: 404 Not Found at /TARGET/SHARE/var/otrs/Kernel/GenericInterface/Transport/HTTP/SOAP.pm line 578 (2014-09-02 09:20:43, error)
I've spent countless hours on Google but couldn't find anything on this. All I could find is code for the Test.pm and TestSimple.pm but nothing really helpful to help me create a custom invoker for my needs and configure the webservice in OTRS to get it to work.
Does anyone have any sample invokers that I can look at to see how to set it up?
Basically I need to pass the ticket information along with my custom dynamic fields to my webservice. From there I can create the record on my end and do whatever processing.
I'm not sure how to setup the Invoker to pass the necessary ticket fields and dynamic fields and how to make it call a specific method in my remote webservice.
I guess getting the Test.pm and TestSimple.pm to work is the first step then I can modify those for my needs. I have not used PERL at all so any help is greatly appreciated.
I'm also struggling with similar set of requirements too. I've also never programmed in PERL, but I can tell you at least that the "Got no TicketNumber" in the Test.pm is right from the PrepareRequest method, there you can see this block of code:
# we need a TicketNumber
if ( !IsStringWithData( $Param{Data}->{TicketNumber} ) ) {
return $Self->{DebuggerObject}->Error( Summary => 'Got no TicketNumber' );
}
You should change all references to TicketNumber to TicketID, or remove the validation whatsoever (also there is mapping to ReturnedData variable).
Invoking specific methods on your WS interface is quite simple (but poorly documented). The Invoker name that you specify in the "OTRS as requester" section of web service configuration corresponds to the WS method that will be called. So if you have WS interface with a method called "create" just name the Invoker "create" too.
As far as the gathering of dynamic field goes, can't help you on that one yet, sorry.
Cheers
I am new to the wsdl\soapmessage query\reply world( if i can put it in this way), and I am facing some difficulties using the following wsdl( which I really really hope, one will be so kind to look at at least one of the services described there)
http://almdemo.polarion.com/polarion/ws/services/TrackerWebService?wsdl
which was provided to me to develop a matlab webinterface. Right now my matlab code looks like this:
targetNamespace = 'http://ws.polarion.com/TrackerWebService';
method = 'queryWorkItems';
values= {'Query','Sort'}
names = {'query', 'sort'}
types ={'xsd:string','xsd:string'}
message = createSoapMessage( targetNamespace, method, values, names, types)
response = callSoapService('http://almdemo.polarion.com/polarion/ws/services',...
% Service's endpoint
'http://almdemo.polarion.com/polarion/#/workitems',...
% Server method to run
message)
% SOAP message created using createSoapMessage
author = parseSoapResponse(response)
Herewith to save you time I will just enonce my two problems:
Is the code correct?
Could someone tell me if such a wsdl link is just a definition of webservices or it is also a service's endpoint?
Normally to execute manually\per clicks this services on the weppage
http://almdemo.polarion.com/polarion, you have to login!
So how do I send a message in matlab which first log me in? Or must such a service be introduced into that wsdl for me to do it?? Could you be kind enough to write how it must be defined, because I don't really
write wsdl files, but I shall learn!**
I will be really thankful for your help and I wish you a happy week(-end) guys(& girls)!!!
Regards
Chrysmac
ps: I tried to use Soapui and gave that webpage as endpoint, but the toool crashes each time I enter my credentials! Maybe because of the dataload!??
VERY basic questions from a FIX newbie
Looking at the documentation at http://www.quickfixengine.org and reading posts here on stackoverflow I see lots of talk about message 'cracking'. I think I sort of get the idea, but feel like I'm still not totally clear.
Can some explain in general what exactly this is (why is it necessary? it sounds like a hack), why it only seems relates to received FIX messages, and is not used at all when using Python?
Thank you!
In practice, all you need to know is this:
Your fromApp() callback gets a Message object. That message is actually a NewOrderSingle or ExecutionReport or something. Rather than making you figure it out, QF lets you inherit from MessageCracker. To use it, call crack() in your fromApp(), as follows:
void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
throw( FIX::FieldNotFound&, FIX::IncorrectDataFormat&, FIX::IncorrectTagValue&, FIX::UnsupportedMessageType& )
{
crack(message, sessionID);
}
What crack() does is this:
Converts your Message into the proper subclass (e.g. NewOrderSingle, ExecutionReport, etc)
Calls your user-defined onMessage(subtype) callback, if defined. If not defined, it throws an UnsupportedMessageType exception and your app will automatically send a BusinessMessageReject (35=j) to the counterparty.
So, do you want to handle NewOrderSingle messages? Great, just define an onMessage(NewOrderSingle) callback.
void onMessage( const FIX42::NewOrderSingle& message, const FIX::SessionID& )
{
// Do whatever you want with your NewOrderSingle message's content.
// Note that this message and the one passed to crack() are the same, content-wise.
}
Do you want to handle ExecutionReports? Define onMessage(ExecutionReport). And so on.
But what about those message types you don't want to handle? It would suck if you had to add handlers to reject all those other message types, but luckily, you don't have to. As I said earlier, if you don't define an onMessage(), QF will reject it for you. (If you want to swallow a particular message type and ignore it without rejection, then just define an onMessage() call with no body.)
Does that clear it up a bit? Perhaps now this page in the QF docs might read a little easier -- the bottom section talks about the MessageCracker.
Note: The MessageCracker does not handle session-level (aka "admin") messages. If you want to add custom handling for, say, Logon or Heartbeat messages, you must do it explicitly in fromAdmin() (see this question for more info).
I use quickfixj for Java. The cracking uses and interface to return the cracked message to the interface implementation. The implementor will over ride the interface's methods so that it can handle each message type individually.
Message cracker takes a plain message and returns the message as a specifically typed message. The advantage of this is that the dictionary will confine the fields of the message so that it is easier to look up each field.
(This is the first time I've done this actually.)
<mx:HTTPService id="post_update" method="POST" result="{Dumper.info('bye')}"/>
The result handler above is just for debugging purposes, but its never hit, even though what I'm uploading via POST...
post_update.url = getPath(parentDocument.url)+"update";
post_update.send(new_sel);
...is received and handled successfully by my Django view:
def wc_post(request) :
request.session['wc'] = request.POST
return http.HttpResponse("<ok/>", mimetype="text/xml")
As far as what I'm sending back from Django, I'm following the guidelines here:
Sending Images From Flex to a Server
I just don't want it to generate an error on the Flex side considering Django is actually receiving and processing the data. Any help appreciated. Can't remember the text of the error in Flex at the moment.
UPDATE: new_sel (what I'm posting from Flex) is just a Flex Object, with various text fields.
UPDATE: various error messages from event.message (in fault handler):
faultCode = "Server.Error.Request"
faultString = "HTTP request error"; DSStatusCode = 500; errorID = 2032; type = "ioError"
This is more grasping at straws than answers, but do I have to send a particular type of header back from Django- the default sent by Django includes a 200 success status code, and the response I was sending of "<ok/>" with mime type of "text/xml" was following the example exactly that I provided from that other source.
And also the url I'm sending the POST to is localhost:8000/wr_view1/wr_webcube/update, and I previously successfully did a GET to localhost:8000/wr_view1/wr_webcube/webcube.xml, and despite the .xml extension in the case of GET, it was still being handled by Django (and without errors in Flex). In the case of this POST, once again, the data is actually succesfully sent and handled by Django, but Flex is returning Error 2032, which I found out can mean numerous different things including cross domain issues, but don't see how that's the case here.
Just had to return HttpResponse("ok") Didn't like it being sent as xml for some reason. So much ado about nothing I guess.