no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / third_party / wayland-proxy / wayland-proxy.cpp
blob493df7bd8a62055f3c095ec40024559e214fff7c
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // This code is based on Rust implementation at
7 // https://github.com/the8472/weyland-p5000
9 // Version 1.1
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdarg.h>
14 #include <sys/ioctl.h>
15 #include <sys/socket.h>
16 #include <sys/stat.h>
17 #include <sys/wait.h>
18 #include <sys/un.h>
19 #include <spawn.h>
20 #include <poll.h>
21 #include <vector>
22 #include <cerrno>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <memory>
26 #include <cassert>
27 #include <pthread.h>
28 #include <sched.h>
30 #include "wayland-proxy.h"
32 // The maximum number of fds libwayland can recvmsg at once
33 #define MAX_LIBWAY_FDS 28
34 #define MAX_DATA_SIZE 4096
35 #define POLL_TIMEOUT 30000
37 bool sPrintInfo = false;
39 void Print(const char* aFormat, ...) {
40 if (!sPrintInfo) {
41 return;
43 va_list args;
44 va_start(args, aFormat);
45 vfprintf(stderr, aFormat, args);
46 va_end(args);
49 void Warning(const char* aOperation) {
50 fprintf(stderr, "Warning: %s : %s\n", aOperation, strerror(errno));
53 void Error(const char* aOperation) {
54 fprintf(stderr, "Error: %s : %s\n", aOperation, strerror(errno));
57 void ErrorPlain(const char* aFormat, ...) {
58 va_list args;
59 va_start(args, aFormat);
60 vfprintf(stderr, aFormat, args);
61 va_end(args);
64 class WaylandMessage {
65 public:
66 bool Write(int aSocket);
68 bool Loaded() const { return !mFailed && (mFds.size() || mData.size()); }
69 bool Failed() const { return mFailed; }
71 explicit WaylandMessage(int aSocket) { Read(aSocket); }
72 ~WaylandMessage();
74 private:
75 void Read(int aSocket);
77 private:
78 bool mFailed = false;
80 std::vector<int> mFds;
81 std::vector<unsigned char> mData;
84 class ProxiedConnection {
85 public:
86 bool Init(int aChildSocket, char* aWaylandDisplay);
87 bool IsConnected() { return mCompositorConnected; }
89 struct pollfd* AddToPollFd(struct pollfd* aPfds);
90 struct pollfd* LoadPollFd(struct pollfd* aPfds);
92 // Process this connection (send/receive data).
93 // Returns false if connection is broken and should be removed.
94 bool Process();
96 ~ProxiedConnection();
98 private:
99 // Try to connect to compositor. Returns false in case of fatal error.
100 bool ConnectToCompositor();
102 bool TransferOrQueue(
103 int aSourceSocket, int aSourcePollFlags, int aDestSocket,
104 std::vector<std::unique_ptr<WaylandMessage>>* aMessageQueue);
105 bool FlushQueue(int aDestSocket, int aDestPollFlags,
106 std::vector<std::unique_ptr<WaylandMessage>>& aMessageQueue);
108 // Where we should connect.
109 // Weak pointer to parent WaylandProxy class.
110 char* mWaylandDisplay = nullptr;
112 // We don't have connected compositor yet. Try to connect
113 bool mCompositorConnected = false;
115 // We're disconnected from app or compositor. We will close this connection.
116 bool mFailed = false;
118 int mCompositorSocket = -1;
119 int mCompositorFlags = 0;
121 int mApplicationSocket = -1;
122 int mApplicationFlags = 0;
124 // Stored proxied data
125 std::vector<std::unique_ptr<WaylandMessage>> mToCompositorQueue;
126 std::vector<std::unique_ptr<WaylandMessage>> mToApplicationQueue;
129 WaylandMessage::~WaylandMessage() {
130 for (auto const fd : mFds) {
131 close(fd);
135 void WaylandMessage::Read(int aSocket) {
136 // We don't expect WaylandMessage re-read
137 assert(!Loaded() && !mFailed);
139 mData.resize(MAX_DATA_SIZE);
141 struct msghdr msg = {0};
142 struct iovec iov = {mData.data(), mData.size()};
143 msg.msg_iov = &iov;
144 msg.msg_iovlen = 1;
146 char cmsgdata[(CMSG_LEN(MAX_LIBWAY_FDS * sizeof(int32_t)))] = {0};
147 msg.msg_control = &cmsgdata;
148 msg.msg_controllen = sizeof(cmsgdata);
150 ssize_t ret = recvmsg(aSocket, &msg, MSG_CMSG_CLOEXEC | MSG_DONTWAIT);
151 if (msg.msg_flags & (MSG_CTRUNC | MSG_TRUNC)) {
152 Error("WaylandMessage::Read() data truncated, small buffer?");
153 mFailed = true;
154 return;
157 if (ret < 1) {
158 switch (errno) {
159 case EAGAIN:
160 case EINTR:
161 // Neither loaded nor failed, we'll try again later
162 Print("WaylandMessage::Read() failed %s\n", strerror(errno));
163 return;
164 default:
165 Error("WaylandMessage::Read() failed");
166 mFailed = true;
167 return;
171 // Set correct data size
172 mData.resize(ret);
174 // Read cmsg
175 struct cmsghdr* header = CMSG_FIRSTHDR(&msg);
176 while (header) {
177 struct cmsghdr* next = CMSG_NXTHDR(&msg, header);
178 if (header->cmsg_level != SOL_SOCKET || header->cmsg_type != SCM_RIGHTS) {
179 header = next;
180 continue;
183 int* data = (int*)CMSG_DATA(header);
184 int filenum = (int)((header->cmsg_len - CMSG_LEN(0)) / sizeof(int));
185 if (filenum > MAX_LIBWAY_FDS) {
186 ErrorPlain("WaylandMessage::Read(): too many files to read");
187 mFailed = true;
188 return;
190 for (int i = 0; i < filenum; i++) {
191 #ifdef DEBUG
192 int flags = fcntl(data[i], F_GETFL, 0);
193 if (flags == -1 && errno == EBADF) {
194 Error("WaylandMessage::Read() invalid fd");
196 #endif
197 mFds.push_back(data[i]);
199 header = next;
203 bool WaylandMessage::Write(int aSocket) {
204 if (!Loaded()) {
205 return false;
208 struct msghdr msg = {0};
209 struct iovec iov = {mData.data(), mData.size()};
210 msg.msg_iov = &iov;
211 msg.msg_iovlen = 1;
213 union {
214 char buf[CMSG_SPACE(sizeof(int) * MAX_LIBWAY_FDS)];
215 struct cmsghdr align;
216 } cmsgu;
217 memset(cmsgu.buf, 0, sizeof(cmsgu.buf));
219 int filenum = mFds.size();
220 if (filenum) {
221 if (filenum > MAX_LIBWAY_FDS) {
222 ErrorPlain("WaylandMessage::Write() too many files to send\n");
223 return false;
225 #ifdef DEBUG
226 for (int i = 0; i < filenum; i++) {
227 int flags = fcntl(mFds[i], F_GETFL, 0);
228 if (flags == -1 && errno == EBADF) {
229 Error("WaylandMessage::Write() invalid fd\n");
232 #endif
233 msg.msg_control = cmsgu.buf;
234 msg.msg_controllen = CMSG_SPACE(filenum * sizeof(int));
236 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
237 cmsg->cmsg_level = SOL_SOCKET;
238 cmsg->cmsg_type = SCM_RIGHTS;
239 cmsg->cmsg_len = CMSG_LEN(filenum * sizeof(int));
240 memcpy(CMSG_DATA(cmsg), mFds.data(), filenum * sizeof(int));
243 ssize_t ret = sendmsg(aSocket, &msg, MSG_CMSG_CLOEXEC | MSG_DONTWAIT);
244 if (ret < 1) {
245 switch (errno) {
246 case EAGAIN:
247 case EINTR:
248 // Neither loaded nor failed, we'll try again later
249 Print("WaylandMessage::Write() failed %s\n", strerror(errno));
250 return false;
251 default:
252 Warning("WaylandMessage::Write() failed");
253 mFailed = true;
254 return false;
258 if (ret != (ssize_t)mData.size()) {
259 Print("WaylandMessage::Write() failed to write all data! (%d vs. %d)\n", ret,
260 mData.size());
262 return true;
265 ProxiedConnection::~ProxiedConnection() {
266 if (mCompositorSocket != -1) {
267 close(mCompositorSocket);
269 if (mApplicationSocket != -1) {
270 close(mApplicationSocket);
274 bool ProxiedConnection::Init(int aApplicationSocket, char* aWaylandDisplay) {
275 mWaylandDisplay = aWaylandDisplay;
276 mApplicationSocket = aApplicationSocket;
277 mCompositorSocket =
278 socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
279 if (mCompositorSocket == -1) {
280 Error("WaylandProxy: ProxiedConnection::Init() socket()");
282 bool ret = mApplicationSocket >= 0 && mCompositorSocket >= 0;
283 Print("WaylandProxy: ProxiedConnection::Init() %s\n", ret ? "OK" : "FAILED");
284 return ret;
287 struct pollfd* ProxiedConnection::AddToPollFd(struct pollfd* aPfds) {
288 // Listen application's requests
289 aPfds->fd = mApplicationSocket;
290 aPfds->events = POLLIN;
292 // We're connected and we have data for appplication from compositor.
293 // Add POLLOUT to request write to app socket.
294 if (mCompositorConnected && !mToApplicationQueue.empty()) {
295 aPfds->events |= POLLOUT;
297 aPfds++;
299 aPfds->fd = mCompositorSocket;
300 aPfds->events = 0;
301 // We're waiting for connection or we have data for compositor
302 if (!mCompositorConnected || !mToCompositorQueue.empty()) {
303 aPfds->events |= POLLOUT;
305 if (mCompositorConnected) {
306 aPfds->events |= POLLIN;
308 aPfds++;
310 return aPfds;
313 struct pollfd* ProxiedConnection::LoadPollFd(struct pollfd* aPfds) {
314 if (aPfds->fd != mApplicationSocket) {
315 return aPfds;
317 mApplicationFlags = aPfds->revents;
318 aPfds++;
319 mCompositorFlags = aPfds->revents;
320 aPfds++;
321 return aPfds;
324 bool ProxiedConnection::ConnectToCompositor() {
325 if (!(mCompositorFlags & POLLOUT)) {
326 // Try again later
327 return true;
330 struct sockaddr_un addr = {};
331 addr.sun_family = AF_UNIX;
332 strcpy(addr.sun_path, mWaylandDisplay);
334 mCompositorConnected =
335 connect(mCompositorSocket, (const struct sockaddr*)&addr,
336 sizeof(struct sockaddr_un)) != -1;
337 if (!mCompositorConnected) {
338 switch (errno) {
339 case EAGAIN:
340 case EALREADY:
341 case ECONNREFUSED:
342 case EINPROGRESS:
343 case EINTR:
344 case EISCONN:
345 case ETIMEDOUT:
346 // We can recover from these errors and try again
347 Warning("ConnectToCompositor() try again");
348 return true;
349 default:
350 Error("ConnectToCompositor() connect()");
351 return false;
354 return true;
357 // Read data from aSourceSocket and try to twite them to aDestSocket.
358 // If data write fails, append them to aMessageQueue.
359 // Return
360 bool ProxiedConnection::TransferOrQueue(
361 int aSourceSocket, int aSourcePollFlags, int aDestSocket,
362 std::vector<std::unique_ptr<WaylandMessage>>* aMessageQueue) {
363 // Don't read if we don't have any data ready
364 if (!(aSourcePollFlags & POLLIN)) {
365 return true;
368 while (1) {
369 int availableData = 0;
370 if (ioctl(aSourceSocket, FIONREAD, &availableData) < 0) {
371 // Broken connection, we're finished here
372 Warning("ProxiedConnection::TransferOrQueue() broken source socket %s\n");
373 return false;
375 if (availableData == 0) {
376 return true;
379 auto message = std::make_unique<WaylandMessage>(aSourceSocket);
380 if (message->Failed()) {
381 // Failed to read message due to error
382 return false;
384 if (!message->Loaded()) {
385 // Let's try again
386 return true;
388 if (!message->Write(aDestSocket)) {
389 if (message->Failed()) {
390 // Failed to write and we can't recover
391 return false;
393 aMessageQueue->push_back(std::move(message));
398 // Try to flush all data to aMessageQueue.
399 bool ProxiedConnection::FlushQueue(
400 int aDestSocket, int aDestPollFlags,
401 std::vector<std::unique_ptr<WaylandMessage>>& aMessageQueue) {
402 // Can't write to destination yet
403 if (!(aDestPollFlags & POLLOUT) || aMessageQueue.empty()) {
404 return true;
407 std::vector<std::unique_ptr<WaylandMessage>>::iterator message;
408 for (message = aMessageQueue.begin(); message != aMessageQueue.end();) {
409 if (!(*message)->Write(aDestSocket)) {
410 // Failed to write the message, remove whole connection
411 // as it's broken.
412 if ((*message)->Failed()) {
413 return false;
415 break;
417 message++;
420 // Remove all written messages at once.
421 if (message != aMessageQueue.begin()) {
422 aMessageQueue.erase(aMessageQueue.begin(), message);
425 return true;
428 bool ProxiedConnection::Process() {
429 if (mFailed) {
430 return false;
433 // Check if appplication is still listening
434 if (mApplicationFlags & (POLLHUP | POLLERR)) {
435 return false;
438 // Check if compositor is still listening
439 if (mCompositorConnected) {
440 if (mCompositorFlags & (POLLHUP | POLLERR)) {
441 return false;
443 } else {
444 // Try to reconnect to compositor.
445 if (!ConnectToCompositor()) {
446 Print("Failed to connect to compositor\n");
447 return false;
449 // We're not connected yet but ConnectToCompositor() didn't return
450 // fatal error. Try again later.
451 if (!mCompositorConnected) {
452 return true;
456 mFailed =
457 !TransferOrQueue(mCompositorSocket, mCompositorFlags, mApplicationSocket,
458 &mToApplicationQueue) ||
459 !TransferOrQueue(mApplicationSocket, mApplicationFlags, mCompositorSocket,
460 &mToCompositorQueue) ||
461 !FlushQueue(mCompositorSocket, mCompositorFlags, mToCompositorQueue) ||
462 !FlushQueue(mApplicationSocket, mApplicationFlags, mToApplicationQueue);
464 return !mFailed;
467 bool WaylandProxy::CheckWaylandDisplay(const char* aWaylandDisplay) {
468 struct sockaddr_un addr = {};
469 addr.sun_family = AF_UNIX;
470 strcpy(addr.sun_path, aWaylandDisplay);
472 int sc = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
473 if (sc == -1) {
474 Error("CheckWaylandDisplay(): failed to create socket");
475 return false;
478 bool ret =
479 connect(sc, (const struct sockaddr*)&addr,
480 sizeof(struct sockaddr_un)) != -1;
481 if (!ret) {
482 switch (errno) {
483 case EAGAIN:
484 case EALREADY:
485 case ECONNREFUSED:
486 case EINPROGRESS:
487 case EINTR:
488 case EISCONN:
489 case ETIMEDOUT:
490 // We can recover from these errors and try again
491 ret = true;
492 break;
493 default:
494 ErrorPlain(
495 "CheckWaylandDisplay(): Failed to connect to Wayland display '%s' error: %s\n",
496 mWaylandDisplay, strerror(errno));
497 break;
501 close(sc);
502 return ret;
506 bool WaylandProxy::SetupWaylandDisplays() {
507 char* waylandDisplay = getenv("WAYLAND_DISPLAY_COMPOSITOR");
508 if (!waylandDisplay) {
509 waylandDisplay = getenv("WAYLAND_DISPLAY");
510 if (!waylandDisplay || waylandDisplay[0] == '\0') {
511 ErrorPlain("WaylandProxy::SetupWaylandDisplays(), Missing Wayland display, WAYLAND_DISPLAY is empty.");
512 return false;
516 char* XDGRuntimeDir = getenv("XDG_RUNTIME_DIR");
517 if (!XDGRuntimeDir) {
518 ErrorPlain("WaylandProxy::SetupWaylandDisplays() Missing XDG_RUNTIME_DIR");
519 return false;
522 // WAYLAND_DISPLAY can be absolute path
523 if (waylandDisplay[0] == '/') {
524 if (strlen(mWaylandDisplay) >= sMaxDisplayNameLen) {
525 ErrorPlain("WaylandProxy::SetupWaylandDisplays() WAYLAND_DISPLAY is too large.");
526 return false;
528 strcpy(mWaylandDisplay, waylandDisplay);
529 } else {
530 int ret = snprintf(mWaylandDisplay, sMaxDisplayNameLen, "%s/%s",
531 XDGRuntimeDir, waylandDisplay);
532 if (ret < 0 || ret >= sMaxDisplayNameLen) {
533 ErrorPlain("WaylandProxy::SetupWaylandDisplays() WAYLAND_DISPLAY/XDG_RUNTIME_DIR is too large.");
534 return false;
538 if (!CheckWaylandDisplay(mWaylandDisplay)) {
539 return false;
542 int ret = snprintf(mWaylandProxy, sMaxDisplayNameLen,
543 "%s/wayland-proxy-%d", XDGRuntimeDir, getpid());
544 if (ret < 0 || ret >= sMaxDisplayNameLen) {
545 ErrorPlain("WaylandProxy::SetupWaylandDisplays() WAYLAND_DISPLAY/XDG_RUNTIME_DIR is too large.");
546 return false;
549 // Save original Wayland display variable for potential reuse
550 setenv("WAYLAND_DISPLAY_COMPOSITOR", waylandDisplay, /* overwrite = */ true);
552 Info("SetupWaylandDisplays() Wayland '%s' proxy '%s'\n",
553 mWaylandDisplay, mWaylandProxy);
554 return true;
557 bool WaylandProxy::StartProxyServer() {
558 mProxyServerSocket =
559 socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
560 if (mProxyServerSocket == -1) {
561 Error("StartProxyServer(): failed to create socket");
562 return false;
565 struct sockaddr_un serverName = {0};
566 serverName.sun_family = AF_UNIX;
567 strcpy(serverName.sun_path, mWaylandProxy);
569 if (bind(mProxyServerSocket, (struct sockaddr*)&serverName,
570 sizeof(serverName)) == -1) {
571 Error("StartProxyServer(): bind() error");
572 return false;
574 if (listen(mProxyServerSocket, 128) == -1) {
575 Error("StartProxyServer(): listen() error");
576 return false;
579 return true;
582 bool WaylandProxy::Init() {
583 Info("Init()\n");
585 if (!SetupWaylandDisplays()) {
586 return false;
589 if (!StartProxyServer()) {
590 return false;
593 Info("Init() finished\n");
594 return true;
597 void WaylandProxy::SetWaylandProxyDisplay() {
598 Info("SetWaylandProxyDisplay() WAYLAND_DISPLAY %s\n", mWaylandDisplay);
599 setenv("WAYLAND_DISPLAY", mWaylandProxy, /* overwrite = */ true);
602 void WaylandProxy::RestoreWaylandDisplay() {
603 unlink(mWaylandProxy);
604 char* waylandDisplay = getenv("WAYLAND_DISPLAY_COMPOSITOR");
605 if (waylandDisplay) {
606 Info("RestoreWaylandDisplay() WAYLAND_DISPLAY restored to %s\n",
607 waylandDisplay);
608 setenv("WAYLAND_DISPLAY", waylandDisplay, /* overwrite = */ true);
609 unsetenv("WAYLAND_DISPLAY_COMPOSITOR");
613 bool WaylandProxy::IsChildAppTerminated() {
614 if (!mApplicationPID) {
615 return false;
617 int status = 0;
618 int ret = waitpid(mApplicationPID, &status, WNOHANG | WUNTRACED | WCONTINUED);
619 if (ret == 0) {
620 return false;
622 if (ret == mApplicationPID) {
623 // Child application is terminated, so quit too.
624 return true;
626 bool terminate = (errno == ECHILD);
627 Error("IsChildAppTerminated: waitpid() error");
628 return terminate;
631 bool WaylandProxy::PollConnections() {
632 int nfds_max = mConnections.size() * 2 + 1;
634 struct pollfd pollfds[nfds_max];
635 struct pollfd* addedPollfd = pollfds;
637 for (auto const& connection : mConnections) {
638 addedPollfd = connection->AddToPollFd(addedPollfd);
640 int nfds = (addedPollfd - pollfds);
642 // If all connections are attached to compositor, add another one
643 // for new potential connection from application.
644 bool addNewConnection = mConnections.empty() ||
645 mConnections.back()->IsConnected();
646 if (addNewConnection) {
647 addedPollfd->fd = mProxyServerSocket;
648 addedPollfd->events = POLLIN;
649 nfds++;
651 assert(addedPollfd < pollfds + nfds_max);
653 while (1) {
654 int ret = poll(pollfds, nfds, POLL_TIMEOUT);
655 if (ret == 0) {
656 // No change on fds
657 continue;
658 } else if (ret > 0) {
659 // We have FD to read
660 break;
661 } else if (ret == -1) {
662 switch (errno) {
663 case EINTR:
664 case EAGAIN:
665 if (IsChildAppTerminated()) {
666 return false;
668 continue;
669 default:
670 Error("Run: poll() error");
671 return false;
676 struct pollfd* loadedPollfd = pollfds;
677 for (auto const& connection : mConnections) {
678 loadedPollfd = connection->LoadPollFd(loadedPollfd);
681 assert(loadedPollfd == addedPollfd);
682 assert(loadedPollfd < pollfds + nfds_max);
684 // Create a new connection if there's a new client waiting
685 if (addNewConnection && (loadedPollfd->revents & POLLIN)) {
686 Info("new child connection\n");
687 int applicationSocket = accept4(loadedPollfd->fd, nullptr, nullptr,
688 SOCK_NONBLOCK | SOCK_CLOEXEC);
689 if (applicationSocket == -1) {
690 switch (errno) {
691 case EAGAIN:
692 case EINTR:
693 // Try again later
694 break;
695 default:
696 Error("Faild to accept connection from application");
697 return false;
699 } else {
700 auto connection = std::make_unique<ProxiedConnection>();
701 if (connection->Init(applicationSocket, mWaylandDisplay)) {
702 mConnections.push_back(std::move(connection));
707 return true;
710 bool WaylandProxy::ProcessConnections() {
711 std::vector<std::unique_ptr<ProxiedConnection>>::iterator connection;
712 for (connection = mConnections.begin(); connection != mConnections.end();) {
713 if (!(*connection)->Process()) {
714 Info("remove connection\n");
715 connection = mConnections.erase(connection);
716 if (mConnections.empty()) {
717 // We removed last connection - quit.
718 Info("removed last connection, quit\n");
719 return false;
721 } else {
722 connection++;
725 return true;
728 void WaylandProxy::Run() {
729 while (!IsChildAppTerminated() && PollConnections() && ProcessConnections())
733 WaylandProxy::~WaylandProxy() {
734 Info("terminated\n");
735 if (mThreadRunning) {
736 Info("thread is still running, terminating.\n");
737 mThreadRunning = false;
738 pthread_cancel(mThread);
739 pthread_join(mThread, nullptr);
741 if (mProxyServerSocket != -1) {
742 close(mProxyServerSocket);
744 RestoreWaylandDisplay();
747 void* WaylandProxy::RunProxyThread(WaylandProxy* aProxy) {
748 #ifdef __linux__
749 pthread_setname_np(pthread_self(), "WaylandProxy");
750 #endif
751 aProxy->Run();
752 Print("[%d] WaylandProxy [%p]: thread exited.\n", getpid(), aProxy);
753 return nullptr;
756 std::unique_ptr<WaylandProxy> WaylandProxy::Create() {
757 auto proxy = std::make_unique<WaylandProxy>();
758 Print("[%d] WaylandProxy [%p]: Created().\n", getpid(), proxy.get());
759 if (!proxy->Init()) {
760 Print("[%d] WaylandProxy [%p]: Init failed, exiting.\n", getpid(), proxy.get());
761 return nullptr;
763 return proxy;
766 bool WaylandProxy::RunChildApplication(char* argv[]) {
767 if (!argv[0]) {
768 ErrorPlain("WaylandProxy::RunChildApplication: missing application to run");
769 return false;
772 mApplicationPID = fork();
773 if (mApplicationPID == -1) {
774 Error("WaylandProxy::RunChildApplication: fork() error");
775 return false;
777 if (mApplicationPID == 0) {
778 SetWaylandProxyDisplay();
779 if (execv(argv[0], argv) == -1) {
780 ErrorPlain(
781 "WaylandProxy::RunChildApplication: failed to run %s error %s\n",
782 argv[0], strerror(errno));
783 exit(1);
787 Run();
788 return true;
791 bool WaylandProxy::RunThread() {
792 pthread_attr_t attr;
793 if (pthread_attr_init(&attr) != 0) {
794 ErrorPlain("WaylandProxy::RunThread(): pthread_attr_init() failed\n");
795 return false;
798 sched_param param;
799 if (pthread_attr_getschedparam(&attr, &param) == 0) {
800 param.sched_priority = sched_get_priority_min(SCHED_RR);
801 pthread_attr_setschedparam(&attr, &param);
804 SetWaylandProxyDisplay();
806 mThreadRunning = pthread_create(&mThread, nullptr, (void* (*)(void*))RunProxyThread, this) == 0;
807 if (!mThreadRunning) {
808 ErrorPlain("WaylandProxy::RunThread(): pthread_create() failed\n");
809 // If we failed to run proxy thread, set WAYLAND_DISPLAY back.
810 RestoreWaylandDisplay();
813 pthread_attr_destroy(&attr);
814 return mThreadRunning;
817 void WaylandProxy::SetVerbose(bool aVerbose) { sPrintInfo = aVerbose; }
819 void WaylandProxy::Info(const char* aFormat, ...) {
820 if (!sPrintInfo) {
821 return;
823 fprintf(stderr,"[%d] WaylandProxy [%p]: ", getpid(), this);
824 va_list args;
825 va_start(args, aFormat);
826 vfprintf(stderr, aFormat, args);
827 va_end(args);
830 void WaylandProxy::Warning(const char* aOperation) {
831 fprintf(stderr, "[%d] Wayland Proxy [%p] Warning: %s : %s\n",
832 getpid(), this, aOperation, strerror(errno));
835 void WaylandProxy::Error(const char* aOperation) {
836 fprintf(stderr, "[%d] Wayland Proxy [%p] Error: %s : %s\n",
837 getpid(), this, aOperation, strerror(errno));
840 void WaylandProxy::ErrorPlain(const char* aFormat, ...) {
841 fprintf(stderr, "[%d] Wayland Proxy [%p] Error: ", getpid(), this);
842 va_list args;
843 va_start(args, aFormat);
844 vfprintf(stderr, aFormat, args);
845 va_end(args);