Implement proper zero size wait semantics for Posix stream sockets.

This commit is contained in:
Sönke Ludwig 2017-01-22 10:47:58 +01:00
parent ca81d25645
commit 58c89a7369
2 changed files with 75 additions and 6 deletions

View file

@ -399,10 +399,10 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
final override void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish) final override void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish)
{ {
if (buffer.length == 0) { /*if (buffer.length == 0) {
on_read_finish(socket, IOStatus.ok, 0); on_read_finish(socket, IOStatus.ok, 0);
return; return;
} }*/
sizediff_t ret; sizediff_t ret;
() @trusted { ret = .recv(socket, buffer.ptr, buffer.length, 0); } (); () @trusted { ret = .recv(socket, buffer.ptr, buffer.length, 0); } ();
@ -417,11 +417,13 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
} }
if (ret == 0) { if (ret == 0) {
print("disconnect");
on_read_finish(socket, IOStatus.disconnected, 0); on_read_finish(socket, IOStatus.disconnected, 0);
return; return;
} }
if (ret < 0 && mode == IOMode.immediate) { if (ret < 0 && mode == IOMode.immediate) {
print("wouldblock");
on_read_finish(socket, IOStatus.wouldBlock, 0); on_read_finish(socket, IOStatus.wouldBlock, 0);
return; return;
} }
@ -469,7 +471,8 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
slot.readCallback(socket, status, slot.bytesRead); slot.readCallback(socket, status, slot.bytesRead);
} }
sizediff_t ret; sizediff_t ret = 0;
if (!slot.readBuffer.length)
() @trusted { ret = .recv(socket, slot.readBuffer.ptr, slot.readBuffer.length, 0); } (); () @trusted { ret = .recv(socket, slot.readBuffer.ptr, slot.readBuffer.length, 0); } ();
if (ret < 0) { if (ret < 0) {
auto err = getSocketError(); auto err = getSocketError();
@ -479,13 +482,13 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
} }
} }
if (ret == 0) { if (ret == 0 && slot.readBuffer.length) {
slot.state = ConnectionState.passiveClose; slot.state = ConnectionState.passiveClose;
finalize(IOStatus.disconnected); finalize(IOStatus.disconnected);
return; return;
} }
if (ret > 0) { if (ret > 0 || !slot.readBuffer.length) {
slot.bytesRead += ret; slot.bytesRead += ret;
slot.readBuffer = slot.readBuffer[ret .. $]; slot.readBuffer = slot.readBuffer[ret .. $];
if (slot.readMode != IOMode.all || slot.readBuffer.length == 0) { if (slot.readMode != IOMode.all || slot.readBuffer.length == 0) {

66
tests/0-tcp-readwait.d Normal file
View file

@ -0,0 +1,66 @@
/++ dub.sdl:
name "test"
dependency "eventcore" path=".."
+/
module test;
import eventcore.core;
import eventcore.socket;
import std.socket : InternetAddress;
import core.time : Duration, msecs;
ubyte[256] s_rbuf;
bool s_done;
void main()
{
static ubyte[] pack1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
auto baddr = new InternetAddress(0x7F000001, 40002);
auto server = listenStream(baddr);
StreamSocket client;
StreamSocket incoming;
server.waitForConnections!((incoming_, addr) {
incoming = incoming_; // work around ref counting issue
incoming.read!((status, bts) {
assert(status == IOStatus.ok);
assert(bts == 0);
incoming.read!((status, bts) {
assert(status == IOStatus.ok);
assert(bts == pack1.length);
assert(s_rbuf[0 .. bts] == pack1);
destroy(incoming);
destroy(server);
destroy(client);
s_done = true;
// FIXME: this shouldn't ne necessary:
eventDriver.core.exit();
})(s_rbuf, IOMode.immediate);
})(s_rbuf[0 .. 0], IOMode.once);
});
connectStream!((sock, status) {
assert(status == ConnectStatus.connected);
client = sock;
auto tm = eventDriver.timers.create();
eventDriver.timers.set(tm, 100.msecs, 0.msecs);
eventDriver.timers.wait(tm, (tm) {
client.write!((wstatus, bytes) {
assert(wstatus == IOStatus.ok);
assert(bytes == 10);
})(pack1, IOMode.all);
});
})(baddr);
ExitReason er;
do er = eventDriver.core.processEvents(Duration.max);
while (er == ExitReason.idle);
//assert(er == ExitReason.outOfWaiters); // FIXME: see above
assert(s_done);
s_done = false;
}