📄 tcpslavebase.cpp
字号:
/* * $Id: tcpslavebase.cpp,v 1.58.2.14 2003/05/14 16:30:23 staikos Exp $ * * Copyright (C) 2000 Alex Zepeda <jazepeda@pacbell.net> * Copyright (C) 2001 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/uio.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <unistd.h>#include <ksocks.h>#include <kdebug.h>#include <kssl.h>#include <ksslcertificate.h>#include <ksslcertificatecache.h>#include <ksslcertificatehome.h>#include <ksslcertdlg.h>#include <ksslpkcs12.h>#include <kmessagebox.h>#include <klocale.h>#include <dcopclient.h>#include <qcstring.h>#include <qdatastream.h>#include <kapp.h>#include "kio/tcpslavebase.h"using namespace KIO;class TCPSlaveBase::TcpSlaveBasePrivate{public: TcpSlaveBasePrivate() : militantSSL(false) {} ~TcpSlaveBasePrivate() {} KSSL *kssl; bool usingTLS; KSSLCertificateCache *cc; QString host; QString realHost; QString ip; DCOPClient *dcc; KSSLPKCS12 *pkcs; int status; int timeout; bool block; bool useSSLTunneling; bool needSSLHandShake; bool militantSSL;};TCPSlaveBase::TCPSlaveBase(unsigned short int default_port, const QCString &protocol, const QCString &pool_socket, const QCString &app_socket) :SlaveBase (protocol, pool_socket, app_socket), m_iSock(-1), m_iDefaultPort(default_port), 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 default_port, const QCString &protocol, const QCString &pool_socket, const QCString &app_socket, bool useSSL) :SlaveBase (protocol, pool_socket, app_socket), m_iSock(-1), m_bIsSSL(useSSL), m_iDefaultPort(default_port), 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 = -1; 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){ 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);}ssize_t TCPSlaveBase::Read(void *data, ssize_t len){ if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling ) { if ( d->needSSLHandShake ) (void) doSSLHandShake( true ); ssize_t size = d->kssl->read(data, len); return size; } return KSocks::self()->read(m_iSock, data, len);}ssize_t TCPSlaveBase::ReadLine(char *data, ssize_t len){ // let's not segfault! if (!data) return -1; *data = 0; // ugliness alert!! calling read() so many times can't be good... int clen = 0; char *buf = data; while (clen < len) { int rc; if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling ) { if ( d->needSSLHandShake ) (void) doSSLHandShake( true ); rc = d->kssl->read(buf, 1); } else rc = KSocks::self()->read(m_iSock, buf, 1); if (rc < 0) return -1; clen++; if (*buf++ == '\n') break; } *buf = 0; return clen;}unsigned short int TCPSlaveBase::GetPort(unsigned short int _port){ unsigned short int port = _port; if (_port <= 0) { struct servent *srv=getservbyname(m_sServiceName, "tcp"); if (srv) { port=ntohs(srv->s_port); } else port=m_iDefaultPort; } return port;} // 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 QCString &host, unsigned short int _port){ return ConnectToHost( host, _port, true );}bool TCPSlaveBase::ConnectToHost( const QString &host, unsigned int _port, bool sendError ){ unsigned short int port; KExtendedSocket ks; // - leaving SSL - warn before we even connect if (metaData("ssl_activate_warnings") == "TRUE" && metaData("ssl_was_in_use") == "TRUE" && !m_bIsSSL) { KSSLSettings kss; if (kss.warnOnLeave()) { int result = messageBox( WarningContinueCancel, 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."), i18n("Security information"), i18n("Continue Loading") ); if ( result == KMessageBox::Cancel ) return -1; } } d->status = -1; d->host = host; d->needSSLHandShake = m_bIsSSL; port = GetPort(_port); ks.setAddress(host, port); 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(); d->ip = sa->nodeName(); ks.release(); // KExtendedSocket no longer applicable if ( d->block != ks.blockingMode() ) ks.setBlockingMode( d->block ); m_iPort=port; 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 = fdopen(m_iSock, "w+")) == 0) { CloseDescriptor(); return false; } return true;}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; } else return false; } else return false;}void TCPSlaveBase::CleanSSL(){ if (d->cc) { delete d->cc; d->cc = NULL; } if (m_bIsSSL || d->usingTLS) { delete d->kssl; d->kssl = NULL; d->usingTLS = false; setMetaData("ssl_in_use", "FALSE"); } d->militantSSL = false;}bool TCPSlaveBase::AtEOF(){ return feof(fp);}int TCPSlaveBase::startTLS(){ if (d->usingTLS || d->useSSLTunneling || m_bIsSSL || !KSSL::doesSSLWork()) return false; d->kssl = new KSSL(false); if (!d->kssl->TLSInit()) { delete d->kssl; d->kssl = NULL; return -1; } if ( !d->realHost.isEmpty() ) { kdDebug(7029) << "Setting real hostname: " << d->realHost << endl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -