2008-12-02 12:01:29 +01:00
/***************************************************************************
* *
* * This file is part of Qt Creator
* *
* * Copyright ( c ) 2008 Nokia Corporation and / or its subsidiary ( - ies ) .
* *
* * Contact : Qt Software Information ( qt - info @ nokia . com )
* *
2008-12-02 14:17:16 +01:00
* *
* * Non - Open Source Usage
* *
2008-12-02 12:01:29 +01:00
* * Licensees may use this file in accordance with the Qt Beta Version
* * License Agreement , Agreement version 2.2 provided with the Software or ,
* * alternatively , in accordance with the terms contained in a written
2008-12-02 14:17:16 +01:00
* * agreement between you and Nokia .
* *
* * GNU General Public License Usage
* *
2008-12-02 12:01:29 +01:00
* * Alternatively , this file may be used under the terms of the GNU General
* * Public License versions 2.0 or 3.0 as published by the Free Software
* * Foundation and appearing in the file LICENSE . GPL included in the packaging
* * of this file . Please review the following information to ensure GNU
* * General Public Licensing requirements will be met :
* *
* * http : //www.fsf.org/licensing/licenses/info/GPLv2.html and
* * http : //www.gnu.org/copyleft/gpl.html.
* *
* * In addition , as a special exception , Nokia gives you certain additional
2008-12-02 14:17:16 +01:00
* * rights . These rights are described in the Nokia Qt GPL Exception
2008-12-16 17:20:00 +01:00
* * version 1.3 , included in the file GPL_EXCEPTION . txt in this package .
2008-12-02 14:17:16 +01:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-02 12:01:29 +01:00
# include "qtlocalpeer.h"
2008-12-02 14:09:21 +01:00
2008-12-02 12:01:29 +01:00
# include <QtCore/QCoreApplication>
# include <QtCore/QTime>
# if defined(Q_OS_WIN)
# include <QtCore/QLibrary>
# include <QtCore/qt_windows.h>
typedef BOOL ( WINAPI * PProcessIdToSessionId ) ( DWORD , DWORD * ) ;
static PProcessIdToSessionId pProcessIdToSessionId = 0 ;
# endif
# if defined(Q_OS_UNIX)
# include <time.h>
# include <unistd.h>
# endif
namespace SharedTools {
2008-12-09 11:07:24 +01:00
const char * QtLocalPeer : : ack = " ack " ;
2008-12-02 12:01:29 +01:00
2008-12-09 11:07:24 +01:00
QtLocalPeer : : QtLocalPeer ( QObject * parent , const QString & appId )
2008-12-02 12:01:29 +01:00
: QObject ( parent ) , id ( appId )
{
if ( id . isEmpty ( ) )
id = QCoreApplication : : applicationFilePath ( ) ; //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win
QByteArray idc = id . toUtf8 ( ) ;
quint16 idNum = qChecksum ( idc . constData ( ) , idc . size ( ) ) ;
//### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
socketName = QLatin1String ( " qtsingleapplication- " )
+ QString : : number ( idNum , 16 ) ;
# if defined(Q_OS_WIN)
if ( ! pProcessIdToSessionId ) {
QLibrary lib ( " kernel32 " ) ;
pProcessIdToSessionId = ( PProcessIdToSessionId ) lib . resolve ( " ProcessIdToSessionId " ) ;
}
if ( pProcessIdToSessionId ) {
DWORD sessionId = 0 ;
pProcessIdToSessionId ( GetCurrentProcessId ( ) , & sessionId ) ;
socketName + = QLatin1Char ( ' - ' ) + QString : : number ( sessionId , 16 ) ;
}
# else
socketName + = QLatin1Char ( ' - ' ) + QString : : number ( : : getuid ( ) , 16 ) ;
# endif
server = new QLocalServer ( this ) ;
QString lockName = QDir ( QDir : : tempPath ( ) ) . absolutePath ( )
+ QLatin1Char ( ' / ' ) + socketName
+ QLatin1String ( " -lockfile " ) ;
lockFile . setFileName ( lockName ) ;
lockFile . open ( QIODevice : : ReadWrite ) ;
}
bool QtLocalPeer : : isClient ( )
{
if ( lockFile . isLocked ( ) )
return false ;
if ( ! lockFile . lock ( QtLockedFile : : WriteLock , false ) )
return true ;
bool res = server - > listen ( socketName ) ;
if ( ! res & & server - > serverError ( ) = = QAbstractSocket : : AddressInUseError )
res = server - > listen ( socketName ) ; // ### Workaround 4.4.0tp bug
if ( ! res )
qWarning ( " QtSingleCoreApplication: listen on local socket failed, %s " , qPrintable ( server - > errorString ( ) ) ) ;
QObject : : connect ( server , SIGNAL ( newConnection ( ) ) , SLOT ( receiveConnection ( ) ) ) ;
return false ;
}
bool QtLocalPeer : : sendMessage ( const QString & message , int timeout )
{
if ( ! isClient ( ) )
return false ;
QLocalSocket socket ;
bool connOk = false ;
2008-12-09 11:07:24 +01:00
for ( int i = 0 ; i < 2 ; i + + ) {
2008-12-02 12:01:29 +01:00
// Try twice, in case the other instance is just starting up
socket . connectToServer ( socketName ) ;
connOk = socket . waitForConnected ( timeout / 2 ) ;
if ( connOk | | i )
break ;
int ms = 250 ;
# if defined(Q_OS_WIN)
Sleep ( DWORD ( ms ) ) ;
# else
struct timespec ts = { ms / 1000 , ( ms % 1000 ) * 1000 * 1000 } ;
nanosleep ( & ts , NULL ) ;
# endif
}
if ( ! connOk )
return false ;
QByteArray uMsg ( message . toUtf8 ( ) ) ;
QDataStream ds ( & socket ) ;
ds . writeBytes ( uMsg . constData ( ) , uMsg . size ( ) ) ;
bool res = socket . waitForBytesWritten ( timeout ) ;
res & = socket . waitForReadyRead ( timeout ) ; // wait for ack
res & = ( socket . read ( qstrlen ( ack ) ) = = ack ) ;
return res ;
}
void QtLocalPeer : : receiveConnection ( )
{
QLocalSocket * socket = server - > nextPendingConnection ( ) ;
if ( ! socket )
return ;
// Why doesn't Qt have a blocking stream that takes care of this shait???
while ( socket - > bytesAvailable ( ) < sizeof ( quint32 ) )
socket - > waitForReadyRead ( ) ;
QDataStream ds ( socket ) ;
QByteArray uMsg ;
quint32 remaining ;
ds > > remaining ;
uMsg . resize ( remaining ) ;
int got = 0 ;
char * uMsgBuf = uMsg . data ( ) ;
//qDebug() << "RCV: remaining" << remaining;
do {
got = ds . readRawData ( uMsgBuf , remaining ) ;
remaining - = got ;
uMsgBuf + = got ;
//qDebug() << "RCV: got" << got << "remaining" << remaining;
} while ( remaining & & got > = 0 & & socket - > waitForReadyRead ( 2000 ) ) ;
//### error check: got<0
if ( got < 0 ) {
qWarning ( ) < < " QtLocalPeer: Message reception failed " < < socket - > errorString ( ) ;
delete socket ;
return ;
}
// ### async this
QString message ( QString : : fromUtf8 ( uMsg ) ) ;
socket - > write ( ack , qstrlen ( ack ) ) ;
socket - > waitForBytesWritten ( 1000 ) ;
delete socket ;
emit messageReceived ( message ) ; // ##(might take a long time to return)
}
2008-12-02 14:09:21 +01:00
} // namespace SharedTools