/*!
  Listen for connections on UNIX domain.
 */
int TApplicationServerBase::nativeListen(const QString &fileDomain, OpenFlag flag)
{
    int sd = -1;
    struct sockaddr_un addr;

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = PF_UNIX;
    if (sizeof(addr.sun_path) < (uint)fileDomain.toLatin1().size() + 1) {
        tSystemError("too long name for UNIX domain socket  [%s:%d]", __FILE__, __LINE__);
        return sd;
    }
    strncpy(addr.sun_path, fileDomain.toLatin1().data(), sizeof(addr.sun_path));

    // create unix domain socket
    sd = ::socket(PF_UNIX, SOCK_STREAM, 0);
    if (sd < 0) {
        tSystemError("Socket create failed  [%s:%d]", __FILE__, __LINE__);
        return sd;
    }

    if (flag == CloseOnExec) {
        ::fcntl(sd, F_SETFD, FD_CLOEXEC); // set close-on-exec flag
    }
    ::fcntl(sd, F_SETFL, ::fcntl(sd, F_GETFL) | O_NONBLOCK);  // non-block

    QFile file(fileDomain);
    if (file.exists()) {
        file.remove();
        tSystemWarn("File for UNIX domain socket removed: %s", qPrintable(fileDomain));
    }

    // Bind
    if (::bind(sd, (sockaddr *)&addr, sizeof(sockaddr_un)) < 0) {
        tSystemError("Bind failed  [%s:%d]", __FILE__, __LINE__);
        goto socket_error;
    }
    file.setPermissions((QFile::Permissions)0x777);

    // Listen
    if (::listen(sd, 50) < 0) {
        tSystemError("Listen failed  [%s:%d]", __FILE__, __LINE__);
        goto socket_error;
    }

    return sd;

socket_error:
    nativeClose(sd);
    return -1;
}
bool TApplicationServer::open()
{
    T_TRACEFUNC("");

    if (!isListening()) {
        quint16 port = Tf::app()->appSettings().value("ListenPort").toUInt();
        int sock = nativeListen(QHostAddress::Any, port);
        if (sock > 0 && setSocketDescriptor(sock)) {
            tSystemDebug("listen successfully.  port:%d", port);
        } else {
            tSystemError("Failed to set socket descriptor: %d", sock);
            nativeClose(sock);
            return false;
        }
    }
    
    // Loads libraries
    if (!libLoaded) {

        // Sets work directory
        QString libPath = Tf::app()->libPath();
        if (QDir(libPath).exists()) {
            // To resolve the symbols in the app libraries
            QDir::setCurrent(libPath);
        } else {
            tSystemError("lib directory not found");
            return false;
        }

        QStringList libs;
#if defined(Q_OS_WIN)
        libs << "controller" << "view";
#else
        libs << "libcontroller" << "libview";
#endif

        for (QStringListIterator it(libs); it.hasNext(); ) {
            QLibrary lib(it.next());
            if (lib.load()) {
                tSystemDebug("Library loaded: %s", qPrintable(lib.fileName()));
                libLoaded = true;
            } else {
                tSystemError("%s", qPrintable(lib.errorString()));
            }
        }

        QStringList controllers = TActionController::availableControllers();
        tSystemDebug("Available controllers: %s", qPrintable(controllers.join(" ")));
    }
    QDir::setCurrent(Tf::app()->webRootPath());

    TUrlRoute::instantiate();
    TSqlDatabasePool::instantiate();
    
    switch (Tf::app()->multiProcessingModule()) {
    case TWebApplication::Thread: {
        TStaticInitializeThread *initializer = new TStaticInitializeThread();
        initializer->start();
        initializer->wait();
        delete initializer;
        break; }
    
    case TWebApplication::Prefork: {
        TStaticInitializer *initializer = new TStaticInitializer();
        initializer->start();
        delete initializer;
        break; }

    default:
        break;
    }

    return true;
}
bool TApplicationServer::open()
{
    T_TRACEFUNC();

    if (!isListening()) {
        quint16 port = Tf::app()->appSettings().value("ListenPort").toUInt();
        int sock = nativeListen(QHostAddress::Any, port);
        if (sock > 0 && setSocketDescriptor(sock)) {
            tSystemDebug("listen successfully.  port:%d", port);
        } else {
            tSystemError("Failed to set socket descriptor: %d", sock);
            nativeClose(sock);
            return false;
        }
    }
    
    // Loads libraries
    if (!libLoaded) {

        // Sets work directory
        QString libPath = Tf::app()->libPath();
        if (QDir(libPath).exists()) {
            // To resolve the symbols in the app libraries
            QDir::setCurrent(libPath);
        } else {
            tSystemError("lib directory not found");
            return false;
        }
        
        QStringList filter;
#if defined(Q_OS_WIN)
        filter << "controller.dll" << "view.dll";
#elif defined(Q_OS_DARWIN)
        filter << "libcontroller.dylib" << "libview.dylib";
#elif defined(Q_OS_UNIX)
        filter << "libcontroller.so" << "libview.so";
#else
        filter << "libcontroller.*" << "libview.*";
#endif

        QDir controllerDir(".");
        QStringList list = controllerDir.entryList(filter, QDir::Files);
        for (QStringListIterator i(list); i.hasNext(); ) {
            QString path = controllerDir.absoluteFilePath(i.next());
            QLibrary lib(path);
            if (lib.load()) {
                tSystemDebug("Library loaded: %s", qPrintable(path));
                libLoaded = true;
            } else {
                tSystemError("%s", qPrintable(lib.errorString()));
            }
        }
    }
    QDir::setCurrent(Tf::app()->webRootPath());

    TUrlRoute::instantiate();
    TSqlDatabasePool::instantiate();
    
    switch (Tf::app()->multiProcessingModule()) {
    case TWebApplication::Thread: {
        TStaticInitializeThread *initializer = new TStaticInitializeThread();
        initializer->start();
        initializer->wait();
        delete initializer;
        break; }
    
    case TWebApplication::Prefork: {
        TStaticInitializer *initializer = new TStaticInitializer();
        initializer->start();
        delete initializer;
        break; }

    default:
        break;
    }

    return true;
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
                                 QFile::MemoryMapFlags flags)
{
#ifndef Q_OS_WINPHONE
    Q_Q(QFSFileEngine);
    Q_UNUSED(flags);
    if (openMode == QFile::NotOpen) {
        q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
        return 0;
    }
    if (offset == 0 && size == 0) {
        q->setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
        return 0;
    }

    // check/setup args to map
    DWORD access = 0;
    if (flags & QFileDevice::MapPrivateOption) {
#ifdef FILE_MAP_COPY
        access = FILE_MAP_COPY;
#else
        q->setError(QFile::UnspecifiedError, "MapPrivateOption unsupported");
        return 0;
#endif
    } else if (openMode & QIODevice::WriteOnly) {
        access = FILE_MAP_WRITE;
    } else if (openMode & QIODevice::ReadOnly) {
        access = FILE_MAP_READ;
    }

    if (mapHandle == NULL) {
        // get handle to the file
        HANDLE handle = fileHandle;

#ifndef Q_OS_WINCE
        if (handle == INVALID_HANDLE_VALUE && fh)
            handle = (HANDLE)::_get_osfhandle(QT_FILENO(fh));
#endif

#ifdef Q_USE_DEPRECATED_MAP_API
        nativeClose();
        // handle automatically closed by kernel with mapHandle (below).
        handle = ::CreateFileForMapping((const wchar_t*)fileEntry.nativeFilePath().utf16(),
                GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0),
                0,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL);
        // Since this is a special case, we check if the return value was NULL and if so
        // we change it to INVALID_HANDLE_VALUE to follow the logic inside this function.
        if(0 == handle)
            handle = INVALID_HANDLE_VALUE;
#endif

        if (handle == INVALID_HANDLE_VALUE) {
            q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
            return 0;
        }

        // first create the file mapping handle
        DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY;
#ifndef Q_OS_WINRT
        mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0);
