<commit_before>/*************************************************************************
 *
 *  $RCSfile: ZipOutputStream.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: mtg $ $Date: 2001-04-27 14:56:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _ZIP_OUTPUT_STREAM_HXX
#define _ZIP_OUTPUT_STREAM_HXX

#ifndef _BYTE_CHUCKER_HXX_
#include <ByteChucker.hxx>
#endif
#ifndef _DEFLATER_HXX
#include <Deflater.hxx>
#endif
#ifndef _CRC32_HXX
#include <CRC32.hxx>
#endif
#ifndef __SGI_STL_VECTOR
#include <vector>
#endif
#ifndef _RTL_CIPHER_H_
#include <rtl/cipher.h>
#endif
#ifndef _COM_SUN_STAR_PACKAGES_ZIPENTRY_HPP_
#include <com/sun/star/packages/ZipEntry.hpp>
#endif
#ifndef _VOS_REF_H_
#include <vos/ref.hxx>
#endif

class EncryptionData;
class ZipOutputStream
{
private:
    com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > xStream;
    ::std::vector < ::com::sun::star::packages::ZipEntry *>         aZipList;
    com::sun::star::uno::Sequence < sal_Int8 > aBuffer;
    com::sun::star::uno::Sequence < sal_Int8 > aEncryptionBuffer;
    ::rtl::OUString     sComment;
    Deflater            aDeflater;
    rtlCipher           aCipher;
    CRC32               aCRC;
    ByteChucker         aChucker;
    com::sun::star::packages::ZipEntry          *pCurrentEntry;
    sal_Int16           nMethod;
    sal_Int16           nLevel;
    sal_Bool            bFinished;
    sal_Bool            bEncryptCurrentEntry;

public:
    ZipOutputStream( com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > &xOStream, sal_Int32 nNewBufferSize);
    ~ZipOutputStream(void);

    void SAL_CALL setEncryptionKey ( com::sun::star::uno::Sequence < sal_Int8 > &rKey, com::sun::star::packages::ZipEntry & rEntry );
    static com::sun::star::uno::Sequence < sal_Int8 > getInitialisationVector();
    // rawWrite to support a direct write to the output stream
    void SAL_CALL rawWrite( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer)
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL rawCloseEntry(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // XZipOutputStream interfaces
    void SAL_CALL setComment( const ::rtl::OUString& rComment )
        throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL setMethod( sal_Int32 nNewMethod )
        throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL setLevel( sal_Int32 nNewLevel )
        throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL putNextEntry( ::com::sun::star::packages::ZipEntry& rEntry,
            const vos::ORef < EncryptionData > &rData,
            sal_Bool bEncrypt = sal_False )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL closeEntry(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL write( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL finish(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL close(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    static sal_uInt32 getCurrentDosTime ( );
protected:
    void doDeflate();
    void writeEND(sal_uInt32 nOffset, sal_uInt32 nLength)
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void writeCEN( const com::sun::star::packages::ZipEntry &rEntry )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void writeEXT( const com::sun::star::packages::ZipEntry &rEntry )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void writeLOC( const com::sun::star::packages::ZipEntry &rEntry )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

};

#endif
<commit_msg>remove unused methods and add nCurrentDataBegin member to track uncompressed stream size<commit_after>/*************************************************************************
 *
 *  $RCSfile: ZipOutputStream.hxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: mtg $ $Date: 2001-05-08 13:49:54 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _ZIP_OUTPUT_STREAM_HXX
#define _ZIP_OUTPUT_STREAM_HXX

#ifndef _BYTE_CHUCKER_HXX_
#include <ByteChucker.hxx>
#endif
#ifndef _DEFLATER_HXX
#include <Deflater.hxx>
#endif
#ifndef _CRC32_HXX
#include <CRC32.hxx>
#endif
#ifndef __SGI_STL_VECTOR
#include <vector>
#endif
#ifndef _RTL_CIPHER_H_
#include <rtl/cipher.h>
#endif
#ifndef _COM_SUN_STAR_PACKAGES_ZIPENTRY_HPP_
#include <com/sun/star/packages/ZipEntry.hpp>
#endif
#ifndef _VOS_REF_H_
#include <vos/ref.hxx>
#endif

class EncryptionData;
class ZipOutputStream
{
protected:
    com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > xStream;
    ::std::vector < ::com::sun::star::packages::ZipEntry *>         aZipList;
    com::sun::star::uno::Sequence < sal_Int8 > aBuffer;
    com::sun::star::uno::Sequence < sal_Int8 > aEncryptionBuffer;
    ::rtl::OUString     sComment;
    Deflater            aDeflater;
    rtlCipher           aCipher;
    CRC32               aCRC;
    ByteChucker         aChucker;
    com::sun::star::packages::ZipEntry          *pCurrentEntry;
    sal_Int16           nMethod;
    sal_Int16           nLevel;
    sal_Bool            bFinished;
    sal_Bool            bEncryptCurrentEntry;
    sal_Int32           nCurrentDataBegin;

public:
    ZipOutputStream( com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > &xOStream, sal_Int32 nNewBufferSize);
    ~ZipOutputStream(void);

    // rawWrite to support a direct write to the output stream
    void SAL_CALL rawWrite( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer)
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL rawCloseEntry(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // XZipOutputStream interfaces
    void SAL_CALL setComment( const ::rtl::OUString& rComment )
        throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL setMethod( sal_Int32 nNewMethod )
        throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL setLevel( sal_Int32 nNewLevel )
        throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL putNextEntry( ::com::sun::star::packages::ZipEntry& rEntry,
            const vos::ORef < EncryptionData > &rData,
            sal_Bool bEncrypt = sal_False )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL closeEntry(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL write( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL finish(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL close(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    static sal_uInt32 getCurrentDosTime ( );
protected:
    void doDeflate();
    void writeEND(sal_uInt32 nOffset, sal_uInt32 nLength)
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void writeCEN( const com::sun::star::packages::ZipEntry &rEntry )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void writeEXT( const com::sun::star::packages::ZipEntry &rEntry )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void writeLOC( const com::sun::star::packages::ZipEntry &rEntry )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

};

#endif
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013 lailongwei<lailongwei@126.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "llbc/common/Export.h"

#include "llbc/core/os/OS_Atomic.h"

#include "llbc/core/thread/MessageBlock.h"
#include "llbc/core/thread/ThreadManager.h"
#include "llbc/core/thread/Guard.h"
#include "llbc/core/thread/Task.h"

__LLBC_INTERNAL_NS_BEGIN

int static __LLBC_BaseTaskEntry(void *arg)
{
    LLBC_NS LLBC_BaseTask *task = reinterpret_cast<LLBC_NS LLBC_BaseTask *>(arg);

    LLBC_NS __LLBC_LibTls *tls = LLBC_NS __LLBC_GetLibTls();

    tls->coreTls.task = task;

    task->OnTaskThreadStart();
    task->Svc();
    task->OnTaskThreadStop();

    tls->coreTls.task = nullptr;

    return 0;
}

__LLBC_INTERNAL_NS_END

__LLBC_NS_BEGIN

LLBC_BaseTask::LLBC_BaseTask(LLBC_ThreadManager *threadMgr)
: _threadNum(0)
, _curThreadNum(0)
, _startCompleted(false)
, _threadManager(threadMgr ? threadMgr : LLBC_ThreadManagerSingleton)
, _taskThreads(nullptr)
{
}

LLBC_BaseTask::~LLBC_BaseTask()
{
    Wait();
    LLBC_XFree(_taskThreads);
}

int LLBC_BaseTask::Activate(int threadNum,
                            int flags,
                            int priority,
                            LLBC_Handle groupHandle,
                            const int stackSize[])
{
    _lock.Lock();

    LLBC_XFree(_taskThreads);
    _taskThreads = LLBC_Calloc(LLBC_Handle, threadNum * sizeof(LLBC_Handle));
    if (_threadManager->CreateThreads(threadNum,
                                      &LLBC_INTERNAL_NS __LLBC_BaseTaskEntry,
                                      this,
                                      flags,
                                      priority,
                                      stackSize,
                                      this,
                                      groupHandle,
                                      nullptr,
                                      _taskThreads) == LLBC_INVALID_HANDLE)
    {
        LLBC_XFree(_taskThreads);
        _lock.Unlock();

        return LLBC_FAILED;
    }

    _threadNum = threadNum;

    _lock.Unlock();

    while (!_startCompleted)
        LLBC_ThreadManager::Sleep(20);

    return LLBC_OK;
}

bool LLBC_BaseTask::IsActivated() const
{
    LLBC_LockGuard guard(const_cast<LLBC_BaseTask *>(this)->_lock);
    return _threadNum != 0;
}

int LLBC_BaseTask::GetThreadCount() const
{
    LLBC_BaseTask *ncThis = const_cast<LLBC_BaseTask *>(this);
    LLBC_LockGuard guard(ncThis->_lock);

    return _threadNum;
}

int LLBC_BaseTask::Wait()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->WaitTask(this);
}

int LLBC_BaseTask::Suspend()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->SuspendTask(this);
}

int LLBC_BaseTask::Resume()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->ResumeTask(this);
}

int LLBC_BaseTask::Cancel()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->CancelTask(this);
}

int LLBC_BaseTask::Kill(int signo)
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->KillTask(this, signo);
}

void LLBC_BaseTask::OnTaskThreadStart()
{
    LLBC_LockGuard guard(_lock);
    if (++_curThreadNum == _threadNum)
        _startCompleted = true;
}

void LLBC_BaseTask::OnTaskThreadStop()
{
    while (!_startCompleted)
        LLBC_ThreadManager:: Sleep(20);

    _lock.Lock();
    if (--_curThreadNum == 0)
    {
        Cleanup();
        InternalCleanup();

        _lock.Unlock();

        return;
    }

    _lock.Unlock();
}

void LLBC_BaseTask::InternalCleanup()
{
    if (_threadNum == 0)
        return;

    _threadNum = 0;
    _curThreadNum = 0;
    _startCompleted = false;

    LLBC_XFree(_taskThreads);

    _msgQueue.Cleanup();
}

void LLBC_BaseTask::GetTaskThreads(std::vector<LLBC_Handle> &taskThreads)
{
    if (!IsActivated())
        return;

    while (!_startCompleted)
        LLBC_ThreadManager::Sleep(10);

    LLBC_LockGuard guard(_lock);
    for (int i = 0; i != _threadNum; ++i)
        taskThreads.push_back(_taskThreads[i]);
}

__LLBC_NS_END
<commit_msg>Task内部等待时间统一调整为1ms<commit_after>// The MIT License (MIT)

// Copyright (c) 2013 lailongwei<lailongwei@126.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "llbc/common/Export.h"

#include "llbc/core/os/OS_Atomic.h"

#include "llbc/core/thread/MessageBlock.h"
#include "llbc/core/thread/ThreadManager.h"
#include "llbc/core/thread/Guard.h"
#include "llbc/core/thread/Task.h"

__LLBC_INTERNAL_NS_BEGIN

int static __LLBC_BaseTaskEntry(void *arg)
{
    LLBC_NS LLBC_BaseTask *task = reinterpret_cast<LLBC_NS LLBC_BaseTask *>(arg);

    LLBC_NS __LLBC_LibTls *tls = LLBC_NS __LLBC_GetLibTls();

    tls->coreTls.task = task;

    task->OnTaskThreadStart();
    task->Svc();
    task->OnTaskThreadStop();

    tls->coreTls.task = nullptr;

    return 0;
}

__LLBC_INTERNAL_NS_END

__LLBC_NS_BEGIN

LLBC_BaseTask::LLBC_BaseTask(LLBC_ThreadManager *threadMgr)
: _threadNum(0)
, _curThreadNum(0)
, _startCompleted(false)
, _threadManager(threadMgr ? threadMgr : LLBC_ThreadManagerSingleton)
, _taskThreads(nullptr)
{
}

LLBC_BaseTask::~LLBC_BaseTask()
{
    Wait();
    LLBC_XFree(_taskThreads);
}

int LLBC_BaseTask::Activate(int threadNum,
                            int flags,
                            int priority,
                            LLBC_Handle groupHandle,
                            const int stackSize[])
{
    _lock.Lock();

    LLBC_XFree(_taskThreads);
    _taskThreads = LLBC_Calloc(LLBC_Handle, threadNum * sizeof(LLBC_Handle));
    if (_threadManager->CreateThreads(threadNum,
                                      &LLBC_INTERNAL_NS __LLBC_BaseTaskEntry,
                                      this,
                                      flags,
                                      priority,
                                      stackSize,
                                      this,
                                      groupHandle,
                                      nullptr,
                                      _taskThreads) == LLBC_INVALID_HANDLE)
    {
        LLBC_XFree(_taskThreads);
        _lock.Unlock();

        return LLBC_FAILED;
    }

    _threadNum = threadNum;

    _lock.Unlock();

    while (!_startCompleted)
        LLBC_ThreadManager::Sleep(1);

    return LLBC_OK;
}

bool LLBC_BaseTask::IsActivated() const
{
    LLBC_LockGuard guard(const_cast<LLBC_BaseTask *>(this)->_lock);
    return _threadNum != 0;
}

int LLBC_BaseTask::GetThreadCount() const
{
    LLBC_BaseTask *ncThis = const_cast<LLBC_BaseTask *>(this);
    LLBC_LockGuard guard(ncThis->_lock);

    return _threadNum;
}

int LLBC_BaseTask::Wait()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->WaitTask(this);
}

int LLBC_BaseTask::Suspend()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->SuspendTask(this);
}

int LLBC_BaseTask::Resume()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->ResumeTask(this);
}

int LLBC_BaseTask::Cancel()
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->CancelTask(this);
}

int LLBC_BaseTask::Kill(int signo)
{
    if (!IsActivated())
    {
        LLBC_SetLastError(LLBC_ERROR_NOT_INIT);
        return LLBC_FAILED;
    }

    return _threadManager->KillTask(this, signo);
}

void LLBC_BaseTask::OnTaskThreadStart()
{
    LLBC_LockGuard guard(_lock);
    if (++_curThreadNum == _threadNum)
        _startCompleted = true;
}

void LLBC_BaseTask::OnTaskThreadStop()
{
    while (!_startCompleted)
        LLBC_ThreadManager::Sleep(1);

    _lock.Lock();
    if (--_curThreadNum == 0)
    {
        Cleanup();
        InternalCleanup();

        _lock.Unlock();

        return;
    }

    _lock.Unlock();
}

void LLBC_BaseTask::InternalCleanup()
{
    if (_threadNum == 0)
        return;

    _threadNum = 0;
    _curThreadNum = 0;
    _startCompleted = false;

    LLBC_XFree(_taskThreads);

    _msgQueue.Cleanup();
}

void LLBC_BaseTask::GetTaskThreads(std::vector<LLBC_Handle> &taskThreads)
{
    if (!IsActivated())
        return;

    while (!_startCompleted)
        LLBC_ThreadManager::Sleep(1);

    LLBC_LockGuard guard(_lock);
    for (int i = 0; i != _threadNum; ++i)
        taskThreads.push_back(_taskThreads[i]);
}

__LLBC_NS_END
<|endoftext|>


<commit_before>#include "dataserver.hpp"

#include <QSslConfiguration>

DataServer::DataServer(QObject *parent) : QObject(parent)
{
    //
}

DataServer::~DataServer()
{
    //
}

/**
 * init - called from starting the APP
 */
