/**
 * Offer an Unix socket over this stream tube.
 *
 * This method offers an Unix socket over this stream tube. The socket address is given as a
 * a QString, which should contain the path to the socket. Abstract Unix sockets are also supported,
 * and are given as addresses prefixed with a \c NUL byte.
 *
 * If your application uses QLocalServer as the local Unix server implementation, you can use the
 * offerUnixSocket(const QLocalServer *, const QVariantMap &, bool) overload instead to more easily
 * pass the server's listen address.
 *
 * Note that only connection managers for which supportsUnixSocketsOnLocalhost() or
 * supportsAbstractUnixSocketsOnLocalhost() is \c true support exporting Unix sockets.
 *
 * If supportsUnixSocketsWithCredentials() or supportsAbstractUnixSocketsWithCredentials(), as
 * appropriate, returns \c true, the \c requireCredentials parameter can be set to \c true to make
 * the connection manager pass an SCM_CREDS or SCM_CREDENTIALS message as supported by the platform
 * when making a new connection. This enables preventing other local users from connecting to the
 * service, but might not be possible to use with all protocols as the message is in-band in the
 * data stream.
 *
 * Arbitrary parameters can be associated with the offer to bootstrap legacy protocols; these will
 * in particular be available as IncomingStreamTubeChannel::parameters() for a tube receiver
 * implemented using TelepathyQt in the other end.
 *
 * This method requires OutgoingStreamTubeChannel::FeatureCore to be ready.
 *
 * \param socketAddress A valid path to an existing Unix socket or abstract Unix socket.
 * \param parameters A dictionary of arbitrary parameters to send with the tube offer.
 * \param requireCredentials Whether the server requires a SCM_CREDS or SCM_CREDENTIALS message
 *                           upon connection.
 * \return A PendingOperation which will emit PendingOperation::finished
 *         when the stream tube is ready to be used
 *         (hence in the #TubeStateOpen state).
 */
PendingOperation *OutgoingStreamTubeChannel::offerUnixSocket(
        const QString &socketAddress,
        const QVariantMap &parameters,
        bool requireCredentials)
{
    SocketAccessControl accessControl = requireCredentials ?
            SocketAccessControlCredentials :
            SocketAccessControlLocalhost;

    if (!isReady(OutgoingStreamTubeChannel::FeatureCore)) {
        warning() << "OutgoingStreamTubeChannel::FeatureCore must be ready before "
                "calling offerTube";
        return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                OutgoingStreamTubeChannelPtr(this));
    }

    // The tube must be not offered
    if (state() != TubeChannelStateNotOffered) {
        warning() << "You can not expose more than a socket for each Stream Tube";
        return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel busy"), OutgoingStreamTubeChannelPtr(this));
    }

    // In this specific overload, we're handling an Unix/AbstractUnix socket
    if (socketAddress.startsWith(QLatin1Char('\0'))) {
        // Abstract Unix socket case
        // Check if the combination type/access control is supported
        if ((accessControl == SocketAccessControlLocalhost &&
                !supportsAbstractUnixSocketsOnLocalhost()) ||
            (accessControl == SocketAccessControlCredentials &&
                !supportsAbstractUnixSocketsWithCredentials()) ) {
            warning() << "You requested an address type/access control combination "
                    "not supported by this channel";
            return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED,
                    QLatin1String("The requested address type/access control "
                            "combination is not supported"),
                    OutgoingStreamTubeChannelPtr(this));
        }

        setAddressType(SocketAddressTypeAbstractUnix);
        setAccessControl(accessControl);
        setLocalAddress(socketAddress);

        PendingVoid *pv = new PendingVoid(
                interface<Client::ChannelTypeStreamTubeInterface>()->Offer(
                        SocketAddressTypeAbstractUnix,
                        QDBusVariant(QVariant(socketAddress.toLatin1())),
                        accessControl,
                        parameters),
                OutgoingStreamTubeChannelPtr(this));
        PendingOpenTube *op = new PendingOpenTube(pv, parameters,
                OutgoingStreamTubeChannelPtr(this));
        return op;
    } else {
        // Unix socket case
        // Check if the combination type/access control is supported
        if ((accessControl == SocketAccessControlLocalhost &&
                !supportsUnixSocketsOnLocalhost()) ||
            (accessControl == SocketAccessControlCredentials &&
                !supportsUnixSocketsWithCredentials()) ||
            (accessControl != SocketAccessControlLocalhost &&
                accessControl != SocketAccessControlCredentials) ) {
            warning() << "You requested an address type/access control combination "
                "not supported by this channel";
            return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED,
                    QLatin1String("The requested address type/access control "
                            "combination is not supported"),
                    OutgoingStreamTubeChannelPtr(this));
        }

        setAddressType(SocketAddressTypeUnix);
        setAccessControl(accessControl);
        setLocalAddress(socketAddress);

        PendingVoid *pv = new PendingVoid(
                interface<Client::ChannelTypeStreamTubeInterface>()->Offer(
                        SocketAddressTypeUnix,
                        QDBusVariant(QVariant(socketAddress.toLatin1())),
                        accessControl,
                        parameters),
                OutgoingStreamTubeChannelPtr(this));
        PendingOpenTube *op = new PendingOpenTube(pv, parameters,
                OutgoingStreamTubeChannelPtr(this));
        return op;
    }
}
/**
 * Accept an incoming stream tube as a Unix socket.
 *
 * This method accepts an incoming connection request for a stream tube. It can be called
 * only if the tube is in the #TubeStateLocalPending state.
 *
 * An Unix socket (can be used with QLocalSocket or alike) will be opened by the connection manager
 * as the local tube endpoint. This is only supported if supportsUnixSocketsOnLocalhost() is \c
 * true.
 *
 * You can also specify whether the CM should require an SCM_CREDS or SCM_CREDENTIALS message
 * upon connection instead of accepting every incoming connection from localhost. This provides
 * additional security, but requires sending the byte retrieved from
 * PendingStreamTubeConnection::credentialByte() in-line in the socket byte stream (in a credentials
 * message if available on the platform), which might not be compatible with all protocols or
 * libraries. Also, only connection managers for which supportsUnixSocketsWithCredentials() is \c
 * true support this type of access control.
 *
 * This method requires IncomingStreamTubeChannel::FeatureCore to be ready.
 *
 * \param requireCredentials Whether the CM should require an SCM_CREDS or SCM_CREDENTIALS message
 *                           upon connection.
 * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished
 *         when the stream tube is ready to be used
 *         (hence in the #TubeStateOpen state).
 * \sa StreamTubeChannel::supportsUnixSocketsOnLocalhost(),
 *     StreamTubeChannel::supportsUnixSocketsWithCredentials(),
 *     StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost(),
 *     StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials()
 */
PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsUnixSocket(
        bool requireCredentials)
{
    if (!isReady(IncomingStreamTubeChannel::FeatureCore)) {
        warning() << "IncomingStreamTubeChannel::FeatureCore must be ready before "
                "calling acceptTubeAsUnixSocket";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                IncomingStreamTubeChannelPtr(this));
    }

    // The tube must be in local pending state
    if (state() != TubeChannelStateLocalPending) {
        warning() << "You can accept tubes only when they are in LocalPending state";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                IncomingStreamTubeChannelPtr(this));
    }

    SocketAccessControl accessControl = requireCredentials ?
            SocketAccessControlCredentials :
            SocketAccessControlLocalhost;
    setAddressType(SocketAddressTypeUnix);
    setAccessControl(accessControl);

    // Fail early if the combination is not supported
    if ((accessControl == SocketAccessControlLocalhost &&
            addressType() == SocketAddressTypeUnix &&
            !supportsUnixSocketsOnLocalhost()) ||
        (accessControl == SocketAccessControlCredentials &&
            addressType() == SocketAddressTypeUnix &&
            !supportsUnixSocketsWithCredentials()) ||
        (accessControl == SocketAccessControlLocalhost &&
            addressType() == SocketAddressTypeAbstractUnix &&
           !supportsAbstractUnixSocketsOnLocalhost()) ||
        (accessControl == SocketAccessControlCredentials &&
           addressType() == SocketAddressTypeAbstractUnix &&
           !supportsAbstractUnixSocketsWithCredentials())) {
        warning() << "You requested an address type/access control combination "
                "not supported by this channel";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_IMPLEMENTED,
                QLatin1String("The requested address type/access control "
                        "combination is not supported"),
                IncomingStreamTubeChannelPtr(this));
    }

    QDBusVariant accessControlParam;
    uchar credentialByte = 0;
    if (accessControl == SocketAccessControlLocalhost) {
        accessControlParam.setVariant(qVariantFromValue(static_cast<uint>(0)));
    } else if (accessControl == SocketAccessControlCredentials) {
        if (mPriv->initRandom) {
            qsrand(QTime::currentTime().msec());
            mPriv->initRandom = false;
        }
        credentialByte = static_cast<uchar>(qrand());
        accessControlParam.setVariant(qVariantFromValue(credentialByte));
    } else {
        Q_ASSERT(false);
    }

    // Perform the actual call
    PendingVariant *pv = new PendingVariant(
            interface<Client::ChannelTypeStreamTubeInterface>()->Accept(
                    addressType(),
                    accessControl,
                    accessControlParam),
            IncomingStreamTubeChannelPtr(this));

    PendingStreamTubeConnection *op = new PendingStreamTubeConnection(pv, addressType(),
            requireCredentials, credentialByte, IncomingStreamTubeChannelPtr(this));
    return op;
}
/**
 * Offer a TCP socket over this stream tube.
 *
 * This method offers a TCP socket over this tube. The socket's address is given as
 * a QHostAddress and a numerical port in native byte order.
 *
 * If your application uses QTcpServer as the local TCP server implementation, you can use the
 * offerTcpSocket(const QTcpServer *, const QVariantMap &) overload instead to more easily pass the
 * server's listen address.
 *
 * It is guaranteed that when the PendingOperation returned by this method will be completed,
 * the tube will be opened and ready to be used.
 *
 * Connection managers adhering to the \telepathy_spec should always support offering IPv4 TCP
 * sockets. IPv6 sockets are only supported if supportsIPv6SocketsOnLocalhost() is \c true.
 *
 * Note that the library will try to use #SocketAccessControlPort access control whenever possible,
 * as it allows to map connections to users based on their source addresses. If
 * supportsIPv4SocketsWithSpecifiedAddress() or supportsIPv6SocketsWithSpecifiedAddress() for IPv4
 * and IPv6 sockets respectively is \c false, this feature is not available, and the
 * connectionsForSourceAddresses() map won't contain useful distinct keys.
 *
 * Arbitrary parameters can be associated with the offer to bootstrap legacy protocols; these will
 * in particular be available as IncomingStreamTubeChannel::parameters() for a tube receiver
 * implemented using TelepathyQt in the other end.
 *
 * This method requires OutgoingStreamTubeChannel::FeatureCore to be ready.
 *
 * \param address A valid IPv4 or IPv6 address pointing to an existing socket.
 * \param port The port the socket is listening for connections to.
 * \param parameters A dictionary of arbitrary parameters to send with the tube offer.
 * \return A PendingOperation which will emit PendingOperation::finished
 *         when the stream tube is ready to be used
 *         (hence in the #TubeStateOpen state).
 */
