net.server: Add a predrain callaback just before writes

Allows sneaking in things in the write buffer just before it's sent to
the network stack. For example ack requests, compression flushes or
other things that make sense to send after stanzas or other things.
This ensures any additional trailing data sent is included in the same
write, and possibly the same TCP packet. Other methods used such as
timers or nextTick might not have the same effect as it depends on
scheduling.
This commit is contained in:
Kim Alvefur 2021-08-16 12:34:52 +02:00
parent b686dda4af
commit d06ae16295
3 changed files with 11 additions and 0 deletions

View file

@ -472,6 +472,7 @@ end
function interface:onwritable()
self:onconnect();
if not self.conn then return; end -- could have been closed in onconnect
self:on("predrain");
local buffer = self.writebuffer;
local data = buffer or "";
if type(buffer) == "table" then

View file

@ -449,6 +449,7 @@ function interface_mt:setlistener(listener, data)
self.onstatus = listener.onstatus;
self.ondetach = listener.ondetach;
self.onattach = listener.onattach;
self.onpredrain = listener.onpredrain;
self.ondrain = listener.ondrain;
self:onattach(data);
end
@ -464,6 +465,8 @@ function interface_mt:ontimeout()
end
function interface_mt:onreadtimeout()
end
function interface_mt:onpredrain()
end
function interface_mt:ondrain()
end
function interface_mt:ondetach()
@ -490,6 +493,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx
onincoming = listener.onincoming; -- will be called when client sends data
ontimeout = listener.ontimeout; -- called when fatal socket timeout occurs
onreadtimeout = listener.onreadtimeout; -- called when socket inactivity timeout occurs
onpredrain = listener.onpredrain; -- called before writes
ondrain = listener.ondrain; -- called when writebuffer is empty
ondetach = listener.ondetach; -- called when disassociating this listener from this connection
onstatus = listener.onstatus; -- called for status changes (e.g. of SSL/TLS)
@ -540,6 +544,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx
interface.eventwritetimeout = false
end
end
interface:onpredrain();
interface.writebuffer = { t_concat(interface.writebuffer) }
local succ, err, byte = interface.conn:send( interface.writebuffer[1], 1, interface.writebufferlen )
--vdebug( "write data:", interface.writebuffer, "error:", err, "part:", byte )

View file

@ -294,6 +294,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
local dispatch = listeners.onincoming
local status = listeners.onstatus
local disconnect = listeners.ondisconnect
local predrain = listeners.onpredrain
local drain = listeners.ondrain
local onreadtimeout = listeners.onreadtimeout;
local detach = listeners.ondetach
@ -338,6 +339,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
dispatch = listeners.onincoming
disconnect = listeners.ondisconnect
status = listeners.onstatus
predrain = listeners.onpredrain
drain = listeners.ondrain
handler.onreadtimeout = listeners.onreadtimeout
detach = listeners.ondetach
@ -552,6 +554,9 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
listeners.onconnect(handler);
end
end
if predrain then
predrain(handler);
end
buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
succ, err, byte = send( socket, buffer, 1, bufferlen )
count = ( succ or byte or 0 ) * STAT_UNIT