Hi Sönke, thanks for the quick reply :)

First, about runTask:

Regarding the runTask version, it would be interesting to see why that failed, because that would usually be the best way to implement this. What exactly went wrong in that case?

Here's what's going on in my app.d this():


shared static this()
{	
	server_dbClient = connectMongoDB("127.0.0.1");
	
	auto settings = new HTTPServerSettings;
	settings.port = 7004;
	settings.bindAddresses = ["0.0.0.0"];
	listenHTTP(settings, &unifiedHTTP);

	server_sslctx = createSSLContext(SSLContextKind.server);
	server_sslctx.useCertificateChainFile("salmon_dirserv.crt");
	server_sslctx.usePrivateKeyFile("salmon_dirserv.key");
	listenTCP(cast(ushort)8080,
	(con)
	{
		try
		{
			SSLStream theSSL = createSSLStream(con, server_sslctx);
			//do stuff with theSSL
			theSSL.finalize();
			con.close();
		}
                catch(Exception e)
                {
                        logInfo(IPv4StringFromVibe(con) ~ ":" ~ to!string(e));
                }
	});
        
        UDPListenerThread theUDP = new UDPListenerThread();
	theUDP.start();

        //(this thread is just the contents of the following runTask.)
	EmailMonitorThread theEmailMonitor = new EmailMonitorThread();
	theEmailMonitor.start();
	
	/*runTask
	({
		client_sslctx = createSSLContext(SSLContextKind.server);
		client_sslctx.useCertificateChainFile("salmon_dirserv.crt");
		client_sslctx.usePrivateKeyFile("salmon_dirserv.key");
		client_dbClient = connectMongoDB("127.0.0.1");
		emailMonitor();
	});

	runTask
	({
		UDP_dbClient = connectMongoDB("127.0.0.1");
		
		auto udpServer = listenUDP(listenOnThisUDPPort);
		logInfo("started UDP listener on port "
                         ~to!string(listenOnThisUDPPort));
		while(true)
		{
			NetworkAddress packetFrom;
			ubyte[] buf = udpServer.recv(null, &packetFrom);
			logInfo("got UDP packet from "~to!string(packetFrom));
			maybeServerDownUDP(buf, packetFrom);
		}
	});*/
	

        logInfo("GOT HERE1");
	auto sCol = server_dbClient.getCollection(serverCollection);
	logInfo("GOT HERE2");
	logInfo(to!string(sCol.find()));
	logInfo("GOT HERE3");
	sCol.remove();
	logInfo("GOT HERE4");
	logInfo(to!string(sCol.find()));
	logInfo("GOT HERE5");
	logInfo("Everything has started.");
}

In this version, that HTTP listener works fine. If I comment either the EmailMonitor thread or the UDP thread, and uncomment the corresponding runTask, the program doesn't even reach the first line of the HTTP request handler function when my browser tries to connect.

Other than HTTP, trying to interact with Mongo also hangs. I included an example at the end: only GOT HERE1,2 will print if either of the threads are replaced with the corresponding runTask().

One possible explanation could be that the event loop gets terminated before the buffer was fully written (and the connection properly closed), but it doesn't sound like that could be the case here, right?

No, unfortunately, the problematic write() is happening inside one of those threads, rather than coming from the listenTCP delegate. The thread is definitely alive long after the write() is attempted.

--vvvv output: ("going to write K in 1" is the end of a 5 second countdown I was using to know when to be looking at tcpdump.)

[4DEBABC8:00000000 trc] timer event fired
[4DEBABC8:00000000 trc] Processing due timers
[4DEBABC8:00000000 trc] first timeout: -0.0016298
[4DEBABC8:00000000 trc] Timer 5 fired (false/false)
[4DEBABC8:00000000 trc] Processing due timers
[4DEBABC8:00000000 trc] no timers scheduled
going to write K in 1...
[4DEBABC8:00000000 dbv] rearming timer 6 in 1 s
[4DEBABC8:00000000 trc] Schedule timer 6
[4DEBABC8:00000000 trc] Rescheduled timer event for 0.999779 seconds
[4DEBABC8:00000000 dbv] first timer 6 in 0.999779 s
[4DEBABC8:00000000 trc] timer event fired
[4DEBABC8:00000000 trc] Processing due timers
[4DEBABC8:00000000 trc] first timeout: -0.0016107
[4DEBABC8:00000000 trc] Timer 6 fired (false/false)
[4DEBABC8:00000000 trc] Processing due timers
[4DEBABC8:00000000 trc] no timers scheduled
[4DEBABC8:00000000 trc] evbuffer_add (fd 28): 30 B
JUST TRIED TO WRITE K
[4DEBABC8:00000000 trc] evbuffer_add (fd 28): 110 B
[4DEBABC8:00000000 trc] SSLStream finalize
[4DEBABC8:00000000 trc] evbuffer_add (fd 28): 31 B
Replying to client with: 128.174.241.44 100
[end of output]

So, I'm guessing the evbufferadd 110 B at the end is the attempt to write K, and then the evbufferadd 31 B is the "finalize" SSL record?

Anyways, thanks a lot for your help so far, to say nothing of writing vibe.d in the first place! Other than this little snag, vibe.d has been really nice to work with. Even if this remains a mystery, I can just work around it, since the server can at least indicate it wants to talk to the other side by establishing a connection.