Add stuff :)
This commit is contained in:
parent
971038fd4f
commit
301765a5bd
182
xbanan/main.cpp
182
xbanan/main.cpp
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <BAN/Array.h>
|
||||||
#include <BAN/ByteSpan.h>
|
#include <BAN/ByteSpan.h>
|
||||||
#include <BAN/Endianness.h>
|
#include <BAN/Endianness.h>
|
||||||
#include <BAN/Optional.h>
|
#include <BAN/Optional.h>
|
||||||
|
|
@ -317,13 +318,15 @@ xVisualType visual {
|
||||||
|
|
||||||
struct Client
|
struct Client
|
||||||
{
|
{
|
||||||
enum class State
|
enum class State : uint8_t
|
||||||
{
|
{
|
||||||
ConnectionSetup,
|
ConnectionSetup,
|
||||||
Connected,
|
Connected,
|
||||||
};
|
};
|
||||||
int fd;
|
int fd;
|
||||||
State state;
|
State state;
|
||||||
|
bool has_epollout { false };
|
||||||
|
bool has_bigrequests { false };
|
||||||
CARD16 sequence { 0 };
|
CARD16 sequence { 0 };
|
||||||
BAN::Vector<uint8_t> input_buffer;
|
BAN::Vector<uint8_t> input_buffer;
|
||||||
BAN::Vector<uint8_t> output_buffer;
|
BAN::Vector<uint8_t> output_buffer;
|
||||||
|
|
@ -331,6 +334,17 @@ struct Client
|
||||||
BAN::HashMap<CARD32, BAN::UniqPtr<Object>> objects;
|
BAN::HashMap<CARD32, BAN::UniqPtr<Object>> objects;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Extension
|
||||||
|
{
|
||||||
|
BAN::StringView name;
|
||||||
|
uint8_t major_opcode;
|
||||||
|
uint8_t opcode_count;
|
||||||
|
BAN::ErrorOr<void> (*handler)(Client&, BAN::ConstByteSpan);
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t g_extension_opcode { 128 };
|
||||||
|
BAN::Array<Extension, 128> g_extensions;
|
||||||
|
|
||||||
BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
||||||
BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
||||||
ATOM atom_value = XA_LAST_PREDEFINED + 1;
|
ATOM atom_value = XA_LAST_PREDEFINED + 1;
|
||||||
|
|
@ -634,6 +648,8 @@ void _invalidate_window_recursive(Client& client_info, WINDOW wid, int32_t x, in
|
||||||
{
|
{
|
||||||
ASSERT(wid != root.windowId);
|
ASSERT(wid != root.windowId);
|
||||||
|
|
||||||
|
if (x + w <= 0 || y + h <= 0)
|
||||||
|
return;
|
||||||
if (w <= 0 || h <= 0)
|
if (w <= 0 || h <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -653,16 +669,22 @@ void _invalidate_window_recursive(Client& client_info, WINDOW wid, int32_t x, in
|
||||||
if (!child_window.mapped)
|
if (!child_window.mapped)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const auto child_x = x - child_window.x;
|
||||||
|
const auto child_y = y - child_window.y;
|
||||||
|
|
||||||
|
const auto child_w = BAN::Math::min<int32_t>(w - child_window.x, child_window.texture().width() - child_x);
|
||||||
|
const auto child_h = BAN::Math::min<int32_t>(h - child_window.y, child_window.texture().height() - child_y);
|
||||||
|
|
||||||
_invalidate_window_recursive(
|
_invalidate_window_recursive(
|
||||||
client_info,
|
client_info,
|
||||||
child_wid,
|
child_wid,
|
||||||
x - child_window.x,
|
child_x, child_y,
|
||||||
y - child_window.y,
|
child_w, child_h
|
||||||
w - child_window.x,
|
|
||||||
h - child_window.y
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dwarnln("invalidate {} {},{} -> {},{}", wid, x, y, x + w, y + h);
|
||||||
|
|
||||||
if (window.window.has<BAN::UniqPtr<LibGUI::Window>>())
|
if (window.window.has<BAN::UniqPtr<LibGUI::Window>>())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -672,8 +694,8 @@ void _invalidate_window_recursive(Client& client_info, WINDOW wid, int32_t x, in
|
||||||
auto& parent_window = parent_object.object.get<Object::Window>();
|
auto& parent_window = parent_object.object.get<Object::Window>();
|
||||||
parent_window.texture().copy_texture(
|
parent_window.texture().copy_texture(
|
||||||
window.texture(),
|
window.texture(),
|
||||||
parent_window.x + x,
|
window.x + x,
|
||||||
parent_window.y + y,
|
window.y + y,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
w,
|
w,
|
||||||
|
|
@ -728,7 +750,7 @@ void invalidate_window(Client& client_info, WINDOW wid, int32_t x, int32_t y, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.window.get<BAN::UniqPtr<LibGUI::Window>>()->invalidate(x, y, w, h);
|
window.window.get<BAN::UniqPtr<LibGUI::Window>>()->invalidate(min_x, min_y, max_x - min_x, max_y - min_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||||
|
|
@ -753,10 +775,10 @@ BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||||
auto attributes = gui_window->get_attributes();
|
auto attributes = gui_window->get_attributes();
|
||||||
attributes.shown = true;
|
attributes.shown = true;
|
||||||
gui_window->set_attributes(attributes);
|
gui_window->set_attributes(attributes);
|
||||||
}
|
|
||||||
|
|
||||||
if (is_visible(client_info, window.parent))
|
gui_window->texture().clear();
|
||||||
TRY(send_visibility_events_recursively(client_info, wid, true));
|
gui_window->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
if (window.event_mask & StructureNotifyMask)
|
if (window.event_mask & StructureNotifyMask)
|
||||||
{
|
{
|
||||||
|
|
@ -790,6 +812,9 @@ BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||||
TRY(encode(client_info.output_buffer, event));
|
TRY(encode(client_info.output_buffer, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_visible(client_info, window.parent))
|
||||||
|
TRY(send_visibility_events_recursively(client_info, wid, true));
|
||||||
|
|
||||||
if (window.event_mask & ExposureMask)
|
if (window.event_mask & ExposureMask)
|
||||||
{
|
{
|
||||||
xEvent event = { .u = {
|
xEvent event = { .u = {
|
||||||
|
|
@ -994,6 +1019,15 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
|
|
||||||
client_info.sequence++;
|
client_info.sequence++;
|
||||||
|
|
||||||
|
if (packet[0] >= 128)
|
||||||
|
{
|
||||||
|
const auto& extension = g_extensions[packet[0] - 128];
|
||||||
|
if (extension.handler != nullptr)
|
||||||
|
return extension.handler(client_info, packet);
|
||||||
|
dwarnln("invalid opcode {}", packet[0]);
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
switch (packet[0])
|
switch (packet[0])
|
||||||
{
|
{
|
||||||
case X_CreateWindow:
|
case X_CreateWindow:
|
||||||
|
|
@ -1014,7 +1048,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
dprintln(" mask: {8h}", request.mask);
|
dprintln(" mask: {8h}", request.mask);
|
||||||
|
|
||||||
uint32_t event_mask { 0 };
|
uint32_t event_mask { 0 };
|
||||||
uint32_t background { 0x000000 };
|
uint32_t background { 0xFF00FF };
|
||||||
|
|
||||||
for (size_t i = 0; i < 32; i++)
|
for (size_t i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -1077,7 +1111,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
auto& parent_window = parent_object->object.get<Object::Window>();
|
auto& parent_window = parent_object->object.get<Object::Window>();
|
||||||
TRY(parent_window.children.push_back(request.wid));
|
TRY(parent_window.children.push_back(request.wid));
|
||||||
|
|
||||||
auto it = TRY(client_info.objects.insert(
|
TRY(client_info.objects.insert(
|
||||||
request.wid,
|
request.wid,
|
||||||
TRY(BAN::UniqPtr<Object>::create(Object {
|
TRY(BAN::UniqPtr<Object>::create(Object {
|
||||||
.type = Object::Type::Window,
|
.type = Object::Type::Window,
|
||||||
|
|
@ -1637,7 +1671,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& property = it->value;
|
auto& property = it->value;
|
||||||
ASSERT(property.type == request.type);
|
|
||||||
ASSERT(property.format == request.format);
|
ASSERT(property.format == request.format);
|
||||||
|
|
||||||
const size_t bytes = (request.format / 8) * request.nUnits;
|
const size_t bytes = (request.format / 8) * request.nUnits;
|
||||||
|
|
@ -1650,11 +1683,13 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
memcpy(property.data.data(), packet.data(), bytes);
|
memcpy(property.data.data(), packet.data(), bytes);
|
||||||
break;
|
break;
|
||||||
case PropModePrepend:
|
case PropModePrepend:
|
||||||
|
ASSERT(property.type == request.type);
|
||||||
TRY(property.data.resize(old_bytes + bytes));
|
TRY(property.data.resize(old_bytes + bytes));
|
||||||
memmove(property.data.data() + old_bytes, property.data.data(), old_bytes);
|
memmove(property.data.data() + old_bytes, property.data.data(), old_bytes);
|
||||||
memcpy(property.data.data(), packet.data(), bytes);
|
memcpy(property.data.data(), packet.data(), bytes);
|
||||||
break;
|
break;
|
||||||
case PropModeAppend:
|
case PropModeAppend:
|
||||||
|
ASSERT(property.type == request.type);
|
||||||
TRY(property.data.resize(old_bytes + bytes));
|
TRY(property.data.resize(old_bytes + bytes));
|
||||||
memcpy(property.data.data() + old_bytes, packet.data(), bytes);
|
memcpy(property.data.data() + old_bytes, packet.data(), bytes);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2223,7 +2258,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
data_u32[y * w + x] = foreground;
|
data_u32[y * w + x] = foreground;
|
||||||
|
|
||||||
if (object.type == Object::Type::Window)
|
if (object.type == Object::Type::Window)
|
||||||
invalidate_window(client_info, request.drawable, rect.x, rect.y, rect.width, rect.height);
|
invalidate_window(client_info, request.drawable, min_x, min_y, max_x - min_x, max_y - min_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -2269,8 +2304,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
const int32_t min_x = BAN::Math::max<int32_t>(0, arc.x);
|
const int32_t min_x = BAN::Math::max<int32_t>(0, arc.x);
|
||||||
const int32_t min_y = BAN::Math::max<int32_t>(0, arc.y);
|
const int32_t min_y = BAN::Math::max<int32_t>(0, arc.y);
|
||||||
|
|
||||||
const int32_t max_x = BAN::Math::max<int32_t>(texture.width(), arc.x + arc.width);
|
const int32_t max_x = BAN::Math::min<int32_t>(texture.width(), arc.x + arc.width);
|
||||||
const int32_t max_y = BAN::Math::max<int32_t>(texture.height(), arc.y + arc.height);
|
const int32_t max_y = BAN::Math::min<int32_t>(texture.height(), arc.y + arc.height);
|
||||||
|
|
||||||
const auto rx = arc.width / 2;
|
const auto rx = arc.width / 2;
|
||||||
const auto ry = arc.height / 2;
|
const auto ry = arc.height / 2;
|
||||||
|
|
@ -2490,6 +2525,16 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
.first_event = 0,
|
.first_event = 0,
|
||||||
.first_error = 0,
|
.first_error = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (const auto& extension : g_extensions)
|
||||||
|
{
|
||||||
|
if (extension.name != name)
|
||||||
|
continue;
|
||||||
|
reply.present = xTrue;
|
||||||
|
reply.major_opcode = extension.major_opcode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
TRY(encode(client_info.output_buffer, reply));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -2557,6 +2602,50 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> extension_bigrequests(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
|
{
|
||||||
|
switch (packet[1])
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
xGenericReply reply {
|
||||||
|
.type = X_Reply,
|
||||||
|
.sequenceNumber = client_info.sequence,
|
||||||
|
.length = 0,
|
||||||
|
.data00 = (16 << 20) / 4, // 16 MiB
|
||||||
|
};
|
||||||
|
TRY(encode(client_info.output_buffer, reply));
|
||||||
|
|
||||||
|
client_info.has_bigrequests = true;
|
||||||
|
|
||||||
|
dprintln("client enabled big requests");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
dwarnln("invalid BIG-REQUESTS minor opcode {}", packet[1]);
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void install_extensions()
|
||||||
|
{
|
||||||
|
const auto install_extension =
|
||||||
|
[](BAN::StringView name, BAN::ErrorOr<void> (*handler)(Client&, BAN::ConstByteSpan))
|
||||||
|
{
|
||||||
|
g_extensions[g_extension_opcode - 128] = {
|
||||||
|
.name = name,
|
||||||
|
.major_opcode = g_extension_opcode,
|
||||||
|
.handler = handler,
|
||||||
|
};
|
||||||
|
g_extension_opcode++;
|
||||||
|
};
|
||||||
|
|
||||||
|
install_extension("BIG-REQUESTS"_sv, extension_bigrequests);
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
for (int sig = 1; sig < NSIG; sig++)
|
for (int sig = 1; sig < NSIG; sig++)
|
||||||
|
|
@ -2694,6 +2783,8 @@ int main()
|
||||||
APPEND_ATOM(XA_WM_TRANSIENT_FOR);
|
APPEND_ATOM(XA_WM_TRANSIENT_FOR);
|
||||||
#undef APPEND_ATOM
|
#undef APPEND_ATOM
|
||||||
|
|
||||||
|
install_extensions();
|
||||||
|
|
||||||
printf("xbanan started\n");
|
printf("xbanan started\n");
|
||||||
|
|
||||||
const auto close_client =
|
const auto close_client =
|
||||||
|
|
@ -2773,7 +2864,13 @@ int main()
|
||||||
ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
|
ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
|
||||||
|
|
||||||
auto& client_info = epoll_thingy.value.get<Client>();
|
auto& client_info = epoll_thingy.value.get<Client>();
|
||||||
|
|
||||||
|
if (events[i].events & EPOLLHUP)
|
||||||
|
{
|
||||||
|
close_client(client_info.fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (events[i].events & EPOLLOUT)
|
if (events[i].events & EPOLLOUT)
|
||||||
{
|
{
|
||||||
const ssize_t nsend = send(
|
const ssize_t nsend = send(
|
||||||
|
|
@ -2783,11 +2880,14 @@ int main()
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (nsend == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||||
|
goto send_done;
|
||||||
|
|
||||||
if (nsend < 0)
|
if (nsend < 0)
|
||||||
perror("xbanan: send");
|
perror("xbanan: send");
|
||||||
if (nsend <= 0)
|
if (nsend <= 0)
|
||||||
{
|
{
|
||||||
close_client(events[i].data.fd);
|
close_client(client_info.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2804,10 +2904,15 @@ int main()
|
||||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
|
if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
|
||||||
{
|
{
|
||||||
perror("xbanan: epoll_ctl");
|
perror("xbanan: epoll_ctl");
|
||||||
close_client(events[i].data.fd);
|
close_client(client_info.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_info.has_epollout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send_done:
|
||||||
|
(void)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(events[i].events & EPOLLIN))
|
if (!(events[i].events & EPOLLIN))
|
||||||
|
|
@ -2818,12 +2923,13 @@ int main()
|
||||||
case Client::State::ConnectionSetup:
|
case Client::State::ConnectionSetup:
|
||||||
{
|
{
|
||||||
xConnClientPrefix client_prefix;
|
xConnClientPrefix client_prefix;
|
||||||
ssize_t nrecv = recv(client_info.fd, &client_prefix, sizeof(client_prefix), 0);
|
|
||||||
|
const ssize_t nrecv = recv(client_info.fd, &client_prefix, sizeof(client_prefix), 0);
|
||||||
if (nrecv < 0)
|
if (nrecv < 0)
|
||||||
perror("xbanan: recv");
|
perror("xbanan: recv");
|
||||||
if (nrecv <= 0)
|
if (nrecv <= 0)
|
||||||
{
|
{
|
||||||
close_client(events[i].data.fd);
|
close_client(client_info.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2832,7 +2938,7 @@ int main()
|
||||||
if (auto ret = setup_client_conneciton(client_info, client_prefix); ret.is_error())
|
if (auto ret = setup_client_conneciton(client_info, client_prefix); ret.is_error())
|
||||||
{
|
{
|
||||||
dwarnln("setup_client_connection: {}", ret.error());
|
dwarnln("setup_client_connection: {}", ret.error());
|
||||||
close_client(events[i].data.fd);
|
close_client(client_info.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2842,12 +2948,12 @@ int main()
|
||||||
{
|
{
|
||||||
char buffer[1024] {};
|
char buffer[1024] {};
|
||||||
|
|
||||||
ssize_t nrecv = recv(client_info.fd, buffer, sizeof(buffer), 0);
|
const ssize_t nrecv = recv(client_info.fd, buffer, sizeof(buffer), 0);
|
||||||
if (nrecv < 0)
|
if (nrecv < 0)
|
||||||
perror("xbanan: recv");
|
perror("xbanan: recv");
|
||||||
if (nrecv <= 0)
|
if (nrecv <= 0)
|
||||||
{
|
{
|
||||||
close_client(events[i].data.fd);
|
close_client(client_info.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2860,16 +2966,34 @@ int main()
|
||||||
if (client_info.input_buffer.size() < 4)
|
if (client_info.input_buffer.size() < 4)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const uint32_t byte_length = 4 * reinterpret_cast<const uint16_t*>(client_info.input_buffer.data())[1];
|
bool is_big_request = false;
|
||||||
|
uint32_t byte_length = 4 * *reinterpret_cast<const uint16_t*>(client_info.input_buffer.data() + 2);
|
||||||
|
|
||||||
|
if (byte_length == 0 && client_info.has_bigrequests)
|
||||||
|
{
|
||||||
|
if (client_info.input_buffer.size() < 8)
|
||||||
|
break;
|
||||||
|
byte_length = 4 * *reinterpret_cast<const uint32_t*>(client_info.input_buffer.data() + 4);
|
||||||
|
is_big_request = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (client_info.input_buffer.size() < byte_length)
|
if (client_info.input_buffer.size() < byte_length)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto packet = BAN::ConstByteSpan(client_info.input_buffer.span()).slice(0, byte_length);
|
auto packet = BAN::ConstByteSpan(client_info.input_buffer.span()).slice(0, byte_length);
|
||||||
|
if (is_big_request)
|
||||||
|
{
|
||||||
|
auto* input_u32 = reinterpret_cast<uint32_t*>(client_info.input_buffer.data());
|
||||||
|
input_u32[1] = input_u32[0];
|
||||||
|
packet = packet.slice(4);
|
||||||
|
|
||||||
|
dprintln("handling big request");
|
||||||
|
}
|
||||||
|
|
||||||
if (auto ret = handle_packet(client_info, packet); ret.is_error())
|
if (auto ret = handle_packet(client_info, packet); ret.is_error())
|
||||||
{
|
{
|
||||||
dwarnln("handle_packet: {}", ret.error());
|
dwarnln("handle_packet: {}", ret.error());
|
||||||
close_client(events[i].data.fd);
|
close_client(client_info.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2889,7 +3013,7 @@ int main()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto& client_info = thingy.value.get<Client>();
|
auto& client_info = thingy.value.get<Client>();
|
||||||
if (client_info.output_buffer.empty())
|
if (client_info.output_buffer.empty() || client_info.has_epollout)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
epoll_event event { .events = EPOLLIN | EPOLLOUT, .data = { .fd = client_info.fd } };
|
epoll_event event { .events = EPOLLIN | EPOLLOUT, .data = { .fd = client_info.fd } };
|
||||||
|
|
@ -2899,6 +3023,8 @@ int main()
|
||||||
close_client(client_info.fd);
|
close_client(client_info.fd);
|
||||||
goto iterator_invalidated;
|
goto iterator_invalidated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_info.has_epollout = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue