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

📄 sslsocket.cpp

📁 一个简单实用的开源C++消息中间件SAFMQ - [软件开发] - [开源 消息中间件 SAFMQ ] 2006-11-23 在很多网络应用中
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 Copyright 2005 Matthew J. Battey

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software distributed
	under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
	CONDITIONS OF ANY KIND, either express or implied. See the License for the
	specific language governing permissions and limitations under the License.




This software implements a platform independent C++ interface to TCP/IP socket
communications.
*/
#include "sslsocket.h"

#ifdef _WIN32
	#define EWOULDBLOCK             WSAEWOULDBLOCK
	#define EINPROGRESS             WSAEINPROGRESS
	#define EALREADY                WSAEALREADY
	#define ENOTSOCK                WSAENOTSOCK
	#define EDESTADDRREQ            WSAEDESTADDRREQ
	#define EMSGSIZE                WSAEMSGSIZE
	#define EPROTOTYPE              WSAEPROTOTYPE
	#define ENOPROTOOPT             WSAENOPROTOOPT
	#define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
	#define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
	#define EOPNOTSUPP              WSAEOPNOTSUPP
	#define EPFNOSUPPORT            WSAEPFNOSUPPORT
	#define EAFNOSUPPORT            WSAEAFNOSUPPORT
	#define EADDRINUSE              WSAEADDRINUSE
	#define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
	#define ENETDOWN                WSAENETDOWN
	#define ENETUNREACH             WSAENETUNREACH
	#define ENETRESET               WSAENETRESET
	#define ECONNABORTED            WSAECONNABORTED
	#define ECONNRESET              WSAECONNRESET
	#define ENOBUFS                 WSAENOBUFS
	#define EISCONN                 WSAEISCONN
	#define ENOTCONN                WSAENOTCONN
	#define ESHUTDOWN               WSAESHUTDOWN
	#define ETOOMANYREFS            WSAETOOMANYREFS
	#define ETIMEDOUT               WSAETIMEDOUT
	#define ECONNREFUSED            WSAECONNREFUSED
	#define ELOOP                   WSAELOOP
	#define EHOSTDOWN               WSAEHOSTDOWN
	#define EHOSTUNREACH            WSAEHOSTUNREACH
	#define EPROCLIM                WSAEPROCLIM
	#define EUSERS                  WSAEUSERS
	#define EDQUOT                  WSAEDQUOT
	#define ESTALE                  WSAESTALE
	#define EREMOTE                 WSAEREMOTE
	typedef int socklen_t;
	#define SOCERRNO				h_errno

	#ifdef min
		#undef min
		#define min _cpp_min
	#endif
	#ifdef max
		#undef max
		#define max _cpp_max
	#endif


#else
	#include <netdb.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <arpa/inet.h>
	#include <unistd.h>
	#include <sys/time.h>
	#include <fcntl.h>
	#define SOCERRNO				errno
#endif

#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

namespace tcpsocket {

struct _SSLInitializer {
	_SSLInitializer() {
		SSL_library_init();
		SSL_load_error_strings();
	}
};
static _SSLInitializer _initializer;

struct X509Data {
	X509Data() {
		certificate = NULL;
	}
	X509Data(const X509Data& cert) {
		certificate = cert.certificate;
	}
	X509Data(X509* cert) {
		certificate = cert;
	}
	X509* certificate;
};

struct SSLSocketData {
	SSLSocketData() {
		ctx = NULL;
		ssl = NULL;
	}

