Hi all

I wrote a simplified program (attached) to demonstrate a problem I'm dealing 
with.
The problem is that libcurl doesn't allow the program to quit because it hangs 
inside curl_multi_cleanup:

(gdb) bt
#0  0x00007ffff7e463f1 in poll () from /lib64/libc.so.6
#1  0x00007ffff7f58a46 in poll (__timeout=1000, __nfds=<optimized out>, 
    __fds=0x7fffffffdc00) at /usr/include/bits/poll2.h:41
#2  Curl_socket_check (readfd0=readfd0@entry=3, readfd1=readfd1@entry=-1, 
    writefd=-1, timeout_ms=<optimized out>, timeout_ms@entry=1000)
    at ../../lib/select.c:217
#3  0x00007ffff7f66347 in Curl_pp_statemach (pp=pp@entry=0x422370, 
    block=block@entry=true) at ../../lib/pingpong.c:112
#4  0x00007ffff7f61121 in imap_block_statemach (conn=<optimized out>)
    at ../../lib/imap.c:1365
#5  imap_disconnect (conn=0x421cc0, dead_connection=<optimized out>)
    at ../../lib/imap.c:1624
#6  0x00007ffff7f3e15d in Curl_disconnect (data=0x4175c0, 
    conn=conn@entry=0x421cc0, dead_connection=dead_connection@entry=false)
    at ../../lib/url.c:781
#7  0x00007ffff7f6e8f3 in Curl_conncache_close_all_connections (
    connc=connc@entry=0x409d70) at ../../lib/conncache.c:573
#8  0x00007ffff7f535d1 in curl_multi_cleanup (multi=multi@entry=0x409c60)
    at ../../lib/multi.c:2244
#9  0x000000000040139a in main (argc=<optimized out>, argv=<optimized out>)
    at curl_imap_teardown_issue.c:89

The program logs in to an imaps:// server (using CURLOPT_CONNECT_ONLY), then 
enters idle mode using curl_easy_send and receives answer using curl_easy_recv. 
Then sleeps for a few seconds and tries to clean up everything and quit. I 
followed the order given at 
https://curl.haxx.se/libcurl/c/curl_multi_cleanup.html but still 
curl_multi_cleanup() doesn't exit for a long time. 

The issue occurs on libcurl-7.61.1 as well as on latest release curl-7.64.1.

Am I doing something wrong, or is it a bug?

-- 
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <curl/curl.h>

static const char cmd[] = "A1 IDLE\n";
static char buf[1024];

int main(int argc, char **argv)
{
	CURLM *mcurl;
	CURL *curl;
	int mrun, sock = CURL_SOCKET_BAD;
	time_t start = time(NULL);
	int state = 0;
	ssize_t pos = 0;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s imaps://mailserver.com u...@mailserver.com password\n", argv[0]);
		return 1;
	}

	assert((mcurl = curl_multi_init()));
	assert((curl = curl_easy_init()));
	assert(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) == CURLE_OK);
	assert(curl_easy_setopt(curl, CURLOPT_URL, argv[1]) == CURLE_OK);
	if (argc > 2)
		assert(curl_easy_setopt(curl, CURLOPT_USERNAME, argv[2]) == CURLE_OK);
	if (argc > 3)
		assert(curl_easy_setopt(curl, CURLOPT_PASSWORD, argv[3]) == CURLE_OK);
	assert(curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L) == CURLE_OK);
	//assert(curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 1L) == CURLE_OK);

	assert(curl_multi_add_handle(mcurl, curl) == CURLM_OK);

	while (time(NULL) - start < 5) {
		struct curl_waitfd waitfd;

		assert(curl_multi_perform(mcurl, &mrun) == CURLM_OK);
		for (;;) {
			int i;
			struct CURLMsg *m = curl_multi_info_read(mcurl, &i);

			if (!m)
				break;
			if (m->msg == CURLMSG_DONE && m->easy_handle == curl) {
				assert(curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sock) == CURLE_OK);
				assert(sock != CURL_SOCKET_BAD);
			}
		}

		if (sock >= 0) {
			waitfd.events = state ? CURL_WAIT_POLLIN : CURL_WAIT_POLLOUT;
			waitfd.revents = 0;
			assert(curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sock) == CURLE_OK);
			waitfd.fd = sock;
		}
		assert(curl_multi_wait(mcurl, &waitfd, sock < 0 ? 0 : 1, 5000, &mrun) == CURLM_OK);
		if (sock >= 0 && (waitfd.revents & waitfd.events)) {
			size_t len = 0;

			if (!state) {
				assert(curl_easy_send(curl, cmd + pos, sizeof(cmd) - 1 - pos, &len) == CURLE_OK);
				if (len > 0)
					pos += len;
				else
					pos = 0;
				if (pos == sizeof(cmd) - 1) {
					state++;
					pos = 0;
				}
			} else if (pos < sizeof(buf)) {
				assert(curl_easy_recv(curl, buf + pos, sizeof(buf) - pos, &len) == CURLE_OK);
				if (len > 0)
					pos += len;
			}
			if (len <= 0)
				sock = -1;
		}
	}

	if (state) {
		fwrite(buf, pos, 1, stdout);
		putchar('\n');
	}

	assert(curl_multi_remove_handle(mcurl, curl) == CURLM_OK);
	curl_easy_cleanup(curl);
	curl_multi_cleanup(mcurl);

	return 0;
}
-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette:   https://curl.haxx.se/mail/etiquette.html

Reply via email to