PendingOperation *OutgoingStreamTubeChannel::offerTcpSocket(
        const QHostAddress &address,
        quint16 port,
        const QVariantMap &parameters)
{
    if (!isReady(OutgoingStreamTubeChannel::FeatureCore)) {
        warning() << "OutgoingStreamTubeChannel::FeatureCore must be ready before "
                "calling offerTube";
        return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                OutgoingStreamTubeChannelPtr(this));
    }

    // The tube must be not offered
    if (state() != TubeChannelStateNotOffered) {
        warning() << "You can not expose more than a socket for each Stream Tube";
        return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel busy"),
                OutgoingStreamTubeChannelPtr(this));
    }

    SocketAccessControl accessControl = SocketAccessControlLocalhost;
    // Check if port is supported

    QHostAddress hostAddress = address;
#if QT_VERSION >= 0x050000
    if (hostAddress == QHostAddress::Any) {
        hostAddress = QHostAddress::AnyIPv4;
    }
#endif

    // In this specific overload, we're handling an IPv4/IPv6 socket
    if (hostAddress.protocol() == QAbstractSocket::IPv4Protocol) {
        // IPv4 case
        SocketAccessControl accessControl;
        // Do some heuristics to find out the best access control.We always prefer port for tracking
        // connections and source addresses.
        if (supportsIPv4SocketsWithSpecifiedAddress()) {
            accessControl = SocketAccessControlPort;
        } else if (supportsIPv4SocketsOnLocalhost()) {
            accessControl = SocketAccessControlLocalhost;
        } else {
            // There are no combinations supported for this socket
            warning() << "You requested an address type/access control combination "
                    "not supported by this channel";
            return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED,
                    QLatin1String("The requested address type/access control "
                            "combination is not supported"),
                    OutgoingStreamTubeChannelPtr(this));
        }

        setAddressType(SocketAddressTypeIPv4);
        setAccessControl(accessControl);
        setIpAddress(qMakePair<QHostAddress, quint16>(hostAddress, port));

        SocketAddressIPv4 addr;
        addr.address = hostAddress.toString();
        addr.port = port;

        PendingVoid *pv = new PendingVoid(
                interface<Client::ChannelTypeStreamTubeInterface>()->Offer(
                        SocketAddressTypeIPv4,
                        QDBusVariant(QVariant::fromValue(addr)),
                        accessControl,
                        parameters),
                OutgoingStreamTubeChannelPtr(this));
        PendingOpenTube *op = new PendingOpenTube(pv, parameters,
                OutgoingStreamTubeChannelPtr(this));
        return op;
    } else if (hostAddress.protocol() == QAbstractSocket::IPv6Protocol) {
        // IPv6 case
        // Do some heuristics to find out the best access control.We always prefer port for tracking
        // connections and source addresses.
        if (supportsIPv6SocketsWithSpecifiedAddress()) {
            accessControl = SocketAccessControlPort;
        } else if (supportsIPv6SocketsOnLocalhost()) {
            accessControl = SocketAccessControlLocalhost;
        } else {
            // There are no combinations supported for this socket
            warning() << "You requested an address type/access control combination "
                    "not supported by this channel";
            return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED,
                    QLatin1String("The requested address type/access control "
                            "combination is not supported"),
                    OutgoingStreamTubeChannelPtr(this));
        }

        setAddressType(SocketAddressTypeIPv6);
        setAccessControl(accessControl);
        setIpAddress(qMakePair<QHostAddress, quint16>(hostAddress, port));

        SocketAddressIPv6 addr;
        addr.address = hostAddress.toString();
        addr.port = port;

        PendingVoid *pv = new PendingVoid(
                interface<Client::ChannelTypeStreamTubeInterface>()->Offer(
                        SocketAddressTypeIPv6,
                        QDBusVariant(QVariant::fromValue(addr)),
                        accessControl,
                        parameters),
                OutgoingStreamTubeChannelPtr(this));
        PendingOpenTube *op = new PendingOpenTube(pv, parameters,
                OutgoingStreamTubeChannelPtr(this));
        return op;
    } else {
        // We're handling an IPv4/IPv6 socket only
        warning() << "offerTube can be called only with a QHostAddress representing "
                "an IPv4 or IPv6 address";
        return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT,
                QLatin1String("Invalid host given"),
                OutgoingStreamTubeChannelPtr(this));
    }

}
/**
 * Accept an incoming stream tube as a TCP socket.
 *
 * This method accepts an incoming connection request for a stream tube. It can be called
 * only if the tube is in the #TubeStateLocalPending state.
 *
 * The connection manager will open a TCP socket for the application to connect to. The address of
 * the socket will be returned in PendingStreamTubeConnection::ipAddress() once the operation has
 * finished successfully.
 *
 * This overload lets you specify an allowed address/port combination for connecting to the CM
 * socket. Connections with other source addresses won't be accepted. The accessors
 * supportsIPv4SocketsWithSpecifiedAddress() and supportsIPv6SocketsWithSpecifiedAddress() can be
 * used to verify that the connection manager supports this kind of access control; otherwise, this
 * method will always fail unless QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or
 * QHostAddress::AnyIPv6 is passed, in which case the behavior is identical to the always supported
 * acceptTubeAsTcpSocket() overload.
 *
 * Note that when using QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or
 * QHostAddress::AnyIPv6, \a allowedPort is ignored.
 *
 * This method requires IncomingStreamTubeChannel::FeatureCore to be ready.
 *
 * \param allowedAddress An allowed address for connecting to the socket.
 * \param allowedPort An allowed port for connecting to the socket.
 * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished
 *         when the stream tube is ready to be used
 *         (hence in the #TubeStateOpen state).
 */
PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsTcpSocket(
        const QHostAddress &allowedAddress,
        quint16 allowedPort)
{
    if (!isReady(IncomingStreamTubeChannel::FeatureCore)) {
        warning() << "IncomingStreamTubeChannel::FeatureCore must be ready before "
                "calling acceptTubeAsTcpSocket";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                IncomingStreamTubeChannelPtr(this));
    }

    // The tube must be in local pending state
    if (state() != TubeChannelStateLocalPending) {
        warning() << "You can accept tubes only when they are in LocalPending state";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                IncomingStreamTubeChannelPtr(this));
    }

    QVariant controlParameter;
    SocketAccessControl accessControl;
    QHostAddress hostAddress = allowedAddress;

#if QT_VERSION >= 0x050000
    if (hostAddress == QHostAddress::Any) {
        hostAddress = QHostAddress::AnyIPv4;
    }
#endif

    // Now, let's check what we need to do with accessControl. There is just one special case, Port.
    if (hostAddress != QHostAddress::Any &&
#if QT_VERSION >= 0x050000
        hostAddress != QHostAddress::AnyIPv4 &&
#endif
        hostAddress != QHostAddress::AnyIPv6) {
        // We need to have a valid QHostAddress AND Port.
        if (hostAddress.isNull() || allowedPort == 0) {
            warning() << "You have to set a valid allowed address+port to use Port access control";
            return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT,
                    QLatin1String("The supplied allowed address and/or port was invalid"),
                    IncomingStreamTubeChannelPtr(this));
        }

        accessControl = SocketAccessControlPort;

        // IPv4 or IPv6?
        if (hostAddress.protocol() == QAbstractSocket::IPv4Protocol) {
            // IPv4 case
            SocketAddressIPv4 addr;
            addr.address = hostAddress.toString();
            addr.port = allowedPort;

            controlParameter = QVariant::fromValue(addr);
        } else if (hostAddress.protocol() == QAbstractSocket::IPv6Protocol) {
            // IPv6 case
            SocketAddressIPv6 addr;
            addr.address = hostAddress.toString();
            addr.port = allowedPort;

            controlParameter = QVariant::fromValue(addr);
        } else {
            // We're handling an IPv4/IPv6 socket only
            warning() << "acceptTubeAsTcpSocket can be called only with a QHostAddress "
                    "representing an IPv4 or IPv6 address";
            return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT,
                    QLatin1String("Invalid host given"),
                    IncomingStreamTubeChannelPtr(this));
        }
    } else {
        // We have to do no special stuff here
        accessControl = SocketAccessControlLocalhost;
        // Since QDBusMarshaller does not like null variants, just add an empty string.
        controlParameter = QVariant(QString());
    }

    // Set the correct address type and access control
    setAddressType(hostAddress.protocol() == QAbstractSocket::IPv4Protocol ?
            SocketAddressTypeIPv4 :
            SocketAddressTypeIPv6);
    setAccessControl(accessControl);

    // Fail early if the combination is not supported
    if ((accessControl == SocketAccessControlLocalhost &&
            addressType() == SocketAddressTypeIPv4 &&
            !supportsIPv4SocketsOnLocalhost()) ||
        (accessControl == SocketAccessControlPort &&
            addressType() == SocketAddressTypeIPv4 &&
            !supportsIPv4SocketsWithSpecifiedAddress()) ||
        (accessControl == SocketAccessControlLocalhost &&
            addressType() == SocketAddressTypeIPv6 &&
            !supportsIPv6SocketsOnLocalhost()) ||
        (accessControl == SocketAccessControlPort &&
            addressType() == SocketAddressTypeIPv6 &&
            !supportsIPv6SocketsWithSpecifiedAddress())) {
        warning() << "You requested an address type/access control combination "
                "not supported by this channel";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_IMPLEMENTED,
                QLatin1String("The requested address type/access control "
                              "combination is not supported"),
                IncomingStreamTubeChannelPtr(this));
    }

    // Perform the actual call
    PendingVariant *pv = new PendingVariant(
            interface<Client::ChannelTypeStreamTubeInterface>()->Accept(
                    addressType(),
                    accessControl,
                    QDBusVariant(controlParameter)),
            IncomingStreamTubeChannelPtr(this));

    PendingStreamTubeConnection *op = new PendingStreamTubeConnection(pv, addressType(),
            false, 0, IncomingStreamTubeChannelPtr(this));
    return op;
}
示例#5
0
	void AccessMap::enableAccessControl(int sec) {return setAccessControl(false, false, sec);}
示例#6
0
	void AccessMap::disableAccessControl(int sec) {return setAccessControl(false, true, sec);}
示例#7
0
	void AccessMap::disableProcedureOnly(int sec) {return setAccessControl(true, false, sec);}
示例#8
0
	void AccessMap::enableProcedureOnly(int sec) {return setAccessControl(true, true, sec);}