The function pointer you pass to the 'MHD_start_daemon' call (for the
access handler callback) needs to have the exact same signature that's
expected by MHD.  I suspect you understand that given your comment about
understanding the cause - I'm just level setting.

I'm not sure why you have "MHD_Result*" as your return type from your
access handler function call, but that looks like the culprit.  It should
just be "MHD_Result" (not a pointer).  You don't show your code, so I'm not
sure if something funky is going on trying to blend C and C++.  So, to be
really thorough...

I'm not claiming to be an expert and I think there are other ways to do
this, but I find this methodology relatively easy to understand:

With C++, you can pass in a C-version of the function with your "Http"
object as the first argument (see the "this" below the
"connectionCallbackC" line in the following code).  Then, use that class
instance pointer to call back into your Http class to do the actual work.

I.e., in your "Http" class, you could have something like this:
--------------------------
void Http::start() {
    ....
    myDaemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION |
MHD_ALLOW_UPGRADE | MHD_ALLOW_SUSPEND_RESUME, // one thread per connection;
also 2 flags needed to support websockets
                                webPort,                       // port to
listen on
                                nullptr,                       // accept
policy callback
                                nullptr,                       // extra arg
to accept policy callback
                                &connectionCallbackC,          // main
'connection' callback (i.e., the "access handler" callback)
                                this,                          // extra
argument to the 'connection' callback
                                MHD_OPTION_NOTIFY_COMPLETED,   // specifies
that the next arg is the callback to call when the connection is done
                                &requestCompletedCallbackC,    // the
callback to call when the connection is done
                                this,                          // extra arg
to the callback when the connection is done
                                MHD_OPTION_CONNECTION_LIMIT,   // specifies
that the next arg is the max number of simultaneous connections
                                (unsigned int)100,             // the
number of permitted simultaneous connections
                                MHD_OPTION_CONNECTION_TIMEOUT, // specifies
that the next arg is how long any given connection can live
                                (unsigned int)60,              // the
number of seconds connections are allowed to live (0 would allow them to
live indefinitely)
                                MHD_OPTION_END);               // no more
options in the arg list
    ...
}
--------------------------

Then, outside the class, put a regular old C function as your callback, and
have it just call back into your Http class using the pointer you provided:

// This could be at the top of your .cpp file or in your .hpp/.h file or
whatever.  It's just a function declaration.
extern "C" MHD_Result connectionCallbackC(void* cls, struct MHD_Connection*
connection, const char* url, const char* method,

const char* version, const char* upload_data, size_t* upload_data_size,
void** con_cls);

// This is the "C" function that gets called as the "access handler".  You
can then just have it call back into your "Http" class to process the data.
// The "cls" value is the one you gave MHD after the function pointer in
the 'MHD_start_daemon' call.  I.e., "this" (specifically, it's a pointer to
your Http class).
MHD_Result connectionCallbackC(void* cls, struct MHD_Connection*
connection, const char* url, const char* method,
                                                        const char*
version, const char* upload_data, size_t* upload_data_size, void** con_cls)
{
    return ((Http*)cls)->connectionCallback(connection, url, method,
version, upload_data, upload_data_size, con_cls);
}

// For completeness, here's the callback in the Http C++ code that gets
called by the above C function:
MHD_Result Http::connectionCallback(struct MHD_Connection* connection,
const char* url, const char* method,
                                                              const char*
version, const char* uploadData, size_t* uploadDataSize, void** connPtr) {
... do stuff ... }



Also noteworthy: MHD very recently changed the type of "MHD_Result" from an
int to an enum.  Some example code out on the internet might be out of
date.  You have to use the real "MHD_Result" (not an int) or it will fail
to compile for similar "type mismatch" reasons.  (I literally just had to
update my code a couple days ago when I updated to the latest MHD version -
I had been counting on it being an int to make something a bit easier
programmatically.  Not hard to work around, of course.)


Hope that helps.

Ken


On Thu, Aug 6, 2020 at 4:50 PM Jason Kary via libmicrohttpd <
libmicrohttpd@gnu.org> wrote:

> Hello,
>
> I’m hoping someone can help me understand how to fix the following error:
>
> /home/jkary/src/xmrig-amd/src/common/api/Httpd.cpp: In member function ‘bool 
> Httpd::start()’:
> /home/jkary/src/xmrig-amd/src/common/api/Httpd.cpp:78:66: error: cannot 
> convert ‘MHD_Result (Httpd::*)(void*, MHD_Connection*, const char*, const 
> char*, const char*, const char*, long unsigned int*, void**)’ to 
> ‘MHD_AccessHandlerCallback’ {aka ‘MHD_Result (*)(void*, MHD_Connection*, 
> const char*, const char*, const char*, const char*, long unsigned int*, 
> void**)’}
>    78 |     m_daemon = MHD_start_daemon(flags, m_port, nullptr, nullptr, 
> &Httpd::handler, this, MHD_OPTION_END);
>       |                                                                  
> ^~~~~~~~~~~~~~~
>       |                                                                  |
>       |                                                                  
> MHD_Result (Httpd::*)(void*, MHD_Connection*, const char*, const char*, const 
> char*, const char*, long unsigned int*, void**)
> In file included from /home/jkary/src/xmrig-amd/src/common/api/Httpd.cpp:25:
> /usr/include/microhttpd.h:2428:45: note:   initializing argument 5 of 
> ‘MHD_Daemon* MHD_start_daemon(unsigned int, uint16_t, 
> MHD_AcceptPolicyCallback, void*, MHD_AccessHandlerCallback, void*, ...)’
>  2428 |                   MHD_AccessHandlerCallback dh, void *dh_cls,
>       |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~^~
> make[2]: *** [CMakeFiles/xmrig-amd.dir/build.make:876: 
> CMakeFiles/xmrig-amd.dir/src/common/api/Httpd.cpp.o] Error 1
> make[1]: *** [CMakeFiles/Makefile2:98: CMakeFiles/xmrig-amd.dir/all] Error 2
> make: *** [Makefile:104: all] Error 2
>
> After a few days of experimenting I’m not able to grok the GNU c++
> compiler error.  I can see the return type does not match and
> libmicrohttpd.h is expecting ‘MHD_Result (*)’ and some generous folks on
> reddit explained the return type is wrong because "Your function is
> expecting pointer to function, not a pointer to non-static member function.”
>
> I am not quite strong enough in C++ (yet) to understand how to fix this
> issue.  I understand the cause but do not know how to fix this error.
>
> Can anyone spend 5 minutes and educate me?
>
> Thanks in advance!
> Jason
>
>

Reply via email to