176
164
mir::send_fds(socket_fd, fds);
179
void mclr::StreamSocketTransport::init()
167
mir::Fd mclr::StreamSocketTransport::watch_fd() const
181
// We use sockets rather than a pipe so that we can control
182
// EPIPE behaviour; we don't want SIGPIPE when the IO loop terminates.
184
socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds);
185
this->shutdown_fd = mir::Fd{socket_fds[1]};
187
auto shutdown_fd = mir::Fd{socket_fds[0]};
188
io_service_thread = std::thread([this, shutdown_fd]
172
bool mclr::StreamSocketTransport::dispatch(md::FdEvents events)
174
if (events & (md::FdEvent::remote_closed | md::FdEvent::error))
190
// Our IO threads must not receive any signals
191
sigset_t all_signals;
192
sigfillset(&all_signals);
194
if (auto error = pthread_sigmask(SIG_BLOCK, &all_signals, NULL))
195
BOOST_THROW_EXCEPTION(
196
boost::enable_error_info(
197
std::runtime_error("Failed to block signals on IO thread")) << boost::errinfo_errno(error));
199
mir::set_thread_name("Client IO loop");
201
int epoll_fd = epoll_create1(0);
204
// Make valgrind happy, harder
205
memset(&event, 0, sizeof(event));
207
event.events = EPOLLIN | EPOLLRDHUP;
208
event.data.fd = socket_fd;
209
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &event);
211
event.events = EPOLLIN | EPOLLRDHUP;
212
event.data.fd = shutdown_fd;
213
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, shutdown_fd, &event);
215
bool shutdown_requested{false};
216
while (!shutdown_requested)
176
if (events & md::FdEvent::readable)
219
epoll_wait(epoll_fd, &event, 1, -1);
220
if (event.data.fd == socket_fd)
222
if (event.events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR))
224
if (event.events & EPOLLIN)
226
// If the remote end shut down cleanly it's possible there's some more
227
// data left to read, or that reads will now return 0 (EOF)
229
// If there's more data left to read, notify of this before disconnect.
231
if (recv(socket_fd, &dummy, sizeof(dummy), MSG_PEEK | MSG_NOSIGNAL) > 0)
235
notify_data_available();
239
//It's quite likely that notify_data_available() will lead to
240
//an exception being thrown; after all, the remote has closed
243
//This doesn't matter; we're already shutting down.
247
notify_disconnected();
248
shutdown_requested = true;
250
else if (event.events & EPOLLIN)
254
notify_data_available();
256
catch (socket_disconnected_error &err)
258
// We've already notified of disconnection.
259
shutdown_requested = true;
261
// These need not be fatal.
262
catch (fd_reception_error &err)
265
catch (socket_error &err)
270
// We've no idea what the problem is, so clean up as best we can.
271
notify_disconnected();
272
shutdown_requested = true;
276
if (event.data.fd == shutdown_fd)
278
shutdown_requested = true;
178
// If the remote end shut down cleanly it's possible there's some more
179
// data left to read, or that reads will now return 0 (EOF)
181
// If there's more data left to read, notify of this before disconnect.
183
if (recv(socket_fd, &dummy, sizeof(dummy), MSG_PEEK | MSG_NOSIGNAL) > 0)
185
notify_data_available();
189
notify_disconnected();
192
else if (events & md::FdEvent::readable)
194
notify_data_available();
199
md::FdEvents mclr::StreamSocketTransport::relevant_events() const
201
return md::FdEvent::readable | md::FdEvent::remote_closed;
285
204
mir::Fd mclr::StreamSocketTransport::open_socket(std::string const& path)