void DataServer::init(DataManager *dataManager)
{
    mDataManager = dataManager;

    // workaround bug iOS - cannot reuse QNetworkAccessManager QTBUG-49751
    // otherwise accessibility not detected if switch off and on again
    // mNetworkAccessManager = new QNetworkAccessManager(this);

    // ONLINE, OFFLINE, HUNGRY
    // get this from settings:
    mUseOnlineStableTimer = true;
    mOnlineStateCollectorInterval = 500;
    mOnlineStableTimerInterval = 2*60*1000; // 2 minutes

    bool connectResult = false;

    // ATTENTION problem on iOS to get correct isOnline from QNetworkConfigurationManager:
    // https://bugreports.qt.io/browse/QTBUG-56151
    // https://bugreports.qt.io/browse/QTBUG-58946
    // so even in airplane mode  isOnline reports true
    // so we' added're using iOS Reachability classes instead
#if defined (Q_OS_IOS)
    mCurrentIsOnline = status() != utility::NotReachable;
    qDebug() << "I O S  REACHABILITY: INIT IS   O N L I N E ?" << mCurrentIsOnline;
#else
    mNetworkConfigManager = new QNetworkConfigurationManager(this);
    mCurrentIsOnline = mNetworkConfigManager->isOnline();
    qDebug() << "INIT IS   O N L I N E ?" << mCurrentIsOnline;
    connectResult = connect(mNetworkConfigManager, SIGNAL(onlineStateChanged(bool)), this, SLOT(onOnlineStateChanged(bool)));
    Q_ASSERT(connectResult);
#endif

    // to avoid too short on-off-cycles
    // coming back from suspended all collected signals
    // fired by QNetworkConfigurationManager
    // this timer waits short time before emitting signal onlineChanged
    mOnlineStateCollector = new QTimer(this);
    mOnlineStateCollector->setSingleShot(true);
    mOnlineStateCollector->setInterval(mOnlineStateCollectorInterval);

    mIsHungry = false;
    if(mUseOnlineStableTimer) {
        mOnlineStableTimer = new QTimer(this);
        mOnlineStableTimer->setSingleShot(true);
        // 2 minutes
        mOnlineStableTimer->setInterval(mOnlineStableTimerInterval);
        if(mCurrentIsOnline) {
            mOnlineStableTimer->start();
        }
    }

    connectResult = connect(mOnlineStateCollector, SIGNAL(timeout()), this, SLOT(onOnlineStateCollected()));
    Q_ASSERT(connectResult);

    if(mUseOnlineStableTimer) {
        connectResult = connect(mOnlineStableTimer, SIGNAL(timeout()), this, SLOT(onOnlineStableConnection()));
        Q_ASSERT(connectResult);
    }

    Q_UNUSED(connectResult)

    qDebug() << "Data Server INIT done";
}

// get the current state
bool DataServer::isOnline()
{
    return mCurrentIsOnline;
}

bool DataServer::serverIsHungry()
{
    return mIsHungry;
}

// Network Info INVOKABLE used in TitleBar onlineButton
// see https://bugreports.qt.io/browse/QTBUG-56151
QString DataServer::networkInfo()
{
    QString networkInfo;
    networkInfo.append("Online: ");
    if(mCurrentIsOnline) {
        networkInfo.append(tr("YES\n"));
    } else {
        networkInfo.append(tr("NO\n"));
    }
#if defined (Q_OS_IOS)
    // active network configurations are confusing
    // under iOS "utun0" and "en2" are reported active even in airplane mode
    // so we don't use QNetworkConfigurationManager for iOS
    switch (status()) {
    case utility::NotReachable:
        networkInfo.append(tr("Internet not reachable"));
        break;
    case utility::ReachableViaWiFi:
        networkInfo.append(tr("WiFi internet connection"));
        break;
    case utility::ReachableViaWWAN:
        networkInfo.append(tr("mobile data internet connection"));
        break;
//  could be removed because all possible values are covered
//  default:
//      break;
    }
#else
    QString activeNetworkConfigNames;
    QList<QNetworkConfiguration> activeConfigs = mNetworkConfigManager->allConfigurations(QNetworkConfiguration::Active);
    for (int i = 0; i < activeConfigs.size(); ++i) {
        QNetworkConfiguration config = activeConfigs.at(i);
        if(!activeNetworkConfigNames.isEmpty()) {
            activeNetworkConfigNames.append(" | ");
        }
        if(config.bearerTypeName() == "Unknown") {
            activeNetworkConfigNames.append("?? ");
        } else {
            activeNetworkConfigNames.append(config.bearerTypeName());
        }
        activeNetworkConfigNames.append(":").append(config.name());
    } // all active configurations
    networkInfo.append("Active: ");
    networkInfo.append(activeNetworkConfigNames).append("\n");
    networkInfo.append("Default: ").append(mNetworkConfigManager->defaultConfiguration().name());

    if(activeNetworkConfigNames.isEmpty()) {
        networkInfo.append("\n").append(tr("no network connection - WIFI On ?"));
    }
#endif
    // ad more infos from configurations
    // or add infos about running requests, last action done, ...
    return networkInfo;
}

