tcpslavebase.cpp

来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· C++ 代码 · 共 1,342 行 · 第 1/3 页

CPP
1,342
字号
/* * $Id: tcpslavebase.cpp 473519 2005-10-23 22:53:30Z staikos $ * * Copyright (C) 2000 Alex Zepeda <zipzippy@sonic.net * Copyright (C) 2001-2003 George Staikos <staikos@kde.org> * Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org> * * This file is part of the KDE project * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB.  If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/types.h>#include <sys/uio.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <time.h>#include <netdb.h>#include <unistd.h>#include <errno.h>#include <ksocks.h>#include <kdebug.h>#include <ksslall.h>#include <ksslcertdlg.h>#include <kmessagebox.h>#ifndef Q_WS_WIN //temporary#include <kresolver.h>#endif#include <klocale.h>#include <dcopclient.h>#include <qcstring.h>#include <qdatastream.h>#include <kapplication.h>#include <kprotocolmanager.h>#include <kde_file.h>#include "kio/tcpslavebase.h"using namespace KIO;class TCPSlaveBase::TcpSlaveBasePrivate{public:  TcpSlaveBasePrivate() : rblockSz(256), militantSSL(false), userAborted(false) {}  ~TcpSlaveBasePrivate() {}  KSSL *kssl;  bool usingTLS;  KSSLCertificateCache *cc;  QString host;  QString realHost;  QString ip;  DCOPClient *dcc;  KSSLPKCS12 *pkcs;  int status;  int timeout;  int rblockSz;      // Size for reading blocks in readLine()  bool block;  bool useSSLTunneling;  bool needSSLHandShake;  bool militantSSL;              // If true, we just drop a connection silently                                 // if SSL certificate check fails in any way.  bool userAborted;  MetaData savedMetaData;};TCPSlaveBase::TCPSlaveBase(unsigned short int defaultPort,                           const QCString &protocol,                           const QCString &poolSocket,                           const QCString &appSocket)             :SlaveBase (protocol, poolSocket, appSocket),              m_iSock(-1),              m_iDefaultPort(defaultPort),              m_sServiceName(protocol),              fp(0){    // We have to have two constructors, so don't add anything    // else in here. Put it in doConstructorStuff() instead.    doConstructorStuff();    m_bIsSSL = false;}TCPSlaveBase::TCPSlaveBase(unsigned short int defaultPort,                           const QCString &protocol,                           const QCString &poolSocket,                           const QCString &appSocket,                           bool useSSL)             :SlaveBase (protocol, poolSocket, appSocket),              m_iSock(-1),              m_bIsSSL(useSSL),              m_iDefaultPort(defaultPort),              m_sServiceName(protocol),              fp(0){    doConstructorStuff();    if (useSSL)        m_bIsSSL = initializeSSL();}// The constructor procedures go here now.void TCPSlaveBase::doConstructorStuff(){    d = new TcpSlaveBasePrivate;    d->kssl = 0L;    d->ip = "";    d->cc = 0L;    d->usingTLS = false;    d->dcc = 0L;    d->pkcs = 0L;    d->status = -1;    d->timeout = KProtocolManager::connectTimeout();    d->block = false;    d->useSSLTunneling = false;}TCPSlaveBase::~TCPSlaveBase(){    cleanSSL();    if (d->usingTLS) delete d->kssl;    if (d->dcc) delete d->dcc;    if (d->pkcs) delete d->pkcs;    delete d;}ssize_t TCPSlaveBase::write(const void *data, ssize_t len){#ifdef Q_OS_UNIX    if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )    {        if ( d->needSSLHandShake )            (void) doSSLHandShake( true );        return d->kssl->write(data, len);    }    return KSocks::self()->write(m_iSock, data, len);#else    return 0;#endif}ssize_t TCPSlaveBase::read(void *data, ssize_t len){#ifdef Q_OS_UNIX    if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )    {        if ( d->needSSLHandShake )            (void) doSSLHandShake( true );        return d->kssl->read(data, len);    }    return KSocks::self()->read(m_iSock, data, len);#else    return 0;#endif}void TCPSlaveBase::setBlockSize(int sz){  if (sz <= 0)    sz = 1;  d->rblockSz = sz;}ssize_t TCPSlaveBase::readLine(char *data, ssize_t len){// Optimization://           It's small, but it probably results in a gain on very high//   speed connections.  I moved 3 if statements out of the while loop//   so that the while loop is as small as possible.  (GS)  // let's not segfault!  if (!data)    return -1;  char tmpbuf[1024];   // 1kb temporary buffer for peeking  *data = 0;  ssize_t clen = 0;  char *buf = data;  int rc = 0;if ((m_bIsSSL || d->usingTLS) && !d->useSSLTunneling) {       // SSL CASE  if ( d->needSSLHandShake )    (void) doSSLHandShake( true );  while (clen < len-1) {    rc = d->kssl->pending();    if (rc > 0) {   // Read a chunk      int bytes = rc;      if (bytes > d->rblockSz)         bytes = d->rblockSz;      rc = d->kssl->peek(tmpbuf, bytes);      if (rc <= 0) {        // FIXME: this doesn't cover rc == 0 case        return -1;      }      bytes = rc;   // in case it contains no \n      for (int i = 0; i < rc; i++) {        if (tmpbuf[i] == '\n') {          bytes = i+1;          break;        }      }      if (bytes+clen >= len)   // don't read too much!        bytes = len - clen - 1;      rc = d->kssl->read(buf, bytes);      if (rc > 0) {        clen += rc;        buf += (rc-1);        if (*buf++ == '\n')          break;      } else {        // FIXME: different case if rc == 0;        return -1;      }    } else {        // Read a byte      rc = d->kssl->read(buf, 1);      if (rc <= 0) {        return -1;        // hm rc = 0 then        // SSL_read says to call SSL_get_error to see if        // this was an error.    FIXME      } else {        clen++;        if (*buf++ == '\n')          break;      }    }  }} else {                                                      // NON SSL CASE  while (clen < len-1) {#ifdef Q_OS_UNIX    rc = KSocks::self()->read(m_iSock, buf, 1);#else    rc = 0;#endif    if (rc <= 0) {      // FIXME: this doesn't cover rc == 0 case      return -1;    } else {      clen++;      if (*buf++ == '\n')        break;    }  }}  // Both cases fall through to here  *buf = 0;return clen;}unsigned short int TCPSlaveBase::port(unsigned short int _p){    unsigned short int p = _p;    if (_p <= 0)    {        p = m_iDefaultPort;    }    return p;}// This function is simply a wrapper to establish the connection// to the server.  It's a bit more complicated than ::connect// because we first have to check to see if the user specified// a port, and if so use it, otherwise we check to see if there// is a port specified in /etc/services, and if so use that// otherwise as a last resort use the supplied default port.bool TCPSlaveBase::connectToHost( const QString &host,                                  unsigned int _port,                                  bool sendError ){#ifdef Q_OS_UNIX    unsigned short int p;    KExtendedSocket ks;    d->userAborted = false;    //  - leaving SSL - warn before we even connect    if (metaData("main_frame_request") == "TRUE" &&         metaData("ssl_activate_warnings") == "TRUE" &&               metaData("ssl_was_in_use") == "TRUE" &&        !m_bIsSSL) {       KSSLSettings kss;       if (kss.warnOnLeave()) {          int result = messageBox( i18n("You are about to leave secure "                                        "mode. Transmissions will no "                                        "longer be encrypted.\nThis "                                        "means that a third party could "                                        "observe your data in transit."),                                   WarningContinueCancel,                                   i18n("Security Information"),                                   i18n("C&ontinue Loading"), QString::null,                                   "WarnOnLeaveSSLMode" );           // Move this setting into KSSL instead          KConfig *config = new KConfig("kioslaverc");          config->setGroup("Notification Messages");          if (!config->readBoolEntry("WarnOnLeaveSSLMode", true)) {              config->deleteEntry("WarnOnLeaveSSLMode");              config->sync();              kss.setWarnOnLeave(false);              kss.save();          }          delete config;          if ( result == KMessageBox::Cancel ) {             d->userAborted = true;             return false;          }       }    }    d->status = -1;    d->host = host;    d->needSSLHandShake = m_bIsSSL;    p = port(_port);    ks.setAddress(host, p);    if ( d->timeout > -1 )        ks.setTimeout( d->timeout );    if (ks.connect() < 0)    {        d->status = ks.status();        if ( sendError )        {            if (d->status == IO_LookupError)                error( ERR_UNKNOWN_HOST, host);            else if ( d->status != -1 )                error( ERR_COULD_NOT_CONNECT, host);        }        return false;    }    m_iSock = ks.fd();    // store the IP for later    const KSocketAddress *sa = ks.peerAddress();    if (sa)      d->ip = sa->nodeName();    else      d->ip = "";    ks.release(); // KExtendedSocket no longer applicable    if ( d->block != ks.blockingMode() )        ks.setBlockingMode( d->block );    m_iPort=p;    if (m_bIsSSL && !d->useSSLTunneling) {        if ( !doSSLHandShake( sendError ) )            return false;    }    else        setMetaData("ssl_in_use", "FALSE");    // Since we want to use stdio on the socket,    // we must fdopen it to get a file pointer,    // if it fails, close everything up    if ((fp = KDE_fdopen(m_iSock, "w+")) == 0) {        closeDescriptor();        return false;    }    return true;#else //!Q_OS_UNIX    return false;#endif //Q_OS_UNIX}void TCPSlaveBase::closeDescriptor(){    stopTLS();    if (fp) {        fclose(fp);        fp=0;        m_iSock=-1;        if (m_bIsSSL)            d->kssl->close();    }    if (m_iSock != -1) {        close(m_iSock);        m_iSock=-1;    }    d->ip = "";    d->host = "";}bool TCPSlaveBase::initializeSSL(){    if (m_bIsSSL) {        if (KSSL::doesSSLWork()) {            d->kssl = new KSSL;            return true;        }    }return false;}void TCPSlaveBase::cleanSSL(){    delete d->cc;    if (m_bIsSSL) {        delete d->kssl;        d->kssl = 0;    }    d->militantSSL = false;}bool TCPSlaveBase::atEnd(){    return feof(fp);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?