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 + -
显示快捷键?