// SLOT
// for some ms no new SIGNAL collected
// now we can inform UI if different from last state
// if stableTimer is used, also watch if offline / online
void DataServer::onOnlineStateCollected() {
    if(mCurrentIsOnline != mNewestIsOnline) {
        mCurrentIsOnline = mNewestIsOnline;
        qDebug() << "NEW ONLINE STATE: " << mCurrentIsOnline;
        emit onlineChanged(mCurrentIsOnline);
        if(mUseOnlineStableTimer) {
            if(!mCurrentIsOnline) {
                // stop mOnlineStableTimer if offline
                mOnlineStableTimer->stop();
                mIsHungry = false;
            } else {
                // if online start mOnlineStableTimer if not already running
                if(!mOnlineStableTimer->isActive()) {
                    mOnlineStableTimer->start();
                }
            }
        }
    }
}

// SLOT
// waits 2 minutes stable online connection
// before emitting SIGNAL that server is now hungry
// to do heavy work (downloads, uploads)
void DataServer::onOnlineStableConnection() {
    qDebug() << "SERVER H U N G R Y";
    mIsHungry = true;
    emit serverIsHungryForHeavyWork();
    // do something - per ex process server queue
}

// Signal coming from QNetworkConfigurationManager
void DataServer::onOnlineStateChanged(bool isOnline)
{
    mNewestIsOnline = isOnline;
    // always restart Collector (Timer)
    mOnlineStateCollector->start();
    if(isOnline) {
        qDebug() << "collect: O N";
    } else {
        qDebug() << "collect: O F F";
    }
}

#if defined (Q_OS_IOS)
void DataServer::statusChanged(utility::NetworkStatus newStatus)
{
    if (newStatus == utility::NotReachable) {
        qDebug("I O S   REACHABILITY: OFFLINE");
        onOnlineStateChanged(false);
    } else {
        onOnlineStateChanged(true);
        qDebug("I O S   REACHABILITY: ONLINE");
    }
}
#endif

// ONLINE end

void DataServer::setConferenceDataPath(const QString &conferenceDataPath)
{
    mConferenceDataPath = conferenceDataPath;
    qDebug() << "Conference Data path: " << mConferenceDataPath;
}

void DataServer::requestSchedule(const int conferenceId)
{
    // workaround bug iOS - cannot reuse QNetworkAccessManager QTBUG-49751
    // otherwise accessibility not detected if switch off and on again
    QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
    if(networkAccessManager->networkAccessible() != QNetworkAccessManager::Accessible) {
        if(networkAccessManager->networkAccessible() == QNetworkAccessManager::NotAccessible) {
            qDebug() << "requestSchedule NO ACCESS TO NETWORK";
            emit serverFailed(tr("No Network Access"));
            return;
        }
        qDebug() << "requestSchedule NO ACCESS: The network accessibility cannot be determined.";
        emit serverFailed(tr("No Network Access"));
        return;
    }

    QString uri;
    // uri = "https://conf.qtcon.org/en/qtcon/public/schedule.json";
    // uri = "http://www.qtworldsummit.com/api/schedule/all/";
    if(conferenceId == 201901) {
        uri = "https://www.qtworldsummit.com/2019/api/schedule/all/?location=Berlin";
    } else {
        uri = "https://www.qtworldsummit.com/2019/api/schedule/all/?location=Tokyo_en";
    }

    qDebug() << "requestSchedule uri:" << uri;

    QNetworkRequest request(uri);
    QByteArray ba = QString::number(conferenceId).toUtf8();
    request.setRawHeader("CONFERENCE_ID", ba);

    // to avoid ssl errors:
    QSslConfiguration conf = request.sslConfiguration();
    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(conf);

    QNetworkReply* reply = networkAccessManager->get(request);
    bool connectResult = connect(reply, SIGNAL(finished()), this, SLOT(onFinishedSchedule()));
    Q_ASSERT(connectResult);
    Q_UNUSED(connectResult)
}

void DataServer::requestVersion()
{
    // workaround bug iOS - cannot reuse QNetworkAccessManager QTBUG-49751
    // otherwise accessibility not detected if switch off and on again
    QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
    if(networkAccessManager->networkAccessible() != QNetworkAccessManager::Accessible) {
        if(networkAccessManager->networkAccessible() == QNetworkAccessManager::NotAccessible) {
            qDebug() << "requestVersion NO ACCESS TO NETWORK";
            emit versionFailed(tr("No Network Access"));
            return;
        }
        qDebug() << "requestVersion NO ACCESS: The network accessibility cannot be determined.";
        emit versionFailed(tr("No Network Access"));
        return;
    }

    QString uri;
    // uri = "https://conf.qtcon.org/en/qtcon/public/schedule/version.json";
    // uri = "http://www.qtworldsummit.com/api/version/show/";
    uri = "https://www.qtworldsummit.com/2019/api/version/show/";
    qDebug() << "requestVersion uri:" << uri;

    QNetworkRequest request(uri);

    // to avoid ssl errors:
//    QSslConfiguration conf = request.sslConfiguration();
//    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
//    request.setSslConfiguration(conf);

    QNetworkReply* reply = networkAccessManager->get(request);
    bool connectResult = connect(reply, SIGNAL(finished()), this, SLOT(onFinishedVersion()));
    Q_ASSERT(connectResult);
    Q_UNUSED(connectResult)
}

void DataServer::requestSpeaker()
{
    // workaround bug iOS - cannot reuse QNetworkAccessManager QTBUG-49751
    // otherwise accessibility not detected if switch off and on again
    QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
    if(networkAccessManager->networkAccessible() != QNetworkAccessManager::Accessible) {
        if(networkAccessManager->networkAccessible() == QNetworkAccessManager::NotAccessible) {
            qDebug() << "requestSpeaker NO ACCESS TO NETWORK";
            emit serverFailed(tr("No Network Access"));
            return;
        }
        qDebug() << "requestSpeaker NO ACCESS: The network accessibility cannot be determined.";
        emit serverFailed(tr("No Network Access"));
        return;
    }

    QString uri;
    // uri = "https://conf.qtcon.org/en/qtcon/public/speakers.json";
    // uri = "http://www.qtworldsummit.com/api/speakers/all/";
    uri = "https://www.qtworldsummit.com/2019/api/speakers/all/";
    qDebug() << "requestSpeaker uri:" << uri;

    QNetworkRequest request(uri);

    // to avoid ssl errors:
    QSslConfiguration conf = request.sslConfiguration();
    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(conf);

    QNetworkReply* reply = networkAccessManager->get(request);
    bool connectResult = connect(reply, SIGNAL(finished()), this, SLOT(onFinishedSpeaker()));
    Q_ASSERT(connectResult);
    Q_UNUSED(connectResult)
}

// SLOTS
void DataServer::onFinishedSchedule()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    if(!reply) {
        qWarning() << "Schedule REPLY is NULL";
        emit serverFailed(tr("No Network Reply"));
        return;
    }
    const qint64 available = reply->bytesAvailable();
    if(available == 0) {
        qWarning() << "Schedule: No Bytes received";
        emit serverFailed(tr("No Schedule Data received"));
        return;
    }
    int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "schedule HTTP STATUS: " << httpStatusCode << " Bytes: " << available;
    if(httpStatusCode != 200) {
        qDebug() << "Schedule Status Code not 200";
        emit serverFailed(tr("No sucess getting Schedule from Server. Got HTTP Status ")+QString::number(httpStatusCode));
        return;
    }
    // more schedules this year ?
    QByteArray ba = reply->request().rawHeader("CONFERENCE_ID");
    QString conferenceString = QString::fromUtf8(ba);

    QString scheduleFilePath = mConferenceDataPath+"schedule_"+conferenceString+".json";
    QFile saveFile(scheduleFilePath);
    if (!saveFile.open(QIODevice::WriteOnly)) {
        qWarning() << "Couldn't open file to write " << scheduleFilePath;
        emit serverFailed(tr("Schedule Data cannot be written"));
        return;
    }
    qint64 bytesWritten = saveFile.write(reply->readAll());
    saveFile.close();
    qDebug() << "Schedule Data Bytes written: " << bytesWritten << " to: " << scheduleFilePath;

    // more schedules this year ?
    int conferenceId = conferenceString.toInt();
    if(conferenceId == 201901) {
        requestSchedule(201902);
        return;
    }

    // now getting the speaker data
    requestSpeaker();
}

void DataServer::onFinishedSpeaker()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    if(!reply) {
        qWarning() << "Speaker REPLY is NULL";
        emit serverFailed(tr("No Network Reply"));
        return;
    }
    const qint64 available = reply->bytesAvailable();
    if(available == 0) {
        qWarning() << "Speaker No Bytes received";
        emit serverFailed(tr("No Speaker Data received"));
        return;
    }
    int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "Speaker HTTP STATUS: " << httpStatusCode << " Bytes: " << available;
    if(httpStatusCode != 200) {
        qDebug() << "Speaker Status Code not 200";
        emit serverFailed(tr("No sucess getting Speaker from Server. Got HTTP Status ")+QString::number(httpStatusCode));
        return;
    }
    QString speakerFilePath = mConferenceDataPath+"speaker.json";
    QFile saveFile(speakerFilePath);
    if (!saveFile.open(QIODevice::WriteOnly)) {
        qWarning() << "Couldn't open file to write " << speakerFilePath;
        emit serverFailed(tr("Speaker Data cannot be written"));
        return;
    }
    qint64 bytesWritten = saveFile.write(reply->readAll());
    saveFile.close();
    qDebug() << "Data Bytes written: " << bytesWritten << " to: " << speakerFilePath;

    emit serverSuccess();
}

void DataServer::onFinishedVersion()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    if(!reply) {
        qWarning() << "Version REPLY is NULL";
        emit versionFailed(tr("No Network Reply"));
        return;
    }
    const qint64 available = reply->bytesAvailable();
    if(available == 0) {
        qWarning() << "Version No Bytes received";
        emit versionFailed(tr("No Version Data received"));
        return;
    }
    int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "Version HTTP STATUS: " << httpStatusCode << " Bytes: " << available;
    if(httpStatusCode != 200) {
        qDebug() << "Version Status Code not 200";
        emit versionFailed(tr("No sucess getting Version from Server. Got HTTP Status ")+QString::number(httpStatusCode));
        return;
    }
    emit versionSuccess(reply->readAll());
}

<commit_msg>removed workaround QNAM bug<commit_after>#include "dataserver.hpp"

#include <QSslConfiguration>

DataServer::DataServer(QObject *parent) : QObject(parent)
{
    //
}

DataServer::~DataServer()
{
    //
}

/**
 * init - called from starting the APP
 */
void DataServer::init(DataManager *dataManager)
{
    mDataManager = dataManager;

    mNetworkAccessManager = new QNetworkAccessManager(this);

    // ONLINE, OFFLINE, HUNGRY
    // get this from settings:
    mUseOnlineStableTimer = true;
    mOnlineStateCollectorInterval = 500;
    mOnlineStableTimerInterval = 2*60*1000; // 2 minutes

    bool connectResult = false;

    // ATTENTION problem on iOS to get correct isOnline from QNetworkConfigurationManager:
    // https://bugreports.qt.io/browse/QTBUG-56151
    // https://bugreports.qt.io/browse/QTBUG-58946
    // so even in airplane mode  isOnline reports true
    // so we' added're using iOS Reachability classes instead
#if defined (Q_OS_IOS)
    mCurrentIsOnline = status() != utility::NotReachable;
    qDebug() << "I O S  REACHABILITY: INIT IS   O N L I N E ?" << mCurrentIsOnline;
#else
    mNetworkConfigManager = new QNetworkConfigurationManager(this);
    mCurrentIsOnline = mNetworkConfigManager->isOnline();
    qDebug() << "INIT IS   O N L I N E ?" << mCurrentIsOnline;
    connectResult = connect(mNetworkConfigManager, SIGNAL(onlineStateChanged(bool)), this, SLOT(onOnlineStateChanged(bool)));
    Q_ASSERT(connectResult);
#endif

    // to avoid too short on-off-cycles
    // coming back from suspended all collected signals
    // fired by QNetworkConfigurationManager
    // this timer waits short time before emitting signal onlineChanged
    mOnlineStateCollector = new QTimer(this);
    mOnlineStateCollector->setSingleShot(true);
    mOnlineStateCollector->setInterval(mOnlineStateCollectorInterval);

    mIsHungry = false;
    if(mUseOnlineStableTimer) {
        mOnlineStableTimer = new QTimer(this);
        mOnlineStableTimer->setSingleShot(true);
        // 2 minutes
        mOnlineStableTimer->setInterval(mOnlineStableTimerInterval);
        if(mCurrentIsOnline) {
            mOnlineStableTimer->start();
        }
    }

    connectResult = connect(mOnlineStateCollector, SIGNAL(timeout()), this, SLOT(onOnlineStateCollected()));
    Q_ASSERT(connectResult);

    if(mUseOnlineStableTimer) {
        connectResult = connect(mOnlineStableTimer, SIGNAL(timeout()), this, SLOT(onOnlineStableConnection()));
        Q_ASSERT(connectResult);
    }

    Q_UNUSED(connectResult)

    qDebug() << "Data Server INIT done";
}

// get the current state
bool DataServer::isOnline()
{
    return mCurrentIsOnline;
}

bool DataServer::serverIsHungry()
{
    return mIsHungry;
}

// Network Info INVOKABLE used in TitleBar onlineButton
// see https://bugreports.qt.io/browse/QTBUG-56151
QString DataServer::networkInfo()
{
    QString networkInfo;
    networkInfo.append("Online: ");
    if(mCurrentIsOnline) {
        networkInfo.append(tr("YES\n"));
    } else {
        networkInfo.append(tr("NO\n"));
    }
#if defined (Q_OS_IOS)
    // active network configurations are confusing
    // under iOS "utun0" and "en2" are reported active even in airplane mode
    // so we don't use QNetworkConfigurationManager for iOS
    switch (status()) {
    case utility::NotReachable:
        networkInfo.append(tr("Internet not reachable"));
        break;
    case utility::ReachableViaWiFi:
        networkInfo.append(tr("WiFi internet connection"));
        break;
    case utility::ReachableViaWWAN:
        networkInfo.append(tr("mobile data internet connection"));
        break;
//  could be removed because all possible values are covered
//  default:
//      break;
    }
#else
    QString activeNetworkConfigNames;
    QList<QNetworkConfiguration> activeConfigs = mNetworkConfigManager->allConfigurations(QNetworkConfiguration::Active);
    for (int i = 0; i < activeConfigs.size(); ++i) {
        QNetworkConfiguration config = activeConfigs.at(i);
        if(!activeNetworkConfigNames.isEmpty()) {
            activeNetworkConfigNames.append(" | ");
        }
        if(config.bearerTypeName() == "Unknown") {
            activeNetworkConfigNames.append("?? ");
        } else {
            activeNetworkConfigNames.append(config.bearerTypeName());
        }
        activeNetworkConfigNames.append(":").append(config.name());
    } // all active configurations
    networkInfo.append("Active: ");
    networkInfo.append(activeNetworkConfigNames).append("\n");
    networkInfo.append("Default: ").append(mNetworkConfigManager->defaultConfiguration().name());

    if(activeNetworkConfigNames.isEmpty()) {
        networkInfo.append("\n").append(tr("no network connection - WIFI On ?"));
    }
#endif
    // ad more infos from configurations
    // or add infos about running requests, last action done, ...
    return networkInfo;
}

// SLOT
// for some ms no new SIGNAL collected
// now we can inform UI if different from last state
// if stableTimer is used, also watch if offline / online
void DataServer::onOnlineStateCollected() {
    if(mCurrentIsOnline != mNewestIsOnline) {
        mCurrentIsOnline = mNewestIsOnline;
        qDebug() << "NEW ONLINE STATE: " << mCurrentIsOnline;
        emit onlineChanged(mCurrentIsOnline);
        if(mUseOnlineStableTimer) {
            if(!mCurrentIsOnline) {
                // stop mOnlineStableTimer if offline
                mOnlineStableTimer->stop();
                mIsHungry = false;
            } else {
                // if online start mOnlineStableTimer if not already running
                if(!mOnlineStableTimer->isActive()) {
                    mOnlineStableTimer->start();
                }
            }
        }
    }
}

// SLOT
// waits 2 minutes stable online connection
// before emitting SIGNAL that server is now hungry
// to do heavy work (downloads, uploads)
void DataServer::onOnlineStableConnection() {
    qDebug() << "SERVER H U N G R Y";
    mIsHungry = true;
    emit serverIsHungryForHeavyWork();
    // do something - per ex process server queue
}

// Signal coming from QNetworkConfigurationManager
void DataServer::onOnlineStateChanged(bool isOnline)
{
    mNewestIsOnline = isOnline;
    // always restart Collector (Timer)
    mOnlineStateCollector->start();
    if(isOnline) {
        qDebug() << "collect: O N";
    } else {
        qDebug() << "collect: O F F";
    }
}

#if defined (Q_OS_IOS)
void DataServer::statusChanged(utility::NetworkStatus newStatus)
{
    if (newStatus == utility::NotReachable) {
        qDebug("I O S   REACHABILITY: OFFLINE");
        onOnlineStateChanged(false);
    } else {
        onOnlineStateChanged(true);
        qDebug("I O S   REACHABILITY: ONLINE");
    }
}
#endif

// ONLINE end

void DataServer::setConferenceDataPath(const QString &conferenceDataPath)
{
    mConferenceDataPath = conferenceDataPath;
    qDebug() << "Conference Data path: " << mConferenceDataPath;
}

void DataServer::requestSchedule(const int conferenceId)
{
    if(mNetworkAccessManager->networkAccessible() != QNetworkAccessManager::Accessible) {
        if(mNetworkAccessManager->networkAccessible() == QNetworkAccessManager::NotAccessible) {
            qDebug() << "requestSchedule NO ACCESS TO NETWORK";
            emit serverFailed(tr("No Network Access"));
            return;
        }
        qDebug() << "requestSchedule NO ACCESS: The network accessibility cannot be determined.";
        emit serverFailed(tr("No Network Access"));
        return;
    }

    QString uri;
    // uri = "https://conf.qtcon.org/en/qtcon/public/schedule.json";
    // uri = "http://www.qtworldsummit.com/api/schedule/all/";
    if(conferenceId == 201901) {
        uri = "https://www.qtworldsummit.com/2019/api/schedule/all/?location=Berlin";
    } else {
        uri = "https://www.qtworldsummit.com/2019/api/schedule/all/?location=Tokyo_en";
    }

    qDebug() << "requestSchedule uri:" << uri;

    QNetworkRequest request(uri);
    QByteArray ba = QString::number(conferenceId).toUtf8();
    request.setRawHeader("CONFERENCE_ID", ba);

    // to avoid ssl errors:
    QSslConfiguration conf = request.sslConfiguration();
    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(conf);

    QNetworkReply* reply = mNetworkAccessManager->get(request);
    bool connectResult = connect(reply, SIGNAL(finished()), this, SLOT(onFinishedSchedule()));
    Q_ASSERT(connectResult);
    Q_UNUSED(connectResult)
}

