11#include " ClientSocket.hpp"
22#include " ../../helpers/Memory.hpp"
33#include " ../../helpers/Log.hpp"
4+ #include " ../../helpers/Syscalls.hpp"
45#include " ../../Macros.hpp"
56#include " ../message/MessageParser.hpp"
67#include " ../message/messages/IMessage.hpp"
@@ -30,6 +31,10 @@ using namespace Hyprwire;
3031using namespace Hyprutils ::OS ;
3132using namespace Hyprutils ::Utils;
3233
34+ namespace {
35+ std::chrono::milliseconds g_handshakeMax = std::chrono::milliseconds(5000 );
36+ }
37+
3338SP <IClientSocket> IClientSocket::open (const std::string& path) {
3439 SP <CClientSocket> sock = makeShared<CClientSocket>();
3540 sock->m_self = sock;
@@ -101,18 +106,34 @@ void CClientSocket::addImplementation(SP<IProtocolClientImplementation>&& x) {
101106 m_impls.emplace_back (std::move (x));
102107}
103108
104- constexpr const size_t HANDSHAKE_MAX_MS = 5000 ;
109+ void CClientSocket::setHandshakeTimeoutForTests (std::chrono::milliseconds timeout) {
110+ g_handshakeMax = timeout;
111+ }
112+
113+ void CClientSocket::resetHandshakeTimeoutForTests () {
114+ g_handshakeMax = std::chrono::milliseconds (5000 );
115+ }
105116
106117//
107118bool CClientSocket::dispatchEvents (bool block) {
108119
109120 if (m_error)
110121 return false ;
111122
123+ collectOrphanedObjects ();
124+
112125 if (!m_handshakeDone) {
113- const auto MAX_MS =
114- std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::milliseconds (HANDSHAKE_MAX_MS ) - (std::chrono::steady_clock::now () - m_handshakeBegin)).count ();
115- int ret = poll (m_pollfds.data (), m_pollfds.size (), block ? MAX_MS : 0 );
126+ const auto elapsed = std::chrono::steady_clock::now () - m_handshakeBegin;
127+ const auto maxMs = g_handshakeMax;
128+
129+ if (block && elapsed >= maxMs) {
130+ Debug::log (ERR , " handshake error: timed out" );
131+ disconnectOnError ();
132+ return false ;
133+ }
134+
135+ const auto timeout = block ? std::chrono::duration_cast<std::chrono::milliseconds>(maxMs - elapsed).count () : 0 ;
136+ int ret = Syscalls::poll (m_pollfds.data (), m_pollfds.size (), static_cast <int >(timeout));
116137 if (block && !ret) {
117138 Debug::log (ERR , " handshake error: timed out" );
118139 disconnectOnError ();
@@ -121,13 +142,15 @@ bool CClientSocket::dispatchEvents(bool block) {
121142 }
122143
123144 if (m_handshakeDone)
124- poll (m_pollfds.data (), m_pollfds.size (), block ? -1 : 0 );
145+ Syscalls:: poll (m_pollfds.data (), m_pollfds.size (), block ? -1 : 0 );
125146
126147 if (m_pollfds[0 ].revents & POLLHUP )
127148 return false ;
128149
129- if (!(m_pollfds[0 ].revents & POLLIN ))
150+ if (!(m_pollfds[0 ].revents & POLLIN )) {
151+ collectOrphanedObjects ();
130152 return true ;
153+ }
131154
132155 // dispatch
133156
@@ -165,6 +188,8 @@ bool CClientSocket::dispatchEvents(bool block) {
165188 return true ;
166189 });
167190
191+ collectOrphanedObjects ();
192+
168193 return !m_error;
169194}
170195
@@ -203,13 +228,13 @@ void CClientSocket::sendMessage(const IMessage& message) {
203228 }
204229
205230 while (m_fd.isValid ()) {
206- int ret = sendmsg (m_fd.get (), &msg, 0 );
231+ int ret = Syscalls:: sendmsg (m_fd.get (), &msg, 0 );
207232 if (ret < 0 && (errno == EWOULDBLOCK || errno == EAGAIN )) {
208233 pollfd pfd = {
209234 .fd = m_fd.get (),
210235 .events = POLLOUT | POLLWRBAND ,
211236 };
212- poll (&pfd, 1 , -1 );
237+ Syscalls:: poll (&pfd, 1 , -1 );
213238 } else
214239 break ;
215240 }
@@ -327,14 +352,38 @@ void CClientSocket::waitForObject(SP<IWireObject> x) {
327352}
328353
329354void CClientSocket::onGeneric (const CGenericProtocolMessage& msg) {
355+ SP <CClientObject> object;
356+
330357 for (const auto & o : m_objects) {
331- if (o->m_id == msg.m_object ) {
332- o-> called (msg. m_method , msg. m_dataSpan , msg. m_fds ) ;
333- return ;
358+ if (o && o ->m_id == msg.m_object ) {
359+ object = o ;
360+ break ;
334361 }
335362 }
336363
337- Debug::log (WARN , " [{} @ {:.3f}] -> Generic message not handled. No object with id {}!" , m_fd.get (), steadyMillis (), msg.m_object );
364+ if (!object) {
365+ Debug::log (ERR , " [{} @ {:.3f}] -> Generic message references unknown object {}" , m_fd.get (), steadyMillis (), msg.m_object );
366+ disconnectOnError ();
367+ return ;
368+ }
369+
370+ object->called (msg.m_method , msg.m_dataSpan , msg.m_fds );
371+ }
372+
373+ void CClientSocket::destroyObject (uint32_t id) {
374+ std::erase_if (m_objects, [id](const auto & obj) { return obj && obj->m_id == id; });
375+ }
376+
377+ void CClientSocket::collectOrphanedObjects () {
378+ std::erase_if (m_objects, [](const auto & obj) {
379+ if (!obj)
380+ return true ;
381+
382+ if (obj->m_id == 0 )
383+ return false ;
384+
385+ return obj.strongRef () == 1 ;
386+ });
338387}
339388
340389SP <IObject> CClientSocket::objectForId (uint32_t id) {
0 commit comments