⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tlssocket.cpp

📁 MIME解析的代码
💻 CPP
字号:
//// VMime library (http://www.vmime.org)// Copyright (C) 2002-2008 Vincent Richard <vincent@vincent-richard.net>//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License as// published by the Free Software Foundation; either version 2 of// the License, or (at your option) any later version.//// This program 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// General Public License for more details.//// You should have received a copy of the GNU General Public License along// with this program; if not, write to the Free Software Foundation, Inc.,// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//// Linking this library statically or dynamically with other modules is making// a combined work based on this library.  Thus, the terms and conditions of// the GNU General Public License cover the whole combination.//#include <gnutls/gnutls.h>#include <gnutls/x509.h>#include "vmime/net/tls/TLSSocket.hpp"#include "vmime/net/tls/TLSSession.hpp"#include "vmime/platform.hpp"#include "vmime/security/cert/X509Certificate.hpp"namespace vmime {namespace net {namespace tls {TLSSocket::TLSSocket(ref <TLSSession> session, ref <socket> sok)	: m_session(session), m_wrapped(sok), m_connected(false),	  m_handshaking(false), m_ex(NULL){	gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);	gnutls_transport_set_push_function(*m_session->m_gnutlsSession, gnutlsPushFunc);	gnutls_transport_set_pull_function(*m_session->m_gnutlsSession, gnutlsPullFunc);}TLSSocket::~TLSSocket(){	try	{		disconnect();	}	catch (...)	{		// Don't throw exception in destructor	}}void TLSSocket::connect(const string& address, const port_t port){	m_wrapped->connect(address, port);	handshake(NULL);	m_connected = true;}void TLSSocket::disconnect(){	if (m_connected)	{		gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR);		m_wrapped->disconnect();		m_connected = false;	}}bool TLSSocket::isConnected() const{	return m_wrapped->isConnected() && m_connected;}void TLSSocket::receive(string& buffer){	const int size = receiveRaw(m_buffer, sizeof(m_buffer));	buffer = vmime::string(m_buffer, size);}void TLSSocket::send(const string& buffer){	sendRaw(buffer.data(), buffer.length());}int TLSSocket::receiveRaw(char* buffer, const int count){	const ssize_t ret = gnutls_record_recv		(*m_session->m_gnutlsSession,		 buffer, static_cast <size_t>(count));	if (m_ex)		internalThrow();	if (ret < 0)	{		if (ret == GNUTLS_E_AGAIN)			return 0;		TLSSession::throwTLSException("gnutls_record_recv", ret);	}	return static_cast <int>(ret);}void TLSSocket::sendRaw(const char* buffer, const int count){	gnutls_record_send		(*m_session->m_gnutlsSession,		 buffer, static_cast <size_t>(count));	if (m_ex)		internalThrow();}void TLSSocket::handshake(ref <timeoutHandler> toHandler){	if (toHandler)		toHandler->resetTimeOut();	// Start handshaking process	m_handshaking = true;	m_toHandler = toHandler;	try	{		while (true)		{			const int ret = gnutls_handshake(*m_session->m_gnutlsSession);			if (m_ex)				internalThrow();			if (ret < 0)			{				if (ret == GNUTLS_E_AGAIN ||				    ret == GNUTLS_E_INTERRUPTED)				{					// Non-fatal error					platform::getHandler()->wait();				}				else				{					TLSSession::throwTLSException("gnutls_handshake", ret);				}			}			else			{				// Successful handshake				break;			}		}	}	catch (...)	{		m_handshaking = false;		m_toHandler = NULL;		throw;	}	m_handshaking = false;	m_toHandler = NULL;	// Verify server's certificate(s)	ref <security::cert::certificateChain> certs = getPeerCertificates();	if (certs == NULL)		throw exceptions::tls_exception("No peer certificate.");	m_session->getCertificateVerifier()->verify(certs);	m_connected = true;}ssize_t TLSSocket::gnutlsPushFunc	(gnutls_transport_ptr trspt, const void* data, size_t len){	TLSSocket* sok = reinterpret_cast <TLSSocket*>(trspt);	try	{		sok->m_wrapped->sendRaw			(reinterpret_cast <const char*>(data), static_cast <int>(len));	}	catch (exception& e)	{		// Workaround for bad behaviour when throwing C++ exceptions		// from C functions (GNU TLS)		sok->m_ex = e.clone();		return -1;	}	return len;}ssize_t TLSSocket::gnutlsPullFunc	(gnutls_transport_ptr trspt, void* data, size_t len){	TLSSocket* sok = reinterpret_cast <TLSSocket*>(trspt);	try	{		// Workaround for cross-platform asynchronous handshaking:		// gnutls_handshake() only returns GNUTLS_E_AGAIN if recv()		// returns -1 and errno is set to EGAIN...		if (sok->m_handshaking)		{			while (true)			{				const ssize_t ret = static_cast <ssize_t>					(sok->m_wrapped->receiveRaw						(reinterpret_cast <char*>(data),						 static_cast <int>(len)));				if (ret == 0)				{					// No data available yet					platform::getHandler()->wait();				}				else				{					return ret;				}				// Check whether the time-out delay is elapsed				if (sok->m_toHandler && sok->m_toHandler->isTimeOut())				{					if (!sok->m_toHandler->handleTimeOut())						throw exceptions::operation_timed_out();					sok->m_toHandler->resetTimeOut();				}			}		}		else		{			const ssize_t n = static_cast <ssize_t>				(sok->m_wrapped->receiveRaw					(reinterpret_cast <char*>(data),					 static_cast <int>(len)));			if (n == 0)				return GNUTLS_E_AGAIN;  // This seems like a hack, really...			return n;		}	}	catch (exception& e)	{		// Workaround for bad behaviour when throwing C++ exceptions		// from C functions (GNU TLS)		sok->m_ex = e.clone();		return -1;	}}ref <security::cert::certificateChain> TLSSocket::getPeerCertificates() const{	unsigned int certCount = 0;	const gnutls_datum* rawData = gnutls_certificate_get_peers		(*m_session->m_gnutlsSession, &certCount);	if (rawData == NULL)		return NULL;	// Try X.509	gnutls_x509_crt* x509Certs = new gnutls_x509_crt[certCount];	unsigned int count = certCount;	int res = gnutls_x509_crt_list_import		(x509Certs, &count, rawData, GNUTLS_X509_FMT_PEM, 0);	if (res <= 0)	{		count = certCount;		res = gnutls_x509_crt_list_import			(x509Certs, &count, rawData, GNUTLS_X509_FMT_DER, 0);	}	if (res >= 1)	{		std::vector <ref <security::cert::certificate> > certs;		bool error = false;		count = static_cast <unsigned int>(res);		for (unsigned int i = 0 ; i < count ; ++i)		{			size_t dataSize = 0;			gnutls_x509_crt_export(x509Certs[i],				GNUTLS_X509_FMT_DER, NULL, &dataSize);			std::vector <byte_t> data(dataSize);			gnutls_x509_crt_export(x509Certs[i],				GNUTLS_X509_FMT_DER, &data[0], &dataSize);			ref <security::cert::X509Certificate> cert =				security::cert::X509Certificate::import(&data[0], dataSize);			if (cert != NULL)				certs.push_back(cert);			else				error = true;			gnutls_x509_crt_deinit(x509Certs[i]);		}		delete [] x509Certs;		if (error)			return NULL;		return vmime::create <security::cert::certificateChain>(certs);	}	delete [] x509Certs;	return NULL;}// Following is a workaround for C++ exceptions to pass correctly between// C and C++ calls.//// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions// thrown by the socket can not be caught.#ifndef VMIME_BUILDING_DOCclass TLSSocket_DeleteExWrapper : public object{public:	TLSSocket_DeleteExWrapper(exception* ex) : m_ex(ex) { }	~TLSSocket_DeleteExWrapper() { delete m_ex; }private:	exception* m_ex;};#endif // VMIME_BUILDING_DOCvoid TLSSocket::internalThrow(){	static std::vector <ref <TLSSocket_DeleteExWrapper> > exToDelete;	if (m_ex)	{		// Reset the current exception pointer to prevent the same		// exception from being thrown again later		exception* ex = m_ex;		m_ex = NULL;		// To avoid memory leaks		exToDelete.push_back(vmime::create <TLSSocket_DeleteExWrapper>(ex));		throw *ex;	}}} // tls} // net} // vmime

⌨️ 快捷键说明

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