void DataServer::requestVersion()
{
    if(mNetworkAccessManager->networkAccessible() != QNetworkAccessManager::Accessible) {
        if(mNetworkAccessManager->networkAccessible() == QNetworkAccessManager::NotAccessible) {
            qDebug() << "requestVersion NO ACCESS TO NETWORK";
            emit versionFailed(tr("No Network Access"));
            return;
        }
        qDebug() << "requestVersion NO ACCESS: The network accessibility cannot be determined.";
        emit versionFailed(tr("No Network Access"));
        return;
    }

    QString uri;
    // uri = "https://conf.qtcon.org/en/qtcon/public/schedule/version.json";
    // uri = "http://www.qtworldsummit.com/api/version/show/";
    uri = "https://www.qtworldsummit.com/2019/api/version/show/";
    qDebug() << "requestVersion uri:" << uri;

    QNetworkRequest request(uri);

    // to avoid ssl errors:
//    QSslConfiguration conf = request.sslConfiguration();
//    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
//    request.setSslConfiguration(conf);

    QNetworkReply* reply = mNetworkAccessManager->get(request);
    bool connectResult = connect(reply, SIGNAL(finished()), this, SLOT(onFinishedVersion()));
    Q_ASSERT(connectResult);
    Q_UNUSED(connectResult)
}

void DataServer::requestSpeaker()
{
    if(mNetworkAccessManager->networkAccessible() != QNetworkAccessManager::Accessible) {
        if(mNetworkAccessManager->networkAccessible() == QNetworkAccessManager::NotAccessible) {
            qDebug() << "requestSpeaker NO ACCESS TO NETWORK";
            emit serverFailed(tr("No Network Access"));
            return;
        }
        qDebug() << "requestSpeaker NO ACCESS: The network accessibility cannot be determined.";
        emit serverFailed(tr("No Network Access"));
        return;
    }

    QString uri;
    // uri = "https://conf.qtcon.org/en/qtcon/public/speakers.json";
    // uri = "http://www.qtworldsummit.com/api/speakers/all/";
    uri = "https://www.qtworldsummit.com/2019/api/speakers/all/";
    qDebug() << "requestSpeaker uri:" << uri;

    QNetworkRequest request(uri);

    // to avoid ssl errors:
    QSslConfiguration conf = request.sslConfiguration();
    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(conf);

    QNetworkReply* reply = mNetworkAccessManager->get(request);
    bool connectResult = connect(reply, SIGNAL(finished()), this, SLOT(onFinishedSpeaker()));
    Q_ASSERT(connectResult);
    Q_UNUSED(connectResult)
}

// SLOTS
void DataServer::onFinishedSchedule()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    if(!reply) {
        qWarning() << "Schedule REPLY is NULL";
        emit serverFailed(tr("No Network Reply"));
        return;
    }
    const qint64 available = reply->bytesAvailable();
    if(available == 0) {
        qWarning() << "Schedule: No Bytes received";
        emit serverFailed(tr("No Schedule Data received"));
        reply->deleteLater();
        return;
    }
    int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "schedule HTTP STATUS: " << httpStatusCode << " Bytes: " << available;
    if(httpStatusCode != 200) {
        qDebug() << "Schedule Status Code not 200";
        emit serverFailed(tr("No sucess getting Schedule from Server. Got HTTP Status ")+QString::number(httpStatusCode));
        reply->deleteLater();
        return;
    }
    // more schedules this year ?
    QByteArray ba = reply->request().rawHeader("CONFERENCE_ID");
    QString conferenceString = QString::fromUtf8(ba);

    QString scheduleFilePath = mConferenceDataPath+"schedule_"+conferenceString+".json";
    QFile saveFile(scheduleFilePath);
    if (!saveFile.open(QIODevice::WriteOnly)) {
        qWarning() << "Couldn't open file to write " << scheduleFilePath;
        emit serverFailed(tr("Schedule Data cannot be written"));
        reply->deleteLater();
        return;
    }
    qint64 bytesWritten = saveFile.write(reply->readAll());
    saveFile.close();
    qDebug() << "Schedule Data Bytes written: " << bytesWritten << " to: " << scheduleFilePath;

    // more schedules this year ?
    int conferenceId = conferenceString.toInt();
    if(conferenceId == 201901) {
        requestSchedule(201902);
        reply->deleteLater();
        return;
    }

    // now getting the speaker data
    requestSpeaker();
    reply->deleteLater();
}

void DataServer::onFinishedSpeaker()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    if(!reply) {
        qWarning() << "Speaker REPLY is NULL";
        emit serverFailed(tr("No Network Reply"));
        return;
    }
    const qint64 available = reply->bytesAvailable();
    if(available == 0) {
        qWarning() << "Speaker No Bytes received";
        emit serverFailed(tr("No Speaker Data received"));
        reply->deleteLater();
        return;
    }
    int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "Speaker HTTP STATUS: " << httpStatusCode << " Bytes: " << available;
    if(httpStatusCode != 200) {
        qDebug() << "Speaker Status Code not 200";
        emit serverFailed(tr("No sucess getting Speaker from Server. Got HTTP Status ")+QString::number(httpStatusCode));
        reply->deleteLater();
        return;
    }
    QString speakerFilePath = mConferenceDataPath+"speaker.json";
    QFile saveFile(speakerFilePath);
    if (!saveFile.open(QIODevice::WriteOnly)) {
        qWarning() << "Couldn't open file to write " << speakerFilePath;
        emit serverFailed(tr("Speaker Data cannot be written"));
        reply->deleteLater();
        return;
    }
    qint64 bytesWritten = saveFile.write(reply->readAll());
    saveFile.close();
    qDebug() << "Data Bytes written: " << bytesWritten << " to: " << speakerFilePath;

    emit serverSuccess();
    reply->deleteLater();
}

void DataServer::onFinishedVersion()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    if(!reply) {
        qWarning() << "Version REPLY is NULL";
        emit versionFailed(tr("No Network Reply"));
        return;
    }
    const qint64 available = reply->bytesAvailable();
    if(available == 0) {
        qWarning() << "Version No Bytes received";
        emit versionFailed(tr("No Version Data received"));
        reply->deleteLater();
        return;
    }
    int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "Version HTTP STATUS: " << httpStatusCode << " Bytes: " << available;
    if(httpStatusCode != 200) {
        qDebug() << "Version Status Code not 200";
        emit versionFailed(tr("No sucess getting Version from Server. Got HTTP Status ")+QString::number(httpStatusCode));
        reply->deleteLater();
        return;
    }
    emit versionSuccess(reply->readAll());
    reply->deleteLater();
}

<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  imgui-wgpu.c
//
//  Test ImGui rendering, no input handling!
//------------------------------------------------------------------------------
#define SOKOL_IMPL
#define SOKOL_WGPU
#include "sokol_gfx.h"
#include "sokol_time.h"
#include "imgui.h"
#define SOKOL_IMGUI_IMPL
#define SOKOL_IMGUI_NO_SOKOL_APP
#include "sokol_imgui.h"
#include "wgpu_entry.h"

static struct {
    sg_pass_action pass_action;
    uint64_t last_time = 0;
    bool show_test_window = true;
    bool show_another_window = false;
} state;

static void init(void) {
    // setup sokol-gfx, sokol-time and sokol-imgui
    sg_desc desc = { };
    desc.wgpu_device = wgpu_device(),
    desc.wgpu_swapchain_format = wgpu_swapchain_format(),
    desc.wgpu_swapchain_render_view_cb = wgpu_swapchain_render_view,
    desc.wgpu_swapchain_resolve_view_cb = wgpu_swapchain_resolve_view,
    desc.wgpu_swapchain_depth_stencil_view_cb = wgpu_swapchain_depth_stencil_view,
    sg_setup(&desc);
    stm_setup();

    // use sokol-imgui with all default-options (we're not doing
    // multi-sampled rendering or using non-default pixel formats)
    simgui_desc_t simgui_desc = { };
    simgui_setup(&simgui_desc);

    // initial clear color
    state.pass_action.colors[0].action = SG_ACTION_CLEAR;
    state.pass_action.colors[0].val[0] = 0.0f;
    state.pass_action.colors[0].val[1] = 0.5f;
    state.pass_action.colors[0].val[2] = 0.7f;
    state.pass_action.colors[0].val[3] = 1.0f;
}

static void frame(void) {
    const int width = wgpu_width();
    const int height = wgpu_height();
    const double delta_time = stm_sec(stm_laptime(&state.last_time));
    simgui_new_frame(width, height, delta_time);

    // 1. Show a simple window
    // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
    static float f = 0.0f;
    ImGui::Text("Hello, world!");
    ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
    ImGui::ColorEdit3("clear color", &state.pass_action.colors[0].val[0]);
    if (ImGui::Button("Test Window")) state.show_test_window ^= 1;
    if (ImGui::Button("Another Window")) state.show_another_window ^= 1;
    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);

    // 2. Show another simple window, this time using an explicit Begin/End pair
    if (state.show_another_window) {
        ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiCond_FirstUseEver);
        ImGui::Begin("Another Window", &state.show_another_window);
        ImGui::Text("Hello");
        ImGui::End();
    }

    // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
    if (state.show_test_window) {
        ImGui::SetNextWindowPos(ImVec2(460, 20), ImGuiCond_FirstUseEver);
        ImGui::ShowTestWindow();
    }

    // the sokol_gfx draw pass
    sg_begin_default_pass(&state.pass_action, width, height);
    simgui_render();
    sg_end_pass();
    sg_commit();
}

static void shutdown(void) {
    simgui_shutdown();
    sg_shutdown();
}

int main() {
    wgpu_desc_t desc = { };
    desc.init_cb = init;
    desc.frame_cb = frame;
    desc.shutdown_cb = shutdown;
    desc.width = 1024;
    desc.height = 768;
    desc.title = "imgui-wgpu";
    wgpu_start(&desc);
    return 0;
}
<commit_msg>imgui-wgpu sample tweaks<commit_after>//------------------------------------------------------------------------------
//  imgui-wgpu.c
//
//  Test ImGui rendering, no input handling!
//------------------------------------------------------------------------------
#define SOKOL_IMPL
#define SOKOL_WGPU
#include "sokol_gfx.h"
#include "sokol_time.h"
#include "imgui.h"
#define SOKOL_IMGUI_IMPL
#define SOKOL_IMGUI_NO_SOKOL_APP
#include "sokol_imgui.h"
#include "wgpu_entry.h"

