Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/network/socket/qlocalserver_win.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtNetwork module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4545
    4646#include <qdebug.h>
    47 #include <qdatetime.h>
    48 #include <qcoreapplication.h>
    49 #include <QMetaType>
    5047
    5148// The buffer size need to be 0 otherwise data could be
     
    5451#define BUFSIZE 0
    5552
     53
     54
     55
    5656QT_BEGIN_NAMESPACE
    5757
    58 QLocalServerThread::QLocalServerThread(QObject *parent) : QThread(parent),
    59     maxPendingConnections(1)
    60 {
    61     stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    62     gotConnectionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    63 }
    64 
    65 QLocalServerThread::~QLocalServerThread()
    66 {
    67     stop();
    68     closeServer();
    69     CloseHandle(stopEvent);
    70     CloseHandle(gotConnectionEvent);
    71 }
    72 
    73 void QLocalServerThread::stop()
    74 {
    75     if (isRunning()) {
    76         SetEvent(stopEvent);
    77         wait();
    78         ResetEvent(stopEvent);
    79     }
    80 }
    81 
    82 void QLocalServerThread::closeServer()
    83 {
    84     while (!pendingHandles.isEmpty())
    85         CloseHandle(pendingHandles.dequeue());
    86 }
    87 
    88 QString QLocalServerThread::setName(const QString &name)
    89 {
    90     QString pipePath = QLatin1String("\\\\.\\pipe\\");
    91     if (name.startsWith(pipePath))
    92         fullServerName = name;
    93     else
    94         fullServerName = pipePath + name;
    95     for (int i = pendingHandles.count(); i < maxPendingConnections; ++i)
    96         if (!makeHandle())
    97             break;
    98     return fullServerName;
    99 }
    100 
    101 bool QLocalServerThread::makeHandle()
    102 {
    103     if (pendingHandles.count() >= maxPendingConnections)
    104         return false;
    105 
    106     HANDLE handle = INVALID_HANDLE_VALUE;
    107     QT_WA({
    108     handle = CreateNamedPipeW(
    109                  (TCHAR*)fullServerName.utf16(), // pipe name
     58bool QLocalServerPrivate::addListener()
     59{
     60    // The object must not change its address once the
     61    // contained OVERLAPPED struct is passed to Windows.
     62    listeners << Listener();
     63    Listener &listener = listeners.last();
     64
     65    listener.handle = CreateNamedPipe(
     66                 (const wchar_t *)fullServerName.utf16(), // pipe name
    11067                 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access
    11168                 PIPE_TYPE_MESSAGE |       // message type pipe
     
    11774                 3000,                     // client time-out
    11875                 NULL);
    119     }, {
    120     handle = CreateNamedPipeA(
    121                  fullServerName.toLocal8Bit().constData(), // pipe name
    122                  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access
    123                  PIPE_TYPE_MESSAGE |       // message type pipe
    124                  PIPE_READMODE_MESSAGE |   // message-read mode
    125                  PIPE_WAIT,                // blocking mode
    126                  PIPE_UNLIMITED_INSTANCES, // max. instances
    127                  BUFSIZE,                  // output buffer size
    128                  BUFSIZE,                  // input buffer size
    129                  3000,                     // client time-out
    130                  NULL);
    131     });
    132 
    133     if (INVALID_HANDLE_VALUE == handle) {
     76
     77    if (listener.handle == INVALID_HANDLE_VALUE) {
     78        setError(QLatin1String("QLocalServerPrivate::addListener"));
     79        listeners.removeLast();
    13480        return false;
    13581    }
    136     pendingHandles.enqueue(handle);
     82
     83    memset(&listener.overlapped, 0, sizeof(listener.overlapped));
     84    listener.overlapped.hEvent = eventHandle;
     85    if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) {
     86        switch (GetLastError()) {
     87        case ERROR_IO_PENDING:
     88            break;
     89        case ERROR_PIPE_CONNECTED:
     90            SetEvent(eventHandle);
     91            break;
     92        default:
     93            CloseHandle(listener.handle);
     94            setError(QLatin1String("QLocalServerPrivate::addListener"));
     95            listeners.removeLast();
     96            return false;
     97        }
     98    } else {
     99        Q_ASSERT_X(false, "QLocalServerPrivate::addListener", "The impossible happened");
     100        SetEvent(eventHandle);
     101    }
    137102    return true;
    138103}
    139104
    140 void QLocalServerThread::run()
    141 {
    142     OVERLAPPED  op;
    143     HANDLE      handleArray[2];
    144     memset(&op, 0, sizeof(op));
    145     handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    146     handleArray[1] = stopEvent;
    147     HANDLE handle = INVALID_HANDLE_VALUE;
    148 
    149     forever {
    150         if (INVALID_HANDLE_VALUE == handle) {
    151             makeHandle();
    152             if (!pendingHandles.isEmpty())
    153                 handle = pendingHandles.dequeue();
    154         }
    155         if (INVALID_HANDLE_VALUE == handle) {
    156             int windowsError = GetLastError();
    157             QString function = QLatin1String("QLocalServer::run");
    158             QString errorString = QLocalServer::tr("%1: Unknown error %2").arg(function).arg(windowsError);
    159             emit error(QAbstractSocket::UnknownSocketError, errorString);
    160             CloseHandle(handleArray[0]);
    161             SetEvent(gotConnectionEvent);
    162             return;
    163         }
    164 
    165         BOOL isConnected = ConnectNamedPipe(handle, &op) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
    166         if (!isConnected) {
    167             switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE))
    168             {
    169             case WAIT_OBJECT_0 + 1:
    170                 CloseHandle(handle);
    171                 CloseHandle(handleArray[0]);
     105void QLocalServerPrivate::setError(const QString &function)
     106{
     107    int windowsError = GetLastError();
     108    errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError));
     109    error = QAbstractSocket::UnknownSocketError;
     110}
     111
     112void QLocalServerPrivate::init()
     113{
     114}
     115
     116bool QLocalServerPrivate::removeServer(const QString &name)
     117{
     118    Q_UNUSED(name);
     119    return true;
     120}
     121
     122bool QLocalServerPrivate::listen(const QString &name)
     123{
     124    Q_Q(QLocalServer);
     125
     126    QString pipePath = QLatin1String("\\\\.\\pipe\\");
     127    if (name.startsWith(pipePath))
     128        fullServerName = name;
     129    else
     130        fullServerName = pipePath + name;
     131
     132    // Use only one event for all listeners of one socket.
     133    // The idea is that listener events are rare, so polling all listeners once in a while is
     134    // cheap compared to waiting for N additional events in each iteration of the main loop.
     135    eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
     136    connectionEventNotifier = new QWinEventNotifier(eventHandle , q);
     137    q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection()));
     138
     139    for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i)
     140        if (!addListener())
     141            return false;
     142    return true;
     143}
     144
     145void QLocalServerPrivate::_q_onNewConnection()
     146{
     147    Q_Q(QLocalServer);
     148    DWORD dummy;
     149
     150    // Reset first, otherwise we could reset an event which was asserted
     151    // immediately after we checked the conn status.
     152    ResetEvent(eventHandle);
     153
     154    // Testing shows that there is indeed absolutely no guarantee which listener gets
     155    // a client connection first, so there is no way around polling all of them.
     156    for (int i = 0; i < listeners.size(); ) {
     157        HANDLE handle = listeners[i].handle;
     158        if (GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE)) {
     159            listeners.removeAt(i);
     160
     161            addListener();
     162
     163            if (pendingConnections.size() > maxPendingConnections)
     164                connectionEventNotifier->setEnabled(false);
     165
     166            // Make this the last thing so connected slots can wreak the least havoc
     167            q->incomingConnection((quintptr)handle);
     168        } else {
     169            if (GetLastError() != ERROR_IO_INCOMPLETE) {
     170                setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
     171                closeServer();
    172172                return;
    173173            }
     174
     175
    174176        }
    175         emit connected(handle);
    176         handle = INVALID_HANDLE_VALUE;
    177         ResetEvent(handleArray[0]);
    178         SetEvent(gotConnectionEvent);
    179     }
    180 }
    181 
    182 void QLocalServerPrivate::init()
    183 {
    184     Q_Q(QLocalServer);
    185     qRegisterMetaType<HANDLE>("HANDLE");
    186     q->connect(&waitForConnection, SIGNAL(connected(HANDLE)),
    187                q, SLOT(_q_openSocket(HANDLE)), Qt::QueuedConnection);
    188     q->connect(&waitForConnection, SIGNAL(finished()),
    189                q, SLOT(_q_stoppedListening()), Qt::QueuedConnection);
    190     q->connect(&waitForConnection, SIGNAL(terminated()),
    191                q, SLOT(_q_stoppedListening()), Qt::QueuedConnection);
    192     q->connect(&waitForConnection, SIGNAL(error(QAbstractSocket::SocketError, const QString &)),
    193                q, SLOT(_q_setError(QAbstractSocket::SocketError, const QString &)));
    194 }
    195 
    196 bool QLocalServerPrivate::removeServer(const QString &name)
    197 {
    198     Q_UNUSED(name);
    199     return true;
    200 }
    201 
    202 bool QLocalServerPrivate::listen(const QString &name)
    203 {
    204     fullServerName = waitForConnection.setName(name);
    205     serverName = name;
    206     waitForConnection.start();
    207     return true;
    208 }
    209 
    210 void QLocalServerPrivate::_q_setError(QAbstractSocket::SocketError e, const QString &eString)
    211 {
    212     error = e;
    213     errorString = eString;
    214 }
    215 
    216 void QLocalServerPrivate::_q_stoppedListening()
    217 {
    218     Q_Q(QLocalServer);
    219     if (!inWaitingFunction)
    220         q->close();
    221 }
    222 
    223 void QLocalServerPrivate::_q_openSocket(HANDLE handle)
    224 {
    225     Q_Q(QLocalServer);
    226     q->incomingConnection((int)handle);
     177    }
    227178}
    228179
    229180void QLocalServerPrivate::closeServer()
    230181{
    231     waitForConnection.stop();
    232     waitForConnection.closeServer();
     182    connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs
     183    connectionEventNotifier->deleteLater();
     184    connectionEventNotifier = 0;
     185    CloseHandle(eventHandle);
     186    for (int i = 0; i < listeners.size(); ++i)
     187        CloseHandle(listeners[i].handle);
     188    listeners.clear();
    233189}
    234190
     
    239195        return;
    240196
    241     DWORD result = WaitForSingleObject(waitForConnection.gotConnectionEvent,
    242                                        (msecs == -1) ? INFINITE : msecs);
     197    DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs);
    243198    if (result == WAIT_TIMEOUT) {
    244199        if (timedOut)
    245200            *timedOut = true;
    246201    } else {
    247         ResetEvent(waitForConnection.gotConnectionEvent);
    248         QCoreApplication::instance()->processEvents();
     202        _q_onNewConnection();
    249203    }
    250204}
Note: See TracChangeset for help on using the changeset viewer.