#else
        mapHandle = ::CreateFileMappingFromApp(handle, 0, protection, 0, 0);
#endif
        if (mapHandle == NULL) {
            q->setError(QFile::PermissionsError, qt_error_string());
#ifdef Q_USE_DEPRECATED_MAP_API
            ::CloseHandle(handle);
#endif
            return 0;
        }
    }

    DWORD offsetHi = offset >> 32;
    DWORD offsetLo = offset & Q_UINT64_C(0xffffffff);
    SYSTEM_INFO sysinfo;
#ifndef Q_OS_WINRT
    ::GetSystemInfo(&sysinfo);
#else
    ::GetNativeSystemInfo(&sysinfo);
#endif
    DWORD mask = sysinfo.dwAllocationGranularity - 1;
    DWORD extra = offset & mask;
    if (extra)
        offsetLo &= ~mask;

    // attempt to create the map
#ifndef Q_OS_WINRT
    LPVOID mapAddress = ::MapViewOfFile(mapHandle, access,
                                      offsetHi, offsetLo, size + extra);
#else
    LPVOID mapAddress = ::MapViewOfFileFromApp(mapHandle, access,
                                               (ULONG64(offsetHi) << 32) + offsetLo, size + extra);
#endif
    if (mapAddress) {
        uchar *address = extra + static_cast<uchar*>(mapAddress);
        maps[address] = extra;
        return address;
    }

    switch(GetLastError()) {
    case ERROR_ACCESS_DENIED:
        q->setError(QFile::PermissionsError, qt_error_string());
        break;
    case ERROR_INVALID_PARAMETER:
        // size are out of bounds
    default:
        q->setError(QFile::UnspecifiedError, qt_error_string());
    }

    ::CloseHandle(mapHandle);
    mapHandle = NULL;