static struct {
    sg_pass_action pass_action;
    uint64_t last_time = 0;
    bool show_test_window = true;
    bool show_another_window = false;
} state;

static void init(void) {
    // setup sokol-gfx, sokol-time and sokol-imgui
    sg_desc desc = { };
    desc.wgpu_device = wgpu_device(),
    desc.wgpu_swapchain_format = wgpu_swapchain_format(),
    desc.wgpu_swapchain_render_view_cb = wgpu_swapchain_render_view,
    desc.wgpu_swapchain_resolve_view_cb = wgpu_swapchain_resolve_view,
    desc.wgpu_swapchain_depth_stencil_view_cb = wgpu_swapchain_depth_stencil_view,
    sg_setup(&desc);
    stm_setup();

    // use sokol-imgui with all default-options (we're not doing
    // multi-sampled rendering or using non-default pixel formats)
    simgui_desc_t simgui_desc = { };
    simgui_setup(&simgui_desc);

    // initial clear color
    state.pass_action.colors[0].action = SG_ACTION_CLEAR;
    state.pass_action.colors[0].val[0] = 0.0f;
    state.pass_action.colors[0].val[1] = 0.5f;
    state.pass_action.colors[0].val[2] = 0.7f;
    state.pass_action.colors[0].val[3] = 1.0f;
}

static void frame(void) {
    const int width = wgpu_width();
    const int height = wgpu_height();
    const double delta_time = stm_sec(stm_laptime(&state.last_time));
    simgui_new_frame(width, height, delta_time);

    // 1. Show a simple window
    // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
    static float f = 0.0f;
    ImGui::Text("Hello, world!");
    ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
    ImGui::ColorEdit3("clear color", &state.pass_action.colors[0].val[0]);
    if (ImGui::Button("Test Window")) state.show_test_window ^= 1;
    if (ImGui::Button("Another Window")) state.show_another_window ^= 1;
    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);

    // 2. Show another simple window, this time using an explicit Begin/End pair
    if (state.show_another_window) {
        ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiCond_Once);
        ImGui::Begin("Another Window", &state.show_another_window);
        ImGui::Text("Hello");
        ImGui::End();
    }

    // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
    if (state.show_test_window) {
        ImGui::ShowTestWindow();
    }

    // the sokol_gfx draw pass
    sg_begin_default_pass(&state.pass_action, width, height);
    simgui_render();
    sg_end_pass();
    sg_commit();
}

static void shutdown(void) {
    simgui_shutdown();
    sg_shutdown();
}

int main() {
    wgpu_desc_t desc = { };
    desc.init_cb = init;
    desc.frame_cb = frame;
    desc.shutdown_cb = shutdown;
    desc.width = 1024;
    desc.height = 768;
    desc.title = "imgui-wgpu";
    wgpu_start(&desc);
    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

using std::cout; using std::vector;

bool is_prefix(vector<int> const& lhs, vector<int> const& rhs)
{
    if(lhs.size() > rhs.size())
        is_prefix(rhs, lhs);
    for(unsigned i = 0; i != lhs.size(); ++i)
        if(lhs[i] != rhs[i]) return false;
    return true;
}

int main()
{
    vector<int> l{ 0, 1, 1, 2 };
    vector<int> r{ 0, 1, 1, 2, 3, 5, 8 };
    cout << (is_prefix(r, l) ? "yes\n" : "no\n");

    return 0;
}

<commit_msg>update ch05 ex5.17<commit_after>#include <iostream>
#include <vector>

using std::cout; using std::vector;

bool is_prefix(vector<int> const& lhs, vector<int> const& rhs)
{
    if(lhs.size() > rhs.size())
        return is_prefix(rhs, lhs);
    for(unsigned i = 0; i != lhs.size(); ++i)
        if(lhs[i] != rhs[i]) return false;
    return true;
}

int main()
{
    vector<int> l{ 0, 1, 1, 2 };
    vector<int> r{ 0, 1, 1, 2, 3, 5, 8 };
    cout << (is_prefix(r, l) ? "yes\n" : "no\n");

    return 0;
}

<|endoftext|>


<commit_before>//! @Alan
//!
//! Exercise 6.21:
//! Write a function that takes an int and a pointer to an int and
//! returns the larger of the int value or the value to which the
//! pointer points. What type should you use for the pointer?
//!

#include <iostream>
using std::cout;

int LargerOne(const int i, const int* ip)
{
    return (i > *ip) ? i : *ip;
}

int main()
{
    int c = 6;
    cout << LargerOne(7, &c);

    return 0;
}
<commit_msg>Update ex6_21.cpp<commit_after>//! @Alan
//!
//! Exercise 6.21:
//! Write a function that takes an int and a pointer to an int and
//! returns the larger of the int value or the value to which the
//! pointer points. What type should you use for the pointer?
//!

#include <iostream>
using std::cout;

int largerOne(const int i, const int* ip)
{
    return ((i > *ip) ? i : *ip);
}

int main()
{
    int c = 6;
    cout << largerOne(7, &c);

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "tcpserverbalancer.h"

#include "wsgi.h"
#include "cwsgiengine.h"
#include "tcpserver.h"
#include "tcpsslserver.h"

#include <QFile>
#include <QLoggingCategory>

#include <QSslKey>

#include <iostream>

#ifdef Q_OS_LINUX
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#endif

Q_LOGGING_CATEGORY(CWSGI_BALANCER, "wsgi.tcp_server_balancer")

using namespace CWSGI;

#ifdef Q_OS_LINUX
int listenReuse(const QHostAddress &address, quint16 port, bool startListening);
#endif

TcpServerBalancer::TcpServerBalancer(WSGI *wsgi) : QTcpServer(wsgi)
  , m_wsgi(wsgi)
{
}

TcpServerBalancer::~TcpServerBalancer()
{
    delete m_sslConfiguration;
}

bool TcpServerBalancer::listen(const QString &line, Protocol *protocol, bool secure)
{
    m_protocol = protocol;

    int commaPos = line.indexOf(QLatin1Char(','));
    const QString addressPortString = line.mid(0, commaPos);
    const QString addressString = addressPortString.section(QLatin1Char(':'), 0, -2);
    const QString portString = addressPortString.section(QLatin1Char(':'), -1);

    QHostAddress address;
    if (addressString.isEmpty()) {
        address = QHostAddress(QHostAddress::Any);
    } else {
        address.setAddress(addressString);
    }

    bool ok;
    quint16 port = portString.toUInt(&ok);
    if (!ok || (port < 1 && port > 35554)) {
        port = 80;
    }

    if (secure) {
        if (commaPos == -1) {
            std::cerr << "No SSL certificate specified" << std::endl;
            exit(1);
        }

        const QString sslString = line.mid(commaPos + 1);
        const QString certPath = sslString.section(QLatin1Char(','), 0, 0);
        QFile certFile(certPath);
        if (!certFile.open(QFile::ReadOnly)) {
            std::cerr << "Failed to open SSL certificate" << qPrintable(certPath)
                      << qPrintable(certFile.errorString()) << std::endl;
            exit(1);
        }
        QSslCertificate cert(&certFile);
        if (cert.isNull()) {
            std::cerr << "Failed to parse SSL certificate" << std::endl;
            exit(1);
        }

        const QString keyPath = sslString.section(QLatin1Char(','), 1, 1);
        QFile keyFile(keyPath);
        if (!keyFile.open(QFile::ReadOnly)) {
            std::cerr << "Failed to open SSL private key" << qPrintable(keyPath)
                      << qPrintable(keyFile.errorString()) << std::endl;
            exit(1);
        }
        QSslKey key(&keyFile, QSsl::Rsa);
        if (key.isNull()) {
            std::cerr << "Failed to parse SSL private key" << std::endl;
            exit(1);
        }

        m_sslConfiguration = new QSslConfiguration;
        m_sslConfiguration->setLocalCertificate(cert);
        m_sslConfiguration->setPrivateKey(key);
        if (m_wsgi->httpsH2()) {
            m_sslConfiguration->setAllowedNextProtocols({ QByteArrayLiteral("h2") });
        }
    }

    m_address = address;
    m_port = port;

    bool reusePort = false;
#ifdef Q_OS_LINUX
    reusePort = m_wsgi->reusePort();
#endif
    if (reusePort) {
#ifdef Q_OS_LINUX
        int socket = listenReuse(address, port, false);
        if (socket > 0) {
            setSocketDescriptor(socket);
            pauseAccepting();
        } else {
            std::cerr << "Failed to listen on TCP: " << qPrintable(line)
                      << " : " << qPrintable(errorString()) << std::endl;
            exit(1);
        }
#endif
    } else {
        bool ret = QTcpServer::listen(address, port);
        if (ret) {
            pauseAccepting();
        } else {
            std::cerr << "Failed to listen on TCP: " << qPrintable(line)
                      << " : " << qPrintable(errorString()) << std::endl;
            exit(1);
        }
    }

    m_serverName = serverAddress().toString() + QLatin1Char(':') + QString::number(port);
    return true;
}

#ifdef Q_OS_LINUX
// UnixWare 7 redefines socket -> _socket
static inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0)
{
    Q_ASSERT((flags & ~O_NONBLOCK) == 0);

    int fd;
#ifdef QT_THREADSAFE_CLOEXEC
    int newtype = type | SOCK_CLOEXEC;
    if (flags & O_NONBLOCK)
        newtype |= SOCK_NONBLOCK;
    fd = ::socket(domain, newtype, protocol);
    return fd;
#else
    fd = ::socket(domain, type, protocol);
    if (fd == -1)
        return -1;

    ::fcntl(fd, F_SETFD, FD_CLOEXEC);

    // set non-block too?
    if (flags & O_NONBLOCK)
        ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);

    return fd;
#endif
}

