LP-106 Setup Wizard refresh : Add dual servo setup (dual aileron or
[librepilot.git] / ground / gcs / src / shared / qtsingleapplication / qtlocalpeer.cpp
blob448c26b49e5bd962e3257987644f5e5f612cec90
1 /**
2 ******************************************************************************
4 * @file qtlocalpeer.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @brief
8 * @see The GNU Public License (GPL) Version 3
9 * @defgroup
10 * @{
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "qtlocalpeer.h"
31 #include <QtCore/QCoreApplication>
32 #include <QtCore/QTime>
34 #if defined(Q_OS_WIN)
35 #include <QtCore/QLibrary>
36 #include <QtCore/qt_windows.h>
37 typedef BOOL (WINAPI * PProcessIdToSessionId)(DWORD, DWORD *);
38 static PProcessIdToSessionId pProcessIdToSessionId = 0;
39 #endif
41 #if defined(Q_OS_UNIX)
42 #include <time.h>
43 #include <unistd.h>
44 #endif
46 namespace SharedTools {
47 const char *QtLocalPeer::ack = "ack";
49 QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
50 : QObject(parent), id(appId)
52 if (id.isEmpty()) {
53 id = QCoreApplication::applicationFilePath(); // ### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win
55 QByteArray idc = id.toUtf8();
56 quint16 idNum = qChecksum(idc.constData(), idc.size());
57 // ### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
59 socketName = QLatin1String("qtsingleapplication-")
60 + QString::number(idNum, 16);
61 #if defined(Q_OS_WIN)
62 if (!pProcessIdToSessionId) {
63 QLibrary lib("kernel32");
64 pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
66 if (pProcessIdToSessionId) {
67 DWORD sessionId = 0;
68 pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
69 socketName += QLatin1Char('-') + QString::number(sessionId, 16);
71 #else
72 socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
73 #endif
75 server = new QLocalServer(this);
76 QString lockName = QDir(QDir::tempPath()).absolutePath()
77 + QLatin1Char('/') + socketName
78 + QLatin1String("-lockfile");
79 lockFile.setFileName(lockName);
80 lockFile.open(QIODevice::ReadWrite);
83 bool QtLocalPeer::isClient()
85 if (lockFile.isLocked()) {
86 return false;
89 if (!lockFile.lock(QtLockedFile::WriteLock, false)) {
90 return true;
93 if (!QLocalServer::removeServer(socketName)) {
94 qWarning("QtSingleCoreApplication: could not cleanup socket");
96 bool res = server->listen(socketName);
97 if (!res) {
98 qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
100 QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
101 return false;
104 bool QtLocalPeer::sendMessage(const QString &message, int timeout)
106 if (!isClient()) {
107 return false;
110 QLocalSocket socket;
111 bool connOk = false;
112 for (int i = 0; i < 2; i++) {
113 // Try twice, in case the other instance is just starting up
114 socket.connectToServer(socketName);
115 connOk = socket.waitForConnected(timeout / 2);
116 if (connOk || i) {
117 break;
119 int ms = 250;
120 #if defined(Q_OS_WIN)
121 Sleep(DWORD(ms));
122 #else
123 struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
124 nanosleep(&ts, NULL);
125 #endif
127 if (!connOk) {
128 return false;
131 QByteArray uMsg(message.toUtf8());
132 QDataStream ds(&socket);
133 ds.writeBytes(uMsg.constData(), uMsg.size());
134 bool res = socket.waitForBytesWritten(timeout);
135 res &= socket.waitForReadyRead(timeout); // wait for ack
136 res &= (socket.read(qstrlen(ack)) == ack);
137 return res;
140 void QtLocalPeer::receiveConnection()
142 QLocalSocket *socket = server->nextPendingConnection();
144 if (!socket) {
145 return;
148 // Why doesn't Qt have a blocking stream that takes care of this shait???
149 while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32))) {
150 socket->waitForReadyRead();
152 QDataStream ds(socket);
153 QByteArray uMsg;
154 quint32 remaining;
155 ds >> remaining;
156 uMsg.resize(remaining);
157 int got = 0;
158 char *uMsgBuf = uMsg.data();
159 // qDebug() << "RCV: remaining" << remaining;
160 do {
161 got = ds.readRawData(uMsgBuf, remaining);
162 remaining -= got;
163 uMsgBuf += got;
164 // qDebug() << "RCV: got" << got << "remaining" << remaining;
165 } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
166 // ### error check: got<0
167 if (got < 0) {
168 qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString();
169 delete socket;
170 return;
172 // ### async this
173 QString message = QString::fromUtf8(uMsg.constData(), uMsg.size());
174 socket->write(ack, qstrlen(ack));
175 socket->waitForBytesWritten(1000);
176 delete socket;
177 emit messageReceived(message); // ##(might take a long time to return)
179 } // namespace SharedTools