libmicrohttpd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libmicrohttpd] MHD_Result casting error.


From: Kenneth Mastro
Subject: Re: [libmicrohttpd] MHD_Result casting error.
Date: Thu, 6 Aug 2020 17:27:03 -0400

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

[Prev in Thread] Current Thread [Next in Thread]