int createNewSocket(QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{
    int protocol = 0;

    int domain = (socketProtocol == QAbstractSocket::IPv6Protocol
                  || socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET;
    int type = SOCK_STREAM;

    int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
    if (socket < 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && errno == EAFNOSUPPORT) {
        domain = AF_INET;
        socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
        socketProtocol = QAbstractSocket::IPv4Protocol;
    }

    if (socket < 0) {
        int ecopy = errno;
        switch (ecopy) {
        case EPROTONOSUPPORT:
        case EAFNOSUPPORT:
        case EINVAL:
            qCDebug(CWSGI_BALANCER) << "setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString)";
            break;
        case ENFILE:
        case EMFILE:
        case ENOBUFS:
        case ENOMEM:
            qCDebug(CWSGI_BALANCER) << "setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
            break;
        case EACCES:
            qCDebug(CWSGI_BALANCER) << "setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
            break;
        default:
            break;
        }

#if defined (QNATIVESOCKETENGINE_DEBUG)
        qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
                socketType, socketProtocol,
                strerror(ecopy));
#endif

        return false;
    }

#if defined (QNATIVESOCKETENGINE_DEBUG)
    qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
            socketType, socketProtocol);
#endif

    return socket;
}

union qt_sockaddr {
    sockaddr a;
    sockaddr_in a4;
    sockaddr_in6 a6;
};

#  define QT_SOCKLEN_T int
#define QT_SOCKET_BIND          ::bind

namespace {
namespace SetSALen {
    template <typename T> void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len)
    { sa->sa_len = len; }
    template <typename T> void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len)
    { sin6->sin6_len = len; }
    template <typename T> void set(T *, ...) {}
}
}

void setPortAndAddress(quint16 port, const QHostAddress &address, QAbstractSocket::NetworkLayerProtocol socketProtocol, qt_sockaddr *aa, int *sockAddrSize)
{
    if (address.protocol() == QAbstractSocket::IPv6Protocol
        || address.protocol() == QAbstractSocket::AnyIPProtocol
        || socketProtocol == QAbstractSocket::IPv6Protocol
        || socketProtocol == QAbstractSocket::AnyIPProtocol) {
        memset(&aa->a6, 0, sizeof(sockaddr_in6));
        aa->a6.sin6_family = AF_INET6;
//#if QT_CONFIG(networkinterface)
//            aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId());
//#endif
        aa->a6.sin6_port = htons(port);
        Q_IPV6ADDR tmp = address.toIPv6Address();
        memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp));
        *sockAddrSize = sizeof(sockaddr_in6);
        SetSALen::set(&aa->a, sizeof(sockaddr_in6));
    } else {
        memset(&aa->a, 0, sizeof(sockaddr_in));
        aa->a4.sin_family = AF_INET;
        aa->a4.sin_port = htons(port);
        aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address());
        *sockAddrSize = sizeof(sockaddr_in);
        SetSALen::set(&aa->a, sizeof(sockaddr_in));
    }
}

bool nativeBind(int socketDescriptor, const QHostAddress &address, quint16 port)
{
    qt_sockaddr aa;
    int sockAddrSize;
    setPortAndAddress(port, address, address.protocol(), &aa, &sockAddrSize);

#ifdef IPV6_V6ONLY
    if (aa.a.sa_family == AF_INET6) {
        int ipv6only = 0;
        if (address.protocol() == QAbstractSocket::IPv6Protocol)
            ipv6only = 1;
        //default value of this socket option varies depending on unix variant (or system configuration on BSD), so always set it explicitly
        ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
    }
#endif

    int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
    if (bindResult < 0 && errno == EAFNOSUPPORT && address.protocol() == QAbstractSocket::AnyIPProtocol) {
        // retry with v4
        aa.a4.sin_family = AF_INET;
        aa.a4.sin_port = htons(port);
        aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address());
        sockAddrSize = sizeof(aa.a4);
        bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
    }

    if (bindResult < 0) {
#if defined (QNATIVESOCKETENGINE_DEBUG)
        int ecopy = errno;
#endif
//        switch(errno) {
//        case EADDRINUSE:
//            setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
//            break;
//        case EACCES:
//            setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
//            break;
//        case EINVAL:
//            setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
//            break;
//        case EADDRNOTAVAIL:
//            setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString);
//            break;
//        default:
//            break;
//        }

#if defined (QNATIVESOCKETENGINE_DEBUG)
        qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
                address.toString().toLatin1().constData(), port, strerror(ecopy));
#endif

        return false;
    }

#if defined (QNATIVESOCKETENGINE_DEBUG)
    qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
            address.toString().toLatin1().constData(), port);
#endif
//    socketState = QAbstractSocket::BoundState;
    return true;
}

int listenReuse(const QHostAddress &address, quint16 port, bool startListening)
{
    QAbstractSocket::NetworkLayerProtocol proto = address.protocol();

    int socket = createNewSocket(proto);
    if (socket < 0) {
        qCCritical(CWSGI_BALANCER) << "Failed to create new socket";
        return -1;
    }

    int optval = 1;
    if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval))) {
        qCCritical(CWSGI_BALANCER) << "Failed to set SO_REUSEPORT on socket" << socket;
        return -1;
    }

    if (!nativeBind(socket, address, port)) {
        qCCritical(CWSGI_BALANCER) << "Failed to bind to socket" << socket;
        return -1;
    }

    if (startListening && ::listen(socket, 100) < 0) {
        qCCritical(CWSGI_BALANCER) << "Failed to listen to socket" << socket;
        return -1;
    }

    return socket;
}
#endif // Q_OS_LINUX

void TcpServerBalancer::setBalancer(bool enable)
{
    m_balancer = enable;
}

void TcpServerBalancer::incomingConnection(qintptr handle)
{
    TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());

    serverIdle->createConnection(handle);
}

TcpServer *TcpServerBalancer::createServer(CWsgiEngine *engine)
{
    TcpServer *server;
    if (m_sslConfiguration) {
        auto sslServer = new TcpSslServer(m_serverName, m_protocol, m_wsgi, engine);
        sslServer->setSslConfiguration(*m_sslConfiguration);
        server = sslServer;
    } else {
        server = new TcpServer(m_serverName, m_protocol, m_wsgi, engine);
    }
    connect(engine, &CWsgiEngine::shutdown, server, &TcpServer::shutdown);

    if (m_balancer) {
        connect(engine, &CWsgiEngine::started, this, [=] () {
            m_servers.push_back(server);
            resumeAccepting();
        }, Qt::QueuedConnection);
        connect(server, &TcpServer::createConnection, server, &TcpServer::incomingConnection, Qt::QueuedConnection);
    } else {

#ifdef Q_OS_LINUX
        if (m_wsgi->reusePort()) {
            connect(engine, &CWsgiEngine::started, this, [=] () {
                int socket = listenReuse(m_address, m_port, true);
                if (!server->setSocketDescriptor(socket)) {
                    qFatal("Failed to set server socket descriptor, reuse-port");
                }
            }, Qt::DirectConnection);
            return server;
        }
#endif

        if (server->setSocketDescriptor(socketDescriptor())) {
            server->pauseAccepting();
            connect(engine, &CWsgiEngine::started, server, &TcpServer::resumeAccepting, Qt::DirectConnection);
        } else {
            qFatal("Failed to set server socket descriptor");
        }
    }

    return server;
}

