freediameter - how to handle request messages outside of dispatch function - c++

So, I've advertised for DCCA application in my extension via fd_disp_register and I can parse and prepare the response message and at the end sending them from my callback function with no issue.
This always works if the answer message is prepared inside of callback function. But what if i want to reply the request message outside of my callback function ?
So, I tried it with a sample code. I changed the callback function logic so there were no sending message from it and instead another thread tries to fetch some information and send out the response.
This absolutely failed, because as soon as callback returns (with 0), the next action gonna take place (according to disp_action value) which is not in my favor.
So, I'd like to ask what is your solution to handle such case, I mean sending out the response messages outside of the callback function ?
Thanks.

I'm not sure I've ever done this before, but looking at libfdproto.h...
enum disp_action {
DISP_ACT_CONT, /* The next handler should be called, unless *msg == NULL. */
DISP_ACT_SEND, /* The updated message must be sent. No further callback is called. */
DISP_ACT_ERROR /* An error must be created and sent as a reply -- not valid for callbacks, only for fd_msg_dispatch. */
};
...it sounds like you want to set *act = DISP_ACT_CONT; and *msg = NULL; (because you've taken ownership of the message).
Does that work?

Related

Proper way to implement async function in Qt/DBus adaptor

As described in D-Bus documentation, all IPC calls considered as asynchronous. When Qt calls remote D-Bus object through QDBusAbstractInterface, there's QBusPendingCall<T> which is fully async and provide signalling when call ran to completion.
In my application design I want to implement async call on my object adaptor, but current Qt/DBus implementation assumes, that all method calls are blocking.
So, there's a question: is there proper way to implement handling D-Bus method call asynchronously?
This is explained pretty well in Declaring Slots in D-Bus Adaptors.
We do this by writing a slot that stores the request data in a persistent structure, indicating to the caller using QDBusMessage::setDelayedReply(true) that the response will be sent later.
struct RequestData
{
QString request;
QString processedData;
QDBusMessage reply;
};
QString processRequest(const QString &request, const QDBusMessage &message)
{
RequestData *data = new RequestData;
data->request = request;
message.setDelayedReply(true);
data->reply = message.createReply();
QDBusConnection::sessionBus().send(data->reply);
appendRequest(data);
return QString();
}
The use of QDBusConnection::sessionBus().send(data->reply) is needed to explicitly inform the caller that the response will be delayed. In this case, the return value is unimportant; we return an arbitrary value to satisfy the compiler.
When the request is processed and a reply is available, it should be sent using the QDBusMessage object that was obtained. In our example, the reply code could be something as follows:
void sendReply(RequestData *data)
{
// data->processedData has been initialized with the request's reply
QDBusMessage &reply = &data->reply;
// send the reply over D-Bus:
reply << data->processedData;
QDBusConnection::sessionBus().send(reply);
// dispose of the transaction data
delete data;
}
As can be seen in the example, when a delayed reply is in place, the return value(s) from the slot will be ignored by Qt D-Bus. They are used only to determine the slot's signature when communicating the adaptor's description to remote applications, or in case the code in the slot decides not to use a delayed reply.
The delayed reply itself is requested from Qt D-Bus by calling QDBusMessage::reply() on the original message. It then becomes the responsibility of the called code to eventually send a reply to the caller.
Warning: When a caller places a method call and waits for a reply, it will only wait for a limited amount of time. Slots intending to take a long time to complete should make that fact clear in documentation so that callers properly set higher timeouts.

libcurl function: about function CURLMOPT_TIMERFUNCTION

I am using multi socket, however, I am confused with this API
int timer_callback(CURLM *multi, /* multi handle */
long timeout_ms, /* see above */
void *userp); /* private callback pointer *
CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_TIMERFUNCTION, timer_callback);
and I know that when the timeout changed, the callback function are called, however, the first time we register the callback function, for example:
curl_multi_setopt(handle, CURLMOPT_TIMERFUNCTION, timer_cb);
//and the callback function is
int timer_cb(CURLM *multi, long timeout_ms,void *userp)
{.....}
the second paramenter timeout_ms value is what? and I read the docs/example hiperfifo.c, and I see the log, this value is 1ms, how did this value come?
thanks
knuth
From the documentation:
CURLMOPT_TIMERFUNCTION - set callback to receive timeout values
int timer_callback(CURLM *multi, /* multi handle */<br>
long timeout_ms, /* see above *//<br
void *userp); /* private callback pointer */
This callback function will be called when the timeout value changes. The timeout_ms value is at what latest time the application should call one of the "performing" functions of the multi interface (curl_multi_socket_action and curl_multi_perform) - to allow libcurl to keep timeouts and retries etc to work. A timeout_ms value of -1 means that there is no timeout at all, and 0 means that the timeout is already expired. libcurl attempts to limit calling this only when the fixed future timeout time actually changes
Once a easy_handle is added to multi_handle via curl_multi_add_handle()[in this case, whenever a new_conn() is available], an internal 'jumpstart' is provided by creating a timeout action with 1ms as the timeout value.
Below comments from multi.c
/* Set the timeout for this multi handle to expire really soon so that it will be taken care of even when this multi handle is added in the midst of operation when only the curl_multi_socket() API is used. During that flow, only sockets that time-out or have actions will be dealt with. Since this handle has no action yet, we make sure it times out to get things to happen. */
Curl_expire(data, 1);
The actual timer callback set with CURLMOPT_TIMERFUNCTION is called inside update_timer() after Curl_expire()
Hope this helps.

Reasoning behind CFReadStreamCreateForHTTPRequest in OSX/IOS

I have recently written an asynchronous HTTP client in c++ for iOS/OSX. I was confused as to why headers were not arriving in my CFHTTPMessageRef response object until I realised that there was an object lurking as a property of the stream which contains the headers (after handling the kCFStreamEventBytesAvailable event).
So now I copy the headers from the property into my response object during the notification of the stream ending, before calling my event handler.
(code available on request, there's quite a lot of it)
The Apple documentation is characteristically silent on the subject and I was wondering if anyone out there knows the reason for this design decision by apple. I am keen to know in case I have a fundamental misunderstanding somewhere?
EDIT: the documentation says this:
After you schedule the request on a run loop, you will eventually get
a header complete callback. At this point, you can call
CFReadStreamCopyProperty to get the message response from the read
stream
However there seems to be no indication as to what the name or value of this event mask is.
EDIT:
Having done some experimenting, I see that the stream creates its own response object some time after sending the kCFStreamEventOpenCompleted notification and before the first kCFStreamEventHasBytesAvailable notification.
In the kCFStreamEventHasBytesAvailable event handler I can do this:
auto response = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream,
kCFStreamPropertyHTTPResponseHeader);
constexpr CFIndex bufferSize = 1024;
UInt8 buffer[bufferSize];
auto bytesRead = CFReadStreamRead(readStream, buffer, bufferSize);
if (bytesRead > 0) {
CFHTTPMessageAppendBytes(response, buffer, bytesRead);
}
CFRelease(response);
and the stream's response message object is indeed updated with new body data.
Now I am curious as to why this is not just done automatically by the stream?

understanding RProperty IPC communication

i'm studying this source base. Basically this is an Anim server client for Symbian 3rd edition for the purpose of grabbing input events without consuming them in a reliable way.
If you spot this line of the server, here it is basically setting the RProperty value (apparently to an increasing counter); it seems no actual processing of the input is done.
inside this client line, the client is supposed to be receiving the notification data, but it only calls Attach.
my understanding is that Attach is only required to be called once, but is not clear in the client what event is triggered every time the server sets the RProperty
How (and where) is the client supposed to access the RProperty value?
After Attaching the client will somewhere Subscribe to the property where it passes a TRequestStatus reference. The server will signal the request status property via the kernel when the asynchronous event has happened (in your case the property was changed). If your example source code is implemented in the right way, you will find an active object (AO; CActive derived class) hanging around and the iStatus of this AO will be passed to the RProperty API. In this case the RunL function of the AO will be called when the property has been changed.
It is essential in Symbian to understand the active object framework and quite few people do it actually. Unfortunately I did not find a really good description online (they are explained quite well in Symbian OS Internals book) but this page at least gives you a quick example.
Example
In the ConstructL of your CMyActive subclass of CActive:
CKeyEventsClient* iClient;
RProperty iProperty;
// ...
void CMyActive::ConstructL()
{
RProcess myProcess;
TSecureId propertyCategory = myProcess.SecureId();
// avoid interference with other properties by defining the category
// as a secure ID of your process (perhaps it's the only allowed value)
TUint propertyKey = 1; // whatever you want
iClient = CKeyEventsClient::NewL(propertyCategory, propertyKey, ...);
iClient->OpenNotificationPropertyL(&iProperty);
// ...
CActiveScheduler::Add(this);
iProperty.Subscribe(iStatus);
SetActive();
}
Your RunL will be called when the property has been changed:
void CMyActive::RunL()
{
if (iStatus.Int() != KErrCancel) User::LeaveIfError(iStatus.Int());
// forward the error to RunError
// "To ensure that the subscriber does not miss updates, it should
// re-issue a subscription request before retrieving the current value
// and acting on it." (from docs)
iProperty.Subscribe(iStatus);
TInt value; // this type is passed to RProperty::Define() in the client
TInt err = iProperty.Get(value);
if (err != KErrNotFound) User::LeaveIfError(err);
SetActive();
}

How to display remote email message?

I have been using this code to display IMAP4 messages:
void DisplayMessageL( const TMsvId &aId )
{
// 1. construct the client MTM
TMsvEntry indexEntry;
TMsvId serviceId;
User::LeaveIfError( iMsvSession->GetEntry(aId, serviceId, indexEntry));
CBaseMtm* mtm = iClientReg->NewMtmL(indexEntry.iMtm);
CleanupStack::PushL(mtm);
// 2. construct the user interface MTM
CBaseMtmUi* uiMtm = iUiReg->NewMtmUiL(*mtm);
CleanupStack::PushL(uiMtm);
// 3. display the message
uiMtm->BaseMtm().SwitchCurrentEntryL(indexEntry.Id());
CMsvOperationWait* waiter=CMsvOperationWait::NewLC();
waiter->Start(); //we use synchronous waiter
CMsvOperation* op = uiMtm->OpenL(waiter->iStatus);
CleanupStack::PushL(op);
CActiveScheduler::Start();
// 4. cleanup for example even members
CleanupStack::PopAndDestroy(4); // op,waiter, mtm, uimtm
}
However, in case when user attempts to download a remote message (i.e. one of the emails previously not retrieved from the mail server), and then cancels the request, my code remains blocked, and it never receives information that the action was canceled.
My question is:
what is the workaround for the above, so the application is not stuck?
can anyone provide a working example for asynchronous call for opening remote messages which do not panic and crash the application?
Asynchronous calls for POP3, SMTP and local IMAP4 messages work perfectly, but remote IMAP4 messages create this issue.
I am testing these examples for S60 5th edition.
Thank you all in advance.
First of all, I would retry removing CMsvOperationWait and deal with the open request asynchronously - i.e. have an active object waiting for the CMsvOperation to complete.
CMsvOperationWait is nothing more than a convenience to make an asynch operation appear synchronous and my suspicion is that this is culprit - in the case of download->show message, there are two asynch operations chained.