📄 qtsslsocket.cpp
字号:
*pBuffer++ = 'Z'; *pBuffer++ = '\0'; time_t lSecondsFromUCT; if (*pString == 'Z') { lSecondsFromUCT = 0; } else { if ((*pString != '+') && (pString[5] != '-')) return 0; lSecondsFromUCT = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60; lSecondsFromUCT += (pString[3] - '0') * 10 + (pString[4] - '0'); if (*pString == '-') lSecondsFromUCT = -lSecondsFromUCT; } tm lTime; lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0'); lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0'); lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0'); lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0'); lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1; lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0'); if (lTime.tm_year < 50) lTime.tm_year += 100; // RFC 2459 lTime.tm_wday = 0; lTime.tm_yday = 0; lTime.tm_isdst = 0; // No DST adjustment requested lResult = mktime(&lTime); if ((time_t)-1 != lResult) { if (0 != lTime.tm_isdst) lResult -= 3600; // mktime may adjust for DST (OS dependent) lResult += lSecondsFromUCT; } else { lResult = 0; } return lResult;}/*! Returns the local SSL certificate as a list of keys and values, separated by '/'. Call this function after the connection has been established and connectionVerificationDone() has been emitted to show the user the details of the certificate. This function is usually only called in the case where the SSL verification failed. If you call this function on an unconnected socket, or before QtSslSocket emits connectionVerificationDone(), or without providing QtSslSocket with a local certificate (see setPathToCertificate()), it will return an empty string. \sa peerCertificate()*/QString QtSslSocket::localCertificate() const{ // Get the local certificate. Usually this is only available in // server mode, but clients can in some cases also have // certificates. X509 *cert = d->ssl ? lib->SSL_get_certificate(d->ssl) : 0; if (!cert) return ""; char *inamestr = lib->X509_NAME_oneline(lib->X509_get_issuer_name(cert), 0, 0); QString inamelist = inamestr; lib->OPENSSL_free(inamestr); char *snamestr = lib->X509_NAME_oneline(lib->X509_get_subject_name(cert), 0, 0); QString snamelist = snamestr; lib->OPENSSL_free(snamestr); ASN1_TIME *nbef = X509_get_notBefore(cert); ASN1_TIME *naft = X509_get_notAfter(cert); QDateTime bef; bef.setTime_t(getTimeFromASN1(nbef)); QDateTime aft; aft.setTime_t(getTimeFromASN1(naft)); lib->X509_free(cert); return QString("%1/%2/notValidBefore=%3/notValidAfter=%4/version=%5/serial=%6") .arg(inamelist).arg(snamelist).arg(bef.toString(Qt::ISODate)) .arg(aft.toString(Qt::ISODate)) .arg(lib->X509_get_version(cert)) .arg(lib->ASN1_INTEGER_get(lib->X509_get_serialNumber(cert)));}/*! Returns the peer SSL certificate as a list of keys and values, separated by '/'. Call this function after the connection has been established and connectionVerificationDone() has been emitted to show the user the details of the peer certificate. This function is usually only called in the case where the SSL verification failed. If you call this function on an unconnected socket, or before QtSslSocket emits connectionVerificationDone(), it will return an empty string. \sa localCertificate()*/QString QtSslSocket::peerCertificate() const{ // Get the local certificate. Usually this is only available in // server mode, but clients can in some cases also have // certificates. X509 *cert = d->ssl ? lib->SSL_get_peer_certificate(d->ssl) : 0; if (!cert) return ""; char *inamestr = lib->X509_NAME_oneline(lib->X509_get_issuer_name(cert), 0, 0); QString inamelist = inamestr; lib->OPENSSL_free(inamestr); char *snamestr = lib->X509_NAME_oneline(lib->X509_get_subject_name(cert), 0, 0); QString snamelist = snamestr; lib->OPENSSL_free(snamestr); ASN1_TIME *nbef = X509_get_notBefore(cert); ASN1_TIME *naft = X509_get_notAfter(cert); QDateTime bef; bef.setTime_t(getTimeFromASN1(nbef)); QDateTime aft; aft.setTime_t(getTimeFromASN1(naft)); lib->X509_free(cert); return QString("%1/%2/notValidBefore=%3/notValidAfter=%4/version=%5/serial=%6") .arg(inamelist).arg(snamelist).arg(bef.toString(Qt::ISODate)) .arg(aft.toString(Qt::ISODate)) .arg(lib->X509_get_version(cert)) .arg(lib->ASN1_INTEGER_get(lib->X509_get_serialNumber(cert)));}/*! \reimp*/qint64 QtSslSocket::bytesAvailable() const{ return d->readBuffer.size();}/*! \reimp*/qint64 QtSslSocket::bytesToWrite() const{ return d->writeBuffer.size();}/*! \reimp*/bool QtSslSocket::canReadLine() const{ return d->readBuffer.canReadLine();}/*! \reimp*/void QtSslSocket::close(){ d->socket->abort(); QTcpSocket::close();}/*! \reimp Returns true; QtSslSocket is a sequential device.*/bool QtSslSocket::isSequential() const{ return true;}/*! \reimp*/bool QtSslSocket::waitForReadyRead(int msecs){ QTime stopWatch; stopWatch.start(); d->readyReadEmitted = false; do { if (!d->writeBuffer.isEmpty()) writeToSocket(); if (!d->socket->waitForReadyRead(qMax(0, msecs - stopWatch.elapsed()))) return false; } while (!d->readyReadEmitted); return true;}/*! \reimp*/bool QtSslSocket::waitForBytesWritten(int msecs){ if (!d->writeBuffer.isEmpty()) writeToSocket(); return d->socket->waitForBytesWritten(msecs);}/*! Returns a pointer to the socket holding the actualy SSL connection. This is different from QtSslSocket, which only acts like a wrapper. Call this function if you need to access the actual connected socket.*/QTcpSocket *QtSslSocket::socket() const{ return d->socket;}/*! Sets or replaces QtSslSocket's internal socket with \a socket. \a socket must be in ConnectedState; otherwise this function does nothing. After calling setSocket(), you can call sslConnect() to initiate a client-side handshake, or sslAccept() to initiate a server-side handshake. QtSslSocket disconnects all \a socket's existing signal connections as part of the handover, but does not take ownership of the object. This functionality is useful if you need to enable SSL on an existing, unencrypted socket. For example, certain network protocols like IMAP4, POP3 and SMTP allow you to use a plain text connection initially, and then convert to an encrypted connection later by issuing a certain command (e.g., "STARTTLS"). Example: \code void NetworkProtocol::readyReadSlot() { // Convert to an SSL connection. if (socket->canReadLine() && socket->readLine() == "STARTTLS\r\n") { QtSslSocket *sslSocket = new QtSslSocket(QtSslSocket::Client, this); sslSocket->setSocket(socket); socket = sslSocket; connectSignals(socket); } } \endcode \sa socket()*/void QtSslSocket::setSocket(QTcpSocket *socket){ if (socket->state() != ConnectedState) { qWarning("QtSslSocket::setSocket: QtSslSocket::setSocket() was called with a " "socket that is not in ConnectedState."); return; } socket->flush(); if (d->socket) delete d->socket; d->socket = socket; d->initializeConnection(d->socket); setOpenMode(socket->openMode()); initSsl();}/*! Initiates the SSL handshake for client-side sockets (Client). This function is useful for when QtSslSocket is initialized using setSocketDescriptor(). After calling sslConnect(), QtSslSocket will eventually emit connectionVerificationDone(). If you connect to a peer by calling connectToHost(), you do not need to call this function as QtSslSocket will do so for you. \sa sslAccept()*/bool QtSslSocket::sslConnect(){ return sslAcceptOrConnect(false);}/*! Initiates the SSL handshake for server-side sockets (Server). This function is useful for when QtSslSocket is initialized using setSocketDescriptor(). After calling sslAccept(), QtSslSocket will eventually emit connectionVerificationDone(). \sa sslConnect()*/bool QtSslSocket::sslAccept(){ open(QAbstractSocket::ReadWrite); return sslAcceptOrConnect(true);}/*! Initiates a connection to the host \a hostName on port \a port, using the open mode \a openMode. After QtSslSocket emits connected(), the SSL handshake will start automatically, and eventually QtSslSocket will emit connectionVerificationDone() to signal that the handshake has completed. \i {It is essential that the connection is not used before the handshake has completed.} Note: This function contains the implementation of connectToHost(). It is implemented as a slot to achieve polymorphic behavior (as QTcpSocket::connectToHost() is not virtual). Reimplement this function to alter the behavior of connectToHost() polymorphically. \sa disconnectFromHostImplementation()*/void QtSslSocket::connectToHostImplementation(const QString &hostName, quint16 port, OpenMode openMode){#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::connectToHostImplementation(" << hostName << "," << port << "," << openMode << ")";#endif if (state() != UnconnectedState) { qWarning("QtSslSocket::connectToHost() called when not in UnconnectedState"); return; } open(openMode); d->socket->connectToHost(hostName, port, openMode);#if QT_VERSION >= 0x040100 setSocketState(ConnectingState);#endif}/*! This function contains the implementation of disconnectFromHost(). It is implemented as a slot to achieve polymorphic behavior (as QTcpSocket::disconnectFromHost() is not virtual). Reimplement this function to alter the behavior of disconnectFromHost() polymorphically. \sa connectToHostImplementation()*/void QtSslSocket::disconnectFromHostImplementation(){#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::disconnectFromHostImplementation()";#endif d->socket->disconnectFromHost(); setSocketState(d->socket->state()); emit stateChanged(d->socket->state());}/*! \reimp*/qint64 QtSslSocket::readData(char *data, qint64 maxSize){ if (!d->connectionSecured) return qint64(-1); qint64 bytesToRead = qMin(qint64(d->readBuffer.size()), maxSize); qint64 readSoFar = 0; while (readSoFar < bytesToRead) { char *ptr = d->readBuffer.readPointer(); int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar), d->readBuffer.nextDataBlockSize()); memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); readSoFar += bytesToReadFromThisBlock; d->readBuffer.free(bytesToReadFromThisBlock); } return readSoFar;}/*! \reimp*/qint64 QtSslSocket::readLineData(char *data, qint64 maxSize){ return qint64(d->readBuffer.readLine(data, int(maxSize)));}/*! \reimp*/qint64 QtSslSocket::writeData(const char *data, qint64 size){ if (!d->calledWriteToSocket) { d->calledWriteToSocket = true; QMetaObject::invokeMethod(this, "writeToSocket", Qt::QueuedConnection); } char *ptr = d->writeBuffer.reserve(size); if (size == 1) *ptr = *data; else memcpy(ptr, data, size); return size;}/*! \internal*/bool QtSslSocket::initSsl(){ // Precondition: certificate for servers if (d->mode == Server) { if (d->cert.isEmpty() && d->certDir.isEmpty()) { setErrorString(tr("QtSslSocket: Certificate required in server mode")); emit error(UnknownSocketError); return false; } else if (d->key.isEmpty()) { setErrorString(tr("Private key required in server mode")); emit error(UnknownSocketError); return false; } } // Create and initialize SSL context. Accept SSLv2, SSLv3 and // TLSv1. d->ctx = lib->SSL_CTX_new(d->mode == Server ? lib->SSLv23_server_method() : lib->SSLv23_client_method()); if (!d->ctx) { setErrorString(tr("Error creating SSL context, %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } // Enable all bug workarounds. lib->SSL_CTX_set_options(d->ctx, SSL_OP_ALL); // Initialize ciphers if (!d->ciph.isEmpty()) { if (!lib->SSL_CTX_set_cipher_list(d->ctx, d->ciph.toLatin1().constData())) { setErrorString(tr("Invalid or empty cipher list, %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } } if (d->mode == Server) { lib->SSL_CTX_set_default_verify_paths(d->ctx); // Load certificate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -