Dear Johannes,

You need to run "MHD_run()" between resuming and asking for the FD set.
It was not very well documented, so I've fixed the documentation in SVN
37877.

You also didn't FD_ZERO your fdsets, but that's minor.  I've attached
your code with my changes, so that it works.

Happy hacking!

Christian

On 09/04/2016 03:49 PM, Johannes Spangenberg wrote:
> Hello,
> 
> I encountered some problems while using the libmicrohttpd. I was using 
> MHD_suspend_connection() and MHD_resume_connection() in combination with 
> an external event loop. The problem was that the connection was not 
> resumed until another request was made. I checked the event loop but 
> they was running and calling MHD_run_with_select() periodically. 
> Afterwards, I wrote a small test program, attached to this mail, to 
> check if it is a bug or misunderstanding of the library. I also tested 
> it agains the last version (0.9.51).
> 
> Connections are still not resumed in the small test program. But in 
> difference to my original project, receiving another request does not 
> resume the first connection. The second request is never accepted by 
> libmicrohttpd. It seems that select() does not return to acceppt the 
> second connection after calling MHD_suspend_connection() on the first 
> one. If I'm not calling MHD_suspend_connection() and 
> MHD_resume_connection(), everythink works. Futuremore, if I am using 
> MHD_USE_SELECT_INTERNALLY and replace the external loop with a busy 
> loop, everything works as well. I thinks it looks like there is a bug in 
> MHD_suspend_connection() and MHD_resume_connection() when used with 
> external select. Could someone take a look and check whether I'm doing 
> something wrong or there is a bug in the library.
> 
> I searchd for it but could not find a solution to fix it. A found 
> another conversation in the mailing list: [MHD_suspend_connection 
> API](http://lists.gnu.org/archive/html/libmicrohttpd/2014-02/msg00005.html). 
> It is not clear but thing it may be possible that he stumbled over the 
> same bug.
> 
> My english is not the best but I hope you can understand everything.
> Johannes
> 
#include <csignal>
#include <iostream>
#include <vector>

#include <sys/select.h>

#include <microhttpd.h>

using std::cout;
using std::endl;

#define nullptr NULL

static volatile bool run_loop = true;
static MHD_Daemon *ctx = nullptr;
static MHD_Response *response = nullptr;
static std::vector<MHD_Connection*> susspended;

void sighandler(int)
{
	run_loop = false;
}

int handle_access(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)
{
	static int second_call_marker;
	static int third_call_marker;
	if (*con_cls == nullptr) {
		cout << "New connection" << endl;
		*con_cls = &second_call_marker;
		return MHD_YES;
	} else if (*con_cls == &second_call_marker) {
		cout << "Suspending connection" << endl;
		MHD_suspend_connection(connection);
		susspended.push_back(connection);
		*con_cls = &third_call_marker;
		return MHD_YES;
	} else {
		cout << "Send response" << endl;
		return MHD_queue_response(connection, 200, response);
	}
}

int main(int argc, char *argv[])
{
	std::signal(SIGINT, &sighandler);
	std::signal(SIGINT, &sighandler);

	ctx = MHD_start_daemon(MHD_USE_DUAL_STACK //| MHD_USE_EPOLL
	                       | MHD_USE_SUSPEND_RESUME | MHD_USE_DEBUG,
	                       8080, nullptr, nullptr,
	                       &handle_access, nullptr,
	                       MHD_OPTION_END);
	response = MHD_create_response_from_buffer(4, const_cast<char*>("TEST"),
	                                           MHD_RESPMEM_PERSISTENT);

	while (run_loop) {
		int max;
		fd_set rs, ws, es;
		struct timeval tv;
		struct timeval *tvp;

                FD_ZERO (&rs);
                FD_ZERO (&ws);
                FD_ZERO (&es);
		cout << "Wait for IO activity" << endl;
		MHD_UNSIGNED_LONG_LONG mhd_timeout = -1LL;
		MHD_get_fdset(ctx, &rs, &ws, &es, &max);
		if (MHD_get_timeout(ctx, &mhd_timeout) == MHD_YES) {
			tv.tv_sec = mhd_timeout / 1000;
			tv.tv_usec = (mhd_timeout % 1000) * 1000;
			tvp = &tv;
		} else {
			tvp = nullptr;
		}

		select(max + 1, &rs, &ws, &es, tvp);
		MHD_run_from_select(ctx, &rs, &ws, &es);

		for (MHD_Connection *connection : susspended) {
			cout << "Resume connection" << endl;
			MHD_resume_connection(connection);
                        MHD_run (ctx);
		}
		susspended.clear();
	}

	cout << "Stop server" << endl;
	MHD_stop_daemon(ctx);
}

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to