#else // !Q_OS_WINPHONE
    Q_UNUSED(offset);
    Q_UNUSED(size);
    Q_UNUSED(flags);
    Q_UNIMPLEMENTED();
#endif // Q_OS_WINPHONE
    return 0;
}
/*!
  Listen a port with SO_REUSEADDR option.
  This function must be called in a tfserver process.
 */
int TApplicationServer::nativeListen(const QHostAddress &address, quint16 port, OpenFlag)
{
    int protocol = (address.protocol() == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET;
    SOCKET sock = ::WSASocket(protocol, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    if (sock == INVALID_SOCKET) {
        tSystemError("WSASocket Error: %d", WSAGetLastError());
        return -1;
    }
    
    // ReuseAddr
    bool on = true;
    if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) {
        tSystemError("setsockopt error: %d", WSAGetLastError());
        goto error_socket;
    }
    
    if (address.protocol() == QAbstractSocket::IPv6Protocol) {
        struct tf_in6_addr {
            quint8 tf_s6_addr[16];
        };
        struct tf_sockaddr_in6 {
            short   sin6_family;            /* AF_INET6 */
            quint16 sin6_port;              /* Transport level port number */
            quint32 sin6_flowinfo;          /* IPv6 flow information */
            struct  tf_in6_addr sin6_addr;  /* IPv6 address */
            quint32 sin6_scope_id;          /* set of interfaces for a scope */
        } sa6;
        
        memset(&sa6, 0, sizeof(sa6));
        sa6.sin6_family = AF_INET6;
        WSAHtons(sock, port, &(sa6.sin6_port));
        Q_IPV6ADDR ipv6 = address.toIPv6Address();
        memcpy(&(sa6.sin6_addr.tf_s6_addr), &ipv6, sizeof(ipv6));
        if (::bind(sock, (struct sockaddr *)&sa6, sizeof(sa6)) != 0) {
            tSystemError("bind(v6) error: %d", WSAGetLastError());
            goto error_socket;
        }
        
    } else if (address.protocol() == QAbstractSocket::IPv4Protocol
#if QT_VERSION >= 0x050000
               || address.protocol() == QAbstractSocket::QAbstractSocket::AnyIPProtocol
#endif
        ) {
        struct sockaddr_in sa;
        memset(&sa, 0, sizeof(sa));
        sa.sin_family = AF_INET;
        WSAHtons(sock, port, &(sa.sin_port));
        WSAHtonl(sock, address.toIPv4Address(), &(sa.sin_addr.s_addr));
        if (::bind(sock, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
            tSystemError("bind error: %d", WSAGetLastError());
            goto error_socket;
        }
    } else {  // UnknownNetworkLayerProtocol
        goto error_socket;
    }
    
    if (::listen(sock, 50) != 0) {
        tSystemError("listen error: %d", WSAGetLastError());
        goto error_socket;
    }
    return sock;

error_socket:
    nativeClose(sock);
    return -1;
}