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

📄 securesocketimpl.cpp

📁 很好用的网络封装库,不熟悉网络编程的人也可以使用。使用风格良好的标准c++编写。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// SecureSocketImpl.cpp
//
// $Id: //poco/1.3/NetSSL_OpenSSL/src/SecureSocketImpl.cpp#4 $
//
// Library: NetSSL_OpenSSL
// Package: SSLSockets
// Module:  SecureSocketImpl
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//


#include "Poco/Net/SecureSocketImpl.h"
#include "Poco/Net/SSLException.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/Utility.h"
#include "Poco/Net/SecureStreamSocketImpl.h"
#include "Poco/Net/StreamSocketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/DNS.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/String.h"
#include "Poco/RegularExpression.h"
#include <openssl/x509v3.h>
#include <openssl/err.h>


using Poco::IOException;
using Poco::TimeoutException;
using Poco::InvalidArgumentException;
using Poco::NumberFormatter;
using Poco::Timespan;


// workaround for C++-incompatible macro
#define POCO_BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(void*)((n)?"a":NULL))



namespace Poco {
namespace Net {


SecureSocketImpl::SecureSocketImpl():_pBIO(0), _pSSL(0)
{
}


SecureSocketImpl::SecureSocketImpl(SSL *pSSL): _pSSL(pSSL)
{
	poco_check_ptr (_pSSL);

	_pBIO = SSL_get_rbio(_pSSL);
	poco_check_ptr (_pBIO);
	int tmpSocket = 0;
	BIO_get_fd(_pBIO, &tmpSocket);
	setSockfd(tmpSocket);

}


SecureSocketImpl::~SecureSocketImpl()
{
	close();
}

	
SocketImpl* SecureSocketImpl::acceptConnection(SocketAddress& clientAddr)
{
	poco_assert (sockfd() != POCO_INVALID_SOCKET);
	poco_check_ptr (_pBIO);

	BIO* pClient = 0;
	int rc = 0;

	do
	{
		rc = BIO_do_accept(_pBIO);
	}
	while (rc <= 0 && _socket.lastError() == POCO_EINTR);

	if (rc > 0)
	{
		pClient = BIO_pop(_pBIO);
		poco_check_ptr (pClient);

		SSL* pSSL = SSL_new(SSLManager::instance().defaultServerContext()->sslContext());
		if (pSSL)
		{
			SSL_set_accept_state(pSSL);
			SSL_set_bio(pSSL, pClient, pClient);
			int err = SSL_accept(pSSL);
			
			if (err > 0)
			{
				SecureStreamSocketImpl* pSI = new SecureStreamSocketImpl(pSSL);
				clientAddr = pSI->peerAddress();
				std::string clientName = clientAddr.host().toString();

				if (X509_V_OK != postConnectionCheck(true, pSSL, clientName))
				{
					delete pSI;
					pSI = 0;
					SSL_shutdown(pSSL);
					SSL_free(pSSL);
					pClient = 0;
					SocketImpl::error("postConnectionCheck failed"); // will throw
				}

				return pSI;
			}
			else
			{
				std::string errMsg = Utility::convertSSLError(pSSL, err);
				SSL_shutdown(pSSL);
				SSL_free(pSSL);
				SocketImpl::error(std::string("failed to acceptConnection: ") + errMsg);
			}
		}
		else
		{
			BIO_free(pClient);
		}
		
	}
	SocketImpl::error(); // will throw
	return 0;
}


void SecureSocketImpl::connect(const SocketAddress& address)
{
	if (sockfd() == POCO_INVALID_SOCKET)
	{
		if (!_pBIO)
			_pBIO = BIO_new(BIO_s_connect());
	}

	int rc = 0;
	do
	{
		BIO_set_conn_hostname(_pBIO, address.host().toString().c_str());
		int tmp = address.port();
		BIO_set_conn_int_port(_pBIO, &tmp);
		rc = BIO_do_connect(_pBIO); // returns 1 in case of ok!
	}
	while (rc != 1 && _socket.lastError() == POCO_EINTR);

	if (rc != 1) SocketImpl::error(address.toString());

	establishTunnel();
	connectSSL(address);
	poco_check_ptr (_pSSL);
}


void SecureSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
{
	poco_assert (sockfd() == POCO_INVALID_SOCKET);
	poco_assert (_pSSL == 0);
	poco_assert (_pBIO == 0);

	_pBIO = BIO_new(BIO_s_connect());
	POCO_BIO_set_nbio_accept(_pBIO, 1); // set nonblocking
	
	try
	{
		BIO_set_conn_hostname(_pBIO, address.host().toString().c_str());
		int tmp = address.port();
		BIO_set_conn_int_port(_pBIO, &tmp);
		int rc = BIO_do_connect(_pBIO); // returns 1 in case of ok!

		if (rc != 1)
		{
			if (_socket.lastError() != POCO_EINPROGRESS && _socket.lastError() != POCO_EWOULDBLOCK)
				SocketImpl::error(address.toString());
			if (!_socket.poll(timeout, SocketImpl::SELECT_READ | SocketImpl::SELECT_WRITE))
				throw Poco::TimeoutException("connect timed out", address.toString());
			int err = _socket.socketError();
			if (err != 0) SocketImpl::error(err);
		}

		establishTunnel();
		connectSSL(address);
		poco_check_ptr (_pSSL);
	}
	catch (Poco::Exception&)
	{
		POCO_BIO_set_nbio_accept(_pBIO, 0);
		throw;
	}
	POCO_BIO_set_nbio_accept(_pBIO, 0);
}


void SecureSocketImpl::connectNB(const SocketAddress& address)
{
	if (sockfd() == POCO_INVALID_SOCKET)
	{
		if(!_pBIO)
			_pBIO = BIO_new(BIO_s_connect());
	}

	POCO_BIO_set_nbio_accept(_pBIO, 1); //setnonBlocking
	BIO_set_conn_hostname(_pBIO, address.host().toString().c_str());
	int tmp = address.port();
	BIO_set_conn_int_port(_pBIO, &tmp);

	int rc = BIO_do_connect(_pBIO); // returns 1 in case of ok!

	if (rc != 1)
	{
		if (_socket.lastError() != POCO_EINPROGRESS && _socket.lastError() != POCO_EWOULDBLOCK)
			SocketImpl::error(address.toString());
	}
	else
	{
		establishTunnel();
		connectSSL(address);
		poco_check_ptr (_pSSL);
	}
}


void SecureSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
{
	_socket.bind(address, reuseAddress);
}

	
void SecureSocketImpl::listen(int backlog)
{
	_socket.listen(backlog);
	_pBIO = BIO_new (BIO_s_accept());
	BIO_set_fd(_pBIO, (int)sockfd(), BIO_CLOSE);
}


void SecureSocketImpl::close()
{
	if (_pSSL)
	{
		if (SSL_get_shutdown(_pSSL) & SSL_RECEIVED_SHUTDOWN)
		{
			SSL_shutdown(_pSSL);
		}
		else
		{
			SSL_clear(_pSSL);
		}
		SSL_free(_pSSL); // frees _pBIO
		_pSSL = 0;
		_pBIO = 0;
	}

	if (_pBIO)
	{
		BIO_free_all(_pBIO); //free all, even BIOs for pending connections
		_pBIO = 0;
	}
	invalidate(); // the socket is already invalid, although the fd still contains a meaningful value, correct that
}


int SecureSocketImpl::sendBytes(const void* buffer, int length, int flags)
{
	poco_assert (sockfd() != POCO_INVALID_SOCKET);
	poco_check_ptr (_pSSL);

	int rc;
	do
	{
		rc = SSL_write(_pSSL, buffer, length);
		if (rc < 0)
		{

⌨️ 快捷键说明

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