	SSL_CTX*	ctx;
	SSL*		ssl;
	int			mrc;
};


/**
Constructs an X509Certificate object from the
masked X509Data structrure.
@param certificate the source data
*/
X509Certificate::X509Certificate(const X509Data* certificate)
{
	this->certificate = new X509Data(*certificate);
}

/**
Destroys the certificate object
*/
X509Certificate::~X509Certificate()
{
	X509_free(certificate->certificate);
	delete certificate;
}

/**
Providse the X509 certificate serial number
@return the X509 certificate serial number
*/
std::string X509Certificate::getSerialNumber()
{
	BIO*	bp = BIO_new(BIO_s_mem());
	char	buffer[1024];
	i2a_ASN1_INTEGER(bp,X509_get_serialNumber(certificate->certificate));
	memset(buffer,0,sizeof(buffer));
	BIO_read(bp,buffer,sizeof(buffer));
	buffer[sizeof(buffer)-1]=0;
	BIO_free(bp);
	return buffer;
}
/**
Provides the Issuer Name
@return the Issuer Name
*/
std::string X509Certificate::getIssuerName()
{
	char	buffer[1024];
	return X509_NAME_oneline(X509_get_issuer_name(certificate->certificate),buffer,sizeof(buffer));
}
/**
Provides the subject name
@return The subject name
*/
std::string X509Certificate::getSubjectName()
{
	char	buffer[1024];
	return X509_NAME_oneline(X509_get_subject_name(certificate->certificate),buffer,sizeof(buffer));
}
/**
Provides the certificate not before date
@return The certificate not before date
*/
std::string X509Certificate::getNotBefore()
{
	BIO*	bp = BIO_new(BIO_s_mem());
	char	buffer[1024];
	ASN1_TIME_print(bp,X509_get_notBefore(certificate->certificate));
	memset(buffer,0,sizeof(buffer));
	BIO_read(bp,buffer,sizeof(buffer));
	buffer[sizeof(buffer)-1]=0;
	BIO_free(bp);
	return buffer;
}
/**
Provides the certificate not after date
@return The certificate not after date
*/
std::string X509Certificate::getNotAfter()
{
	BIO*	bp = BIO_new(BIO_s_mem());
	char	buffer[1024];
	ASN1_TIME_print(bp,X509_get_notAfter(certificate->certificate));
	memset(buffer,0,sizeof(buffer));
	BIO_read(bp,buffer,sizeof(buffer));
	buffer[sizeof(buffer)-1]=0;
	BIO_free(bp);
	return buffer;
}
/**
Converts the certificate to a string
@return The PEM string representation of the certificate
*/
std::string X509Certificate::toString()
{
	BIO* bp = BIO_new(BIO_s_mem());

	char		buffer[512];
	std::string ret;
	int			read;

	PEM_write_bio_X509(bp, certificate->certificate);
	while ((read = BIO_read(bp,buffer,sizeof(buffer))) == sizeof(buffer)) {
		ret.append(buffer,read);
	}
	if (read > 0)
		ret.append(buffer,read);

	BIO_free(bp);
	return ret;
}
/**
Provides a pointer to the X509 data structure
@return the X509 pointer cast to void*
*/
void* X509Certificate::getX509()
{
	return certificate->certificate;
}

// /////////////////////////////////////////////////////////////////////////////
// SSLSocket
// /////////////////////////////////////////////////////////////////////////////
/**
Constructs the SSLSocket object
*/
SSLSocket::SSLSocket()
{
	init();
}

/**
Constructs the SSLSocket and uses the provided socket handle for communications
@param socket_handle [in] A previously created socket handle
@param type [in] Flags the object as an SSL client
@param version [in] The SSL Protocol version to use
*/
SSLSocket::SSLSocket(int socket_handle, SSLSocket::con_type type, SSLSocket::ssl_ver version)
{
	init();
	init_ssl(version);
	m_socket = socket_handle;

	if (!pdata->ctx || !pdata->ssl) {
		throw SocketException(-1);
	}

	pdata->mrc = SSL_set_fd(pdata->ssl,m_socket);
	if (pdata->mrc < 1)
		throw SSLSocketException(getErrorMessage().c_str());

	if (type == con_client)
		SSL_set_connect_state(pdata->ssl);
	else 
		SSL_set_accept_state(pdata->ssl);
}

/**
Constructs the socket from a socket handle.
@param socket_handle [in] A previously created socket handle
@param pData [in] SSLSocketData to use, contains the CTX and/or the SSL object
@param type [in] Flags the object as an SSL client
*/
SSLSocket::SSLSocket(int socket_handle, SSLSocketData* pData, SSLSocket::con_type type)  throw (SSLSocketException)
{
	init();
	m_socket = socket_handle;

	this->pdata->ctx = pData->ctx;
	this->pdata->ssl = pData->ssl;

	if (this->pdata->ssl == NULL && this->pdata->ctx != NULL)
		this->pdata->ssl = SSL_new(this->pdata->ctx);

	if (!this->pdata->ssl) {
		close();
		throw SSLSocketException("Unable to retreive SSL object");
	}

	this->pdata->mrc = SSL_set_fd(this->pdata->ssl,m_socket);
	if (pdata->mrc < 1) {
		close();
		throw SSLSocketException(getErrorMessage().c_str());
	}

	if (type == con_client)
		SSL_set_connect_state(pdata->ssl);
	else if (type == con_server)
		SSL_set_accept_state(pdata->ssl);
}

/**
Copy constructor, copies the socket handle
@param s [in] The source socket
*/	
SSLSocket::SSLSocket(const SSLSocket& s)
{
	init();
	*this = s;
}

/**
Constructs the socket and opens a connection to a server.
@param host [in] The address of the server or DNS name
@param port [in] The TCP port to connect to
@param version [in] The SSL Protocol version to use
*/
SSLSocket::SSLSocket(const char* host, short port, SSLSocket::ssl_ver version) throw (SSLSocketException, SocketException) 
		: Socket(host,port)
{
	init();
	init_ssl(version);

	if (!pdata->ctx || !pdata->ssl) {
		throw SSLSocketException(getErrorMessage().c_str());
	}

	pdata->mrc = SSL_set_fd(pdata->ssl,m_socket);
	if (pdata->mrc < 0) {
		close();
		throw SSLSocketException(getErrorMessage().c_str());
	}

	SSL_set_connect_state(pdata->ssl);	
}
/**
Destroys the SSL socket
*/
SSLSocket::~SSLSocket()
{
	delete pdata;
}
/**
Copy oeprator, copies the socket handle and SSL information
@param s [in] The source socket
@return A reference tot his object.
*/	
SSLSocket& SSLSocket::operator=(const SSLSocket& s)
{
	pdata->ctx = s.pdata->ctx;
	pdata->ssl = s.pdata->ssl;
	m_socket = s.m_socket;
	m_throwOnClose = s.m_throwOnClose;
	return *this;
}

/**
Sends data over the socket.  Sends exactly <code>length</code> bytes.

@param sendBuffer [in] A buffer containing the data to be sent
@param length [in] The number of bytes in the buffer
@return The number of bytes sent, -1 on error, and 0 if the connection was closed
@exception SocketException if the connection was closed and the throw on close flag was set.
*/
size_t SSLSocket::send(const char* sendBuffer, size_t length)	throw (SSLSocketException)
{
	int		sent = 0;
	int		isent;

	while ( sent < length ) {
		pdata->mrc = isent = SSL_write(pdata->ssl,sendBuffer+sent,length-sent);
		if (isent == 0) {
			if (m_throwOnClose)
				throw SocketException(ECONNRESET);
			break;
		} else if (isent < 0) {
			int err = SSL_get_error(pdata->ssl,isent);
			if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
				sleep(200);
			} else {
				throw SSLSocketException(getErrorMessage().c_str());
			}
		} else {
			sent += isent;
		}
	}
	return sent;
}

/**
Receives data from the socket.  Receives exactly <code>length</code> bytes or
less if the socket is closed early.

@param sendBuffer [out] A buffer receiving the data 
@param length [in] The maximum number of bytes in the buffer
@return The number of bytes received, -1 on error, and 0 if the connection was closed
@exception SocketException if the connection was closed and the throw on close flag was set.

⌨️ 快捷键说明

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