#include "moc_tcpserverbalancer.cpp"
<commit_msg>wsgi: Add support for brackets in IPv6 socket string as of RFC 2732<commit_after>/*
 * Copyright (C) 2017 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "tcpserverbalancer.h"

#include "wsgi.h"
#include "cwsgiengine.h"
#include "tcpserver.h"
#include "tcpsslserver.h"

#include <QFile>
#include <QLoggingCategory>

#include <QSslKey>

#include <iostream>

#ifdef Q_OS_LINUX
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#endif

Q_LOGGING_CATEGORY(CWSGI_BALANCER, "wsgi.tcp_server_balancer")

using namespace CWSGI;

#ifdef Q_OS_LINUX
int listenReuse(const QHostAddress &address, quint16 port, bool startListening);
#endif

TcpServerBalancer::TcpServerBalancer(WSGI *wsgi) : QTcpServer(wsgi)
  , m_wsgi(wsgi)
{
}

TcpServerBalancer::~TcpServerBalancer()
{
    delete m_sslConfiguration;
}

bool TcpServerBalancer::listen(const QString &line, Protocol *protocol, bool secure)
{
    m_protocol = protocol;

    int commaPos = line.indexOf(QLatin1Char(','));
    const QString addressPortString = line.mid(0, commaPos);

    QString addressString;
    int closeBracketPos = addressPortString.indexOf(QLatin1Char(']'));
    if (closeBracketPos != -1) {
        if (!line.startsWith(QLatin1Char('['))) {
            std::cerr << "Failed to parse address: " << qPrintable(addressPortString) << std::endl;
            exit(1);
        }
        addressString = addressPortString.mid(1, closeBracketPos - 1);
    } else {
        addressString = addressPortString.section(QLatin1Char(':'), 0, -2);
    }
    const QString portString = addressPortString.section(QLatin1Char(':'), -1);

    QHostAddress address;
    if (addressString.isEmpty()) {
        address = QHostAddress(QHostAddress::Any);
    } else {
        address.setAddress(addressString);
    }

    bool ok;
    quint16 port = portString.toUInt(&ok);
    if (!ok || (port < 1 && port > 35554)) {
        port = 80;
    }

    if (secure) {
        if (commaPos == -1) {
            std::cerr << "No SSL certificate specified" << std::endl;
            exit(1);
        }

        const QString sslString = line.mid(commaPos + 1);
        const QString certPath = sslString.section(QLatin1Char(','), 0, 0);
        QFile certFile(certPath);
        if (!certFile.open(QFile::ReadOnly)) {
            std::cerr << "Failed to open SSL certificate" << qPrintable(certPath)
                      << qPrintable(certFile.errorString()) << std::endl;
            exit(1);
        }
        QSslCertificate cert(&certFile);
        if (cert.isNull()) {
            std::cerr << "Failed to parse SSL certificate" << std::endl;
            exit(1);
        }

        const QString keyPath = sslString.section(QLatin1Char(','), 1, 1);
        QFile keyFile(keyPath);
        if (!keyFile.open(QFile::ReadOnly)) {
            std::cerr << "Failed to open SSL private key" << qPrintable(keyPath)
                      << qPrintable(keyFile.errorString()) << std::endl;
            exit(1);
        }
        QSslKey key(&keyFile, QSsl::Rsa);
        if (key.isNull()) {
            std::cerr << "Failed to parse SSL private key" << std::endl;
            exit(1);
        }

        m_sslConfiguration = new QSslConfiguration;
        m_sslConfiguration->setLocalCertificate(cert);
        m_sslConfiguration->setPrivateKey(key);
        if (m_wsgi->httpsH2()) {
            m_sslConfiguration->setAllowedNextProtocols({ QByteArrayLiteral("h2") });
        }
    }

    m_address = address;
    m_port = port;

    bool reusePort = false;
#ifdef Q_OS_LINUX
    reusePort = m_wsgi->reusePort();
#endif
    if (reusePort) {
#ifdef Q_OS_LINUX
        int socket = listenReuse(address, port, false);
        if (socket > 0) {
            setSocketDescriptor(socket);
            pauseAccepting();
        } else {
            std::cerr << "Failed to listen on TCP: " << qPrintable(line)
                      << " : " << qPrintable(errorString()) << std::endl;
            exit(1);
        }
#endif
    } else {
        bool ret = QTcpServer::listen(address, port);
        if (ret) {
            pauseAccepting();
        } else {
            std::cerr << "Failed to listen on TCP: " << qPrintable(line)
                      << " : " << qPrintable(errorString()) << std::endl;
            exit(1);
        }
    }

    m_serverName = serverAddress().toString() + QLatin1Char(':') + QString::number(port);
    return true;
}

#ifdef Q_OS_LINUX
// UnixWare 7 redefines socket -> _socket
static inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0)
{
    Q_ASSERT((flags & ~O_NONBLOCK) == 0);

    int fd;
#ifdef QT_THREADSAFE_CLOEXEC
    int newtype = type | SOCK_CLOEXEC;
    if (flags & O_NONBLOCK)
        newtype |= SOCK_NONBLOCK;
    fd = ::socket(domain, newtype, protocol);
    return fd;
#else
    fd = ::socket(domain, type, protocol);
    if (fd == -1)
        return -1;

    ::fcntl(fd, F_SETFD, FD_CLOEXEC);

    // set non-block too?
    if (flags & O_NONBLOCK)
        ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);

    return fd;
#endif
}

int createNewSocket(QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{
    int protocol = 0;

    int domain = (socketProtocol == QAbstractSocket::IPv6Protocol
                  || socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET;
    int type = SOCK_STREAM;

    int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
    if (socket < 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && errno == EAFNOSUPPORT) {
        domain = AF_INET;
        socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
        socketProtocol = QAbstractSocket::IPv4Protocol;
    }

    if (socket < 0) {
        int ecopy = errno;
        switch (ecopy) {
        case EPROTONOSUPPORT:
        case EAFNOSUPPORT:
        case EINVAL:
            qCDebug(CWSGI_BALANCER) << "setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString)";
            break;
        case ENFILE:
        case EMFILE:
        case ENOBUFS:
        case ENOMEM:
            qCDebug(CWSGI_BALANCER) << "setError(QAbstractSocket::SocketResourceError, ResourceErrorString)";
            break;
        case EACCES:
            qCDebug(CWSGI_BALANCER) << "setError(QAbstractSocket::SocketAccessError, AccessErrorString)";
            break;
        default:
            break;
        }

#if defined (QNATIVESOCKETENGINE_DEBUG)
        qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
                socketType, socketProtocol,
                strerror(ecopy));
#endif

        return false;
    }

#if defined (QNATIVESOCKETENGINE_DEBUG)
    qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
            socketType, socketProtocol);
#endif

    return socket;
}

union qt_sockaddr {
    sockaddr a;
    sockaddr_in a4;
    sockaddr_in6 a6;
};

#  define QT_SOCKLEN_T int
#define QT_SOCKET_BIND          ::bind

namespace {
namespace SetSALen {
    template <typename T> void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len)
    { sa->sa_len = len; }
    template <typename T> void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len)
    { sin6->sin6_len = len; }
    template <typename T> void set(T *, ...) {}
}
}

void setPortAndAddress(quint16 port, const QHostAddress &address, QAbstractSocket::NetworkLayerProtocol socketProtocol, qt_sockaddr *aa, int *sockAddrSize)
{
    if (address.protocol() == QAbstractSocket::IPv6Protocol
        || address.protocol() == QAbstractSocket::AnyIPProtocol
        || socketProtocol == QAbstractSocket::IPv6Protocol
        || socketProtocol == QAbstractSocket::AnyIPProtocol) {
        memset(&aa->a6, 0, sizeof(sockaddr_in6));
        aa->a6.sin6_family = AF_INET6;
//#if QT_CONFIG(networkinterface)
//            aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId());
//#endif
        aa->a6.sin6_port = htons(port);
        Q_IPV6ADDR tmp = address.toIPv6Address();
        memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp));
        *sockAddrSize = sizeof(sockaddr_in6);
        SetSALen::set(&aa->a, sizeof(sockaddr_in6));
    } else {
        memset(&aa->a, 0, sizeof(sockaddr_in));
        aa->a4.sin_family = AF_INET;
        aa->a4.sin_port = htons(port);
        aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address());
        *sockAddrSize = sizeof(sockaddr_in);
        SetSALen::set(&aa->a, sizeof(sockaddr_in));
    }
}

bool nativeBind(int socketDescriptor, const QHostAddress &address, quint16 port)
{
    qt_sockaddr aa;
    int sockAddrSize;
    setPortAndAddress(port, address, address.protocol(), &aa, &sockAddrSize);

#ifdef IPV6_V6ONLY
    if (aa.a.sa_family == AF_INET6) {
        int ipv6only = 0;
        if (address.protocol() == QAbstractSocket::IPv6Protocol)
            ipv6only = 1;
        //default value of this socket option varies depending on unix variant (or system configuration on BSD), so always set it explicitly
        ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
    }
#endif

    int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
    if (bindResult < 0 && errno == EAFNOSUPPORT && address.protocol() == QAbstractSocket::AnyIPProtocol) {
        // retry with v4
        aa.a4.sin_family = AF_INET;
        aa.a4.sin_port = htons(port);
        aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address());
        sockAddrSize = sizeof(aa.a4);
        bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
    }

    if (bindResult < 0) {
#if defined (QNATIVESOCKETENGINE_DEBUG)
        int ecopy = errno;
#endif
//        switch(errno) {
//        case EADDRINUSE:
//            setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
//            break;
//        case EACCES:
//            setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
//            break;
//        case EINVAL:
//            setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
//            break;
//        case EADDRNOTAVAIL:
//            setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString);
//            break;
//        default:
//            break;
//        }

#if defined (QNATIVESOCKETENGINE_DEBUG)
        qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
                address.toString().toLatin1().constData(), port, strerror(ecopy));
#endif

        return false;
    }

#if defined (QNATIVESOCKETENGINE_DEBUG)
    qCDebug(CWSGI_BALANCER, "QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
            address.toString().toLatin1().constData(), port);
#endif
//    socketState = QAbstractSocket::BoundState;
    return true;
}

int listenReuse(const QHostAddress &address, quint16 port, bool startListening)
{
    QAbstractSocket::NetworkLayerProtocol proto = address.protocol();

    int socket = createNewSocket(proto);
    if (socket < 0) {
        qCCritical(CWSGI_BALANCER) << "Failed to create new socket";
        return -1;
    }

    int optval = 1;
    if (::setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval))) {
        qCCritical(CWSGI_BALANCER) << "Failed to set SO_REUSEPORT on socket" << socket;
        return -1;
    }

    if (!nativeBind(socket, address, port)) {
        qCCritical(CWSGI_BALANCER) << "Failed to bind to socket" << socket;
        return -1;
    }

    if (startListening && ::listen(socket, 100) < 0) {
        qCCritical(CWSGI_BALANCER) << "Failed to listen to socket" << socket;
        return -1;
    }

    return socket;
}
#endif // Q_OS_LINUX

void TcpServerBalancer::setBalancer(bool enable)
{
    m_balancer = enable;
}

void TcpServerBalancer::incomingConnection(qintptr handle)
{
    TcpServer *serverIdle = m_servers.at(m_currentServer++ % m_servers.size());

    serverIdle->createConnection(handle);
}

TcpServer *TcpServerBalancer::createServer(CWsgiEngine *engine)
{
    TcpServer *server;
    if (m_sslConfiguration) {
        auto sslServer = new TcpSslServer(m_serverName, m_protocol, m_wsgi, engine);
        sslServer->setSslConfiguration(*m_sslConfiguration);
        server = sslServer;
    } else {
        server = new TcpServer(m_serverName, m_protocol, m_wsgi, engine);
    }
    connect(engine, &CWsgiEngine::shutdown, server, &TcpServer::shutdown);

    if (m_balancer) {
        connect(engine, &CWsgiEngine::started, this, [=] () {
            m_servers.push_back(server);
            resumeAccepting();
        }, Qt::QueuedConnection);
        connect(server, &TcpServer::createConnection, server, &TcpServer::incomingConnection, Qt::QueuedConnection);
    } else {

#ifdef Q_OS_LINUX
        if (m_wsgi->reusePort()) {
            connect(engine, &CWsgiEngine::started, this, [=] () {
                int socket = listenReuse(m_address, m_port, true);
                if (!server->setSocketDescriptor(socket)) {
                    qFatal("Failed to set server socket descriptor, reuse-port");
                }
            }, Qt::DirectConnection);
            return server;
        }
#endif

        if (server->setSocketDescriptor(socketDescriptor())) {
            server->pauseAccepting();
            connect(engine, &CWsgiEngine::started, server, &TcpServer::resumeAccepting, Qt::DirectConnection);
        } else {
            qFatal("Failed to set server socket descriptor");
        }
    }

    return server;
}

#include "moc_tcpserverbalancer.cpp"
<|endoftext|>