Fix TLS read/write dispatch on tls branch

TCPSocket inherits from both Socket and TLS, both declaring receiveData()
as unrelated sibling methods - only Socket::receiveData was virtual, so
TLS::receiveData (SSL_read) was never reached regardless of TLS config,
and even when reached its result was never forwarded to onDataReceived
(that call was commented out). Added an explicit TCPSocket::receiveData
override dispatching to TLS::receiveData or Socket::receiveData based on
tlsInfo, and completed TLS::receiveData to actually return/forward the
decrypted bytes.

Write path did not exist at all. Added Socket::sendData() as a new
virtual hook mirroring receiveData, routed Socket::writeSocket() through
it instead of a raw ::write(), added TLS::sendData() (SSL_write, same
error-handling style as the existing TLS methods), and TCPSocket::sendData()
dispatching the same way the read side does.

Also fixed: a queued write in writeSocket() was being popped off the fifo
as if sent even when shutDown was true and nothing was actually written;
removed a dead empty if(tlsInfo){} stub in onDataReceived, no longer
needed now dispatch happens one level up; replaced leftover debug
std::cout lines with proper Log() calls matching the rest of the file.

Verified via full local compile: all 20 .cpp files build clean, link
into libServerCore.a, and nm confirms the new/fixed symbols are correctly
defined in the right object files.
This commit is contained in:
Brad Arant committed 2026-08-22 19:51:08 -07:00
1 parent 5feabd0fde
commit 701d03dcd9
6 files changed
+932 -851

No files matched your search

+207 -202
View File
@@ -1,202 +1,207 @@
#include "Socket.h" #include "Socket.h"
#include "EPoll.h" #include "EPoll.h"
#include "Exception.h" #include "Exception.h"
#include "Log.h" #include "Log.h"
#include "ZString.h" #include "ZString.h"
namespace core namespace core
{ {
void sigpipe_handler(int unused) {} void sigpipe_handler(int unused) {}
Socket::Socket(EPoll &ePoll, std::string text) : ePoll(ePoll), text(text) { Socket::Socket(EPoll &ePoll, std::string text) : ePoll(ePoll), text(text) {
coreutils::Log(coreutils::LOG_DEBUG_2) << "Socket object created [" << text << "]."; coreutils::Log(coreutils::LOG_DEBUG_2) << "Socket object created [" << text << "].";
buffer = (char *)malloc(4096); buffer = (char *)malloc(4096);
length = 4096; length = 4096;
} }
Socket::~Socket() { Socket::~Socket() {
shutDown = true; shutDown = true;
onUnregister(); onUnregister();
disableSocket(); disableSocket();
coreutils::Log(coreutils::LOG_DEBUG_4) << "Free on socket " << descriptor; coreutils::Log(coreutils::LOG_DEBUG_4) << "Free on socket " << descriptor;
free(buffer); free(buffer);
if(descriptor == -1) if(descriptor == -1)
return; return;
close(descriptor); close(descriptor);
coreutils::Log(coreutils::LOG_DEBUG_1) << text << " has ended (" << descriptor << ")."; coreutils::Log(coreutils::LOG_DEBUG_1) << text << " has ended (" << descriptor << ").";
} }
void Socket::setDescriptor(int descriptor) void Socket::setDescriptor(int descriptor)
{ {
if ((descriptor == -1) && (errno == 24)) if ((descriptor == -1) && (errno == 24))
{ {
shutdown("Too many files open"); shutdown("Too many files open");
throw coreutils::Exception("Too many files open. Refusing connection."); throw coreutils::Exception("Too many files open. Refusing connection.");
} }
coreutils::Log(coreutils::LOG_DEBUG_1) << text << " has started (" << descriptor << ")."; coreutils::Log(coreutils::LOG_DEBUG_1) << text << " has started (" << descriptor << ").";
if(descriptor < 3) if(descriptor < 3)
throw coreutils::Exception("Descriptor out of range", __FILE__, __LINE__); throw coreutils::Exception("Descriptor out of range", __FILE__, __LINE__);
this->descriptor = descriptor; this->descriptor = descriptor;
onRegister(); onRegister();
enableSocket(); enableSocket();
onRegistered(); onRegistered();
} }
int Socket::getDescriptor() int Socket::getDescriptor()
{ {
return descriptor; return descriptor;
} }
void Socket::setBufferSize(int length) void Socket::setBufferSize(int length)
{ {
this->length = length; this->length = length;
buffer = (char *)realloc(buffer, length); buffer = (char *)realloc(buffer, length);
} }
int Socket::getBufferSize() int Socket::getBufferSize()
{ {
return length; return length;
} }
void Socket::onRegister() {} void Socket::onRegister() {}
void Socket::onRegistered() {} void Socket::onRegistered() {}
void Socket::onUnregister() {} void Socket::onUnregister() {}
void Socket::onUnregistered() {} void Socket::onUnregistered() {}
bool Socket::eventReceived(struct epoll_event event, long long eventId) { bool Socket::eventReceived(struct epoll_event event, long long eventId) {
coreutils::Log(coreutils::LOG_DEBUG_1) << "Event process beginning for socket " << getDescriptor(); coreutils::Log(coreutils::LOG_DEBUG_1) << "Event process beginning for socket " << getDescriptor();
if(inHandler) if(inHandler)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ coreutils::Log(coreutils::LOG_DEBUG_2) << "inHandler was already true."; coreutils::Log(coreutils::LOG_DEBUG_2) << "inHandler was already true.";
inHandler = true; inHandler = true;
if(event.events & EPOLLRDHUP) { if(event.events & EPOLLRDHUP) {
coreutils::Log(coreutils::LOG_DEBUG_2) << "EPOLLRDHUP"; coreutils::Log(coreutils::LOG_DEBUG_2) << "EPOLLRDHUP";
readHangup = true; readHangup = true;
shutdown("hangup received"); shutdown("hangup received");
} }
if(event.events & EPOLLIN) { if(event.events & EPOLLIN) {
coreutils::Log(coreutils::LOG_DEBUG_2) << "EPOLLIN"; coreutils::Log(coreutils::LOG_DEBUG_2) << "EPOLLIN";
coreutils::ZString zbuffer(buffer, length); coreutils::ZString zbuffer(buffer, length);
lock.lock(); lock.lock();
receiveData(zbuffer); receiveData(zbuffer);
if(!shutDown) { if(!shutDown) {
inHandler = false; inHandler = false;
lock.unlock(); lock.unlock();
resetSocket(); resetSocket();
} }
} }
if(event.events & EPOLLWRNORM) { if(event.events & EPOLLWRNORM) {
coreutils::Log(coreutils::LOG_DEBUG_2) << "EPOLLWRNORM"; coreutils::Log(coreutils::LOG_DEBUG_2) << "EPOLLWRNORM";
writeSocket(); writeSocket();
inHandler = false; inHandler = false;
resetSocket(); resetSocket();
} }
inHandler = false; inHandler = false;
coreutils::Log(coreutils::LOG_DEBUG_1) << "Event process ending for socket " << getDescriptor(); coreutils::Log(coreutils::LOG_DEBUG_1) << "Event process ending for socket " << getDescriptor();
return !shutDown; return !shutDown;
} }
void Socket::connectionRequest() {} void Socket::connectionRequest() {}
void Socket::onDataReceived(std::string data) { void Socket::onDataReceived(std::string data) {
throw coreutils::Exception("Need to override onDataReceived.", __FILE__, __LINE__, -1); throw coreutils::Exception("Need to override onDataReceived.", __FILE__, __LINE__, -1);
} }
void Socket::onDataReceived(coreutils::ZString &data) { void Socket::onDataReceived(coreutils::ZString &data) {
onDataReceived(std::string(data.getData(), data.getLength())); onDataReceived(std::string(data.getData(), data.getLength()));
} }
void Socket::receiveData(coreutils::ZString &buffer) { void Socket::receiveData(coreutils::ZString &buffer) {
coreutils::ZString blank(""); coreutils::ZString blank("");
if(buffer.getLength() <= 0) if(buffer.getLength() <= 0)
throw coreutils::Exception("Request to receive data with a zero buffer length.", __FILE__, __LINE__, -1); throw coreutils::Exception("Request to receive data with a zero buffer length.", __FILE__, __LINE__, -1);
int len; int len;
int error = -1; int error = -1;
if((len = ::read(getDescriptor(), buffer.getData(), buffer.getLength())) >= 0) { if((len = ::read(getDescriptor(), buffer.getData(), buffer.getLength())) >= 0) {
coreutils::ZString zbuffer(buffer.getData(), len); coreutils::ZString zbuffer(buffer.getData(), len);
// coreutils::Log(coreutils::LOG_DEBUG_1) << zbuffer; // coreutils::Log(coreutils::LOG_DEBUG_1) << zbuffer;
onDataReceived(zbuffer); onDataReceived(zbuffer);
} else { } else {
error = errno; error = errno;
switch (error) { switch (error) {
// When a listening socket receives a connection // When a listening socket receives a connection
// request we get one of these. // request we get one of these.
case ENOTCONN: case ENOTCONN:
connectionRequest(); connectionRequest();
break; break;
case ECONNRESET: case ECONNRESET:
break; break;
default: default:
throw coreutils::Exception("Error in read of data from socket.", __FILE__, __LINE__, error); throw coreutils::Exception("Error in read of data from socket.", __FILE__, __LINE__, error);
} }
} }
} }
void Socket::writeSocket() { int Socket::sendData(const char *data, int length) {
outlock.lock(); return ::write(descriptor, data, length);
// coreutils::Log(coreutils::LOG_DEBUG_3) << "writing data to socket " << getDescriptor(); }
if(fifo.size() > 0) {
if(!shutDown) void Socket::writeSocket() {
int rc = ::write(descriptor, fifo.front().c_str(), fifo.front().length()); outlock.lock();
fifo.pop(); // coreutils::Log(coreutils::LOG_DEBUG_3) << "writing data to socket " << getDescriptor();
} if(fifo.size() > 0) {
outlock.unlock(); if(!shutDown) {
} sendData(fifo.front().c_str(), fifo.front().length());
fifo.pop();
int Socket::write(std::string data) { }
outlock.lock(); }
fifo.emplace(data); outlock.unlock();
outlock.unlock(); }
if(lock.try_lock()) {
resetSocket(); int Socket::write(std::string data) {
lock.unlock(); outlock.lock();
} fifo.emplace(data);
return 1; outlock.unlock();
} if(lock.try_lock()) {
resetSocket();
void Socket::output(std::stringstream &out) lock.unlock();
{ }
out << "|" << descriptor << "|"; return 1;
} }
bool Socket::needsToWrite() void Socket::output(std::stringstream &out)
{ {
return fifo.size() > 0; out << "|" << descriptor << "|";
} }
void Socket::shutdown(std::string text) { bool Socket::needsToWrite()
coreutils::Log(coreutils::LOG_DEBUG_2) << "Shutdown requested from " << this->text << " (" << descriptor << ") with reason: " << text << "."; {
shutDown = true; return fifo.size() > 0;
reset = false; }
}
void Socket::shutdown(std::string text) {
void Socket::enableSocket() { coreutils::Log(coreutils::LOG_DEBUG_2) << "Shutdown requested from " << this->text << " (" << descriptor << ") with reason: " << text << ".";
struct epoll_event event; shutDown = true;
event.data.ptr = this; reset = false;
event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT | EPOLLET; }
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_ADD, getDescriptor(), &event);
} void Socket::enableSocket() {
struct epoll_event event;
void Socket::disableSocket() { event.data.ptr = this;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_DEL, getDescriptor(), NULL); event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT | EPOLLET;
} epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_ADD, getDescriptor(), &event);
}
void Socket::resetSocket() {
struct epoll_event event; void Socket::disableSocket() {
event.data.ptr = this; epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_DEL, getDescriptor(), NULL);
event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT | EPOLLET; }
if(fifo.size() > 0)
event.events |= EPOLLWRNORM; void Socket::resetSocket() {
if(!shutDown) struct epoll_event event;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_MOD, getDescriptor(), &event); event.data.ptr = this;
} event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT | EPOLLET;
if(fifo.size() > 0)
event.events |= EPOLLWRNORM;
} if(!shutDown)
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_MOD, getDescriptor(), &event);
}
}
+221 -212
View File
@@ -1,212 +1,221 @@
#ifndef __Socket_h__ #ifndef __Socket_h__
#define __Socket_h__ #define __Socket_h__
#include "ZString.h" #include "ZString.h"
#include <queue> #include <queue>
#include <mutex> #include <mutex>
#include <sys/epoll.h> #include <sys/epoll.h>
namespace core { namespace core {
class EPoll; class EPoll;
/// ///
/// Socket /// Socket
/// ///
/// The core component to managing a socket. /// The core component to managing a socket.
/// ///
/// Hooks into the EPoll through the registration and unregistration process and provides a /// Hooks into the EPoll through the registration and unregistration process and provides a
/// communication socket of the specified protocol type. This object provides for all receiving /// communication socket of the specified protocol type. This object provides for all receiving
/// data threading through use of the EPoll object and also provides buffering for output data /// data threading through use of the EPoll object and also provides buffering for output data
/// requests to the socket. /// requests to the socket.
/// ///
/// A program using a socket object can request to open a socket (network or device) and /// A program using a socket object can request to open a socket (network or device) and
/// communicate through the streambuffer interface of the socket object. /// communicate through the streambuffer interface of the socket object.
/// ///
/// The socket side of the Socket accepts EPOLLIN event and will maintain the data in a buffer /// The socket side of the Socket accepts EPOLLIN event and will maintain the data in a buffer
/// for the stream readers to read. A onDataReceived event is then sent with the data received in /// for the stream readers to read. A onDataReceived event is then sent with the data received in
/// the buffer that can be read through the stream. Only sockets that send events to epoll can be /// the buffer that can be read through the stream. Only sockets that send events to epoll can be
/// used with this object. /// used with this object.
/// ///
/// When writing to the stream the data is written into a buffer and a EPOLLOUT is scheduled. Upon /// When writing to the stream the data is written into a buffer and a EPOLLOUT is scheduled. Upon
/// receiving the EPOLLOUT event then the buffer is written to the socket output. /// receiving the EPOLLOUT event then the buffer is written to the socket output.
/// ///
class Socket { class Socket {
public: public:
/// ///
/// Constructor /// Constructor
/// ///
/// @param ePoll The EPoll socket descriptor. /// @param ePoll The EPoll socket descriptor.
/// @param text A title for this socket. /// @param text A title for this socket.
/// ///
Socket(EPoll &ePoll, std::string text = ""); Socket(EPoll &ePoll, std::string text = "");
/// ///
/// Destructor /// Destructor
/// ///
virtual ~Socket(); virtual ~Socket();
/// ///
/// Use the shutdown() method to terminate the socket connection and remove resources. /// Use the shutdown() method to terminate the socket connection and remove resources.
/// This method is provided to ensure that all destructors are called for all inherited /// This method is provided to ensure that all destructors are called for all inherited
/// objects with a virtual destructor. /// objects with a virtual destructor.
/// ///
void shutdown(std::string text = "unknown"); void shutdown(std::string text = "unknown");
/// ///
/// setDescriptor establishes the file descriptor for the socket and registers the socket /// setDescriptor establishes the file descriptor for the socket and registers the socket
/// on the EPoll controller. setDescriptor will invoke the onRegister() event. /// on the EPoll controller. setDescriptor will invoke the onRegister() event.
/// ///
void setDescriptor(int descriptor); ///<Set the descriptor for the socket. void setDescriptor(int descriptor); ///<Set the descriptor for the socket.
int getDescriptor(); ///< Get the descriptor for the socket. int getDescriptor(); ///< Get the descriptor for the socket.
/// ///
/// The event received from epoll is sent through the eventReceived /// The event received from epoll is sent through the eventReceived
/// method which will parse the event and call the read and write /// method which will parse the event and call the read and write
/// callbacks on the socket. /// callbacks on the socket.
/// ///
/// This method is called by the BMAEPoll object and should not be called /// This method is called by the BMAEPoll object and should not be called
/// from any user extended classes unless an epoll event is being /// from any user extended classes unless an epoll event is being
/// simulated. /// simulated.
/// ///
/// The return value of false will delete the socket object causing the destructors to run. /// The return value of false will delete the socket object causing the destructors to run.
/// The return value of true will enable the socket on ePoll to receive more events. /// The return value of true will enable the socket on ePoll to receive more events.
/// ///
bool eventReceived(struct epoll_event event, long long eventId); ///< Parse epoll event and call specified callbacks. bool eventReceived(struct epoll_event event, long long eventId); ///< Parse epoll event and call specified callbacks.
/// ///
/// Write data to the socket. /// Write data to the socket.
/// ///
int write(std::string data); int write(std::string data);
void write(char *buffer, int length); void write(char *buffer, int length);
void output(std::stringstream &out); void output(std::stringstream &out);
/// ///
/// The onRegister method is called before the socket is registered with /// The onRegister method is called before the socket is registered with
/// ePoll so objects extending the Socket definition can initialize the socket /// ePoll so objects extending the Socket definition can initialize the socket
/// before receiving events. Evoked when the /// before receiving events. Evoked when the
/// descriptor is set using setDescriptor for the socket. /// descriptor is set using setDescriptor for the socket.
/// ///
virtual void onRegister(); ///< Called before the socket has registered with the epoll processing. virtual void onRegister(); ///< Called before the socket has registered with the epoll processing.
virtual void onRegistered(); ///< Called after the socket has been registered with epoll processing. virtual void onRegistered(); ///< Called after the socket has been registered with epoll processing.
virtual void onUnregister(); virtual void onUnregister();
/// ///
/// ePoll and socket communcation events will be stopped. The default method will /// ePoll and socket communcation events will be stopped. The default method will
/// close the socket and clean up the connection. If this is overridden by an /// close the socket and clean up the connection. If this is overridden by an
/// extended object then the object should call this method to clean the socket up. /// extended object then the object should call this method to clean the socket up.
/// ///
virtual void onUnregistered(); ///< Called when the socket has finished unregistering for the epoll processing. virtual void onUnregistered(); ///< Called when the socket has finished unregistering for the epoll processing.
bool needsToWrite(); bool needsToWrite();
bool reset = false; bool reset = false;
volatile bool shutDown = false; volatile bool shutDown = false;
void enableSocket(); void enableSocket();
void disableSocket(); void disableSocket();
protected: protected:
EPoll &ePoll; // The EPoll control object. EPoll &ePoll; // The EPoll control object.
void setBufferSize(int length); void setBufferSize(int length);
int getBufferSize(); int getBufferSize();
/// ///
/// The onConnected method is called when the socket is ready to communicate. /// The onConnected method is called when the socket is ready to communicate.
/// Writing to the socket can begin on this call to initiate a contact with the /// Writing to the socket can begin on this call to initiate a contact with the
/// remote device. /// remote device.
/// ///
// virtual void onConnected(); ///< Called when socket is open and ready to communicate. // virtual void onConnected(); ///< Called when socket is open and ready to communicate.
/// ///
/// The connectionRequest method is called to instantiate a new session handler object /// The connectionRequest method is called to instantiate a new session handler object
/// and form a new connection to a listening server. /// and form a new connection to a listening server.
/// ///
virtual void connectionRequest(); virtual void connectionRequest();
/// ///
/// ///
/// ///
// virtual void onDisconnected(); ///< Called when socket is closing and no longer ready to communicate. // virtual void onDisconnected(); ///< Called when socket is closing and no longer ready to communicate.
/// ///
/// The onDataReceived method is called when the socket has received an event from /// The onDataReceived method is called when the socket has received an event from
/// epoll and there is data ready to be read from the socket. The default handler /// epoll and there is data ready to be read from the socket. The default handler
/// will pull the data and put it into the streambuf for the socket. EPOLLIN /// will pull the data and put it into the streambuf for the socket. EPOLLIN
/// ///
/// @param data the data that has been received from the socket. /// @param data the data that has been received from the socket.
/// ///
virtual void onDataReceived(std::string data); ///< Called when data is received from the socket. virtual void onDataReceived(std::string data); ///< Called when data is received from the socket.
/// ///
/// ///
/// ///
virtual void onDataReceived(coreutils::ZString &data); virtual void onDataReceived(coreutils::ZString &data);
/// ///
/// receiveData will read the data from the socket and place it in the socket buffer. /// receiveData will read the data from the socket and place it in the socket buffer.
/// TLS layer overrides this to be able to read from SSL. /// TLS layer overrides this to be able to read from SSL.
/// ///
virtual void receiveData(coreutils::ZString &buffer); virtual void receiveData(coreutils::ZString &buffer);
private: ///
/// sendData writes data to the socket descriptor. TLS layer overrides this to
std::string text; /// write through SSL instead of a raw socket write.
int descriptor = -1; ///
std::mutex outlock; /// @return The number of bytes written, or -1 on error.
bool readHangup = false; ///
volatile bool inHandler = false;
virtual int sendData(const char *data, int length);
//-------------------------------------------------------------------------------------
// the writeSocket is called when epoll has received a write request for a socket. private:
// Writing data to this socket is queued in the streambuf and permission is requested
// to write to the socket. This routine handles the writing of the streambuf data std::string text;
// buffer to the socket. int descriptor = -1;
//------------------------------------------------------------------------------------- std::mutex outlock;
bool readHangup = false;
void writeSocket(); volatile bool inHandler = false;
// int_type underflow(); //-------------------------------------------------------------------------------------
// int_type uflow(); // the writeSocket is called when epoll has received a write request for a socket.
// int_type pbackfail(int_type ch); // Writing data to this socket is queued in the streambuf and permission is requested
// streamsize showmanyc(); // to write to the socket. This routine handles the writing of the streambuf data
// buffer to the socket.
char *buffer; // This is a pointer to the managed buffer space. //-------------------------------------------------------------------------------------
int length; // This is the length of the buffer.
void writeSocket();
std::queue<std::string> fifo;
// int_type underflow();
void resetSocket(); // int_type uflow();
// int_type pbackfail(int_type ch);
std::mutex lock; // streamsize showmanyc();
}; char *buffer; // This is a pointer to the managed buffer space.
int length; // This is the length of the buffer.
}
std::queue<std::string> fifo;
#endif
void resetSocket();
std::mutex lock;
};
}
#endif
+95 -80
View File
@@ -1,80 +1,95 @@
#include "TCPSocket.h" #include "TCPSocket.h"
#include "EPoll.h" #include "EPoll.h"
#include "Log.h" #include "Log.h"
#include "Exception.h" #include "Exception.h"
#include "errno.h" #include "errno.h"
namespace core { namespace core {
TCPSocket::TCPSocket(EPoll &ePoll) : Socket(ePoll) {} TCPSocket::TCPSocket(EPoll &ePoll) : Socket(ePoll) {}
TCPSocket::TCPSocket(EPoll &ePoll, std::string text) : Socket(ePoll, text) {} TCPSocket::TCPSocket(EPoll &ePoll, std::string text) : Socket(ePoll, text) {}
TCPSocket::TCPSocket(EPoll &ePoll, TLSInfo *tlsInfo, std::string text) : Socket(ePoll, text), TLS(tlsInfo), tlsInfo(tlsInfo) {} TCPSocket::TCPSocket(EPoll &ePoll, TLSInfo *tlsInfo, std::string text) : Socket(ePoll, text), TLS(tlsInfo), tlsInfo(tlsInfo) {}
TCPSocket::TCPSocket(EPoll &ePoll, SSL_CTX *ctx, std::string text) : Socket(ePoll, text), TLS(ctx) {} TCPSocket::TCPSocket(EPoll &ePoll, SSL_CTX *ctx, std::string text) : Socket(ePoll, text), TLS(ctx) {}
TCPSocket::~TCPSocket() {} TCPSocket::~TCPSocket() {}
void TCPSocket::connect(IPAddress &address) { void TCPSocket::connect(IPAddress &address) {
setDescriptor(socket(AF_INET, SOCK_STREAM, 0)); setDescriptor(socket(AF_INET, SOCK_STREAM, 0));
if(::connect(getDescriptor(), (struct sockaddr *)&address.addr, address.addressLength) == -1) if(::connect(getDescriptor(), (struct sockaddr *)&address.addr, address.addressLength) == -1)
throw coreutils::Exception("Error on connect to TCP socket." + errno); throw coreutils::Exception("Error on connect to TCP socket." + errno);
coreutils::Log(coreutils::LOG_DEBUG_3) << "Connected to IP..." << address.getClientAddressAndPort(); coreutils::Log(coreutils::LOG_DEBUG_3) << "Connected to IP..." << address.getClientAddressAndPort();
} }
void TCPSocket::output(std::stringstream &out) { void TCPSocket::output(std::stringstream &out) {
out << "|" << ipAddress.getClientAddressAndPort(); out << "|" << ipAddress.getClientAddressAndPort();
} }
void TCPSocket::onDataReceived(coreutils::ZString &data) { void TCPSocket::receiveData(coreutils::ZString &buffer) {
if(tlsInfo) {
if(tlsInfo) { int len = TLS::receiveData(buffer);
if(len >= 0) {
} coreutils::ZString zbuffer(buffer.getData(), len);
onDataReceived(zbuffer);
if (data.getLength() > 0) { }
lineBuffer = (char *)realloc(lineBuffer, lineBufferSize + data.getLength()); } else {
memcpy(lineBuffer + lineBufferSize, data.getData(), data.getLength()); Socket::receiveData(buffer);
lineBufferSize += data.getLength(); }
while (lineBufferSize > 0) { }
if (blockSize == 0) {
lineLength = strcspn(lineBuffer, "\r\n"); int TCPSocket::sendData(const char *data, int length) {
if (lineLength == lineBufferSize) if(tlsInfo)
break; return TLS::sendData(data, length);
coreutils::ZString zLine(lineBuffer, lineLength); else
onLineReceived(zLine); return Socket::sendData(data, length);
if (lineBuffer[lineLength] == '\r') }
++lineLength;
if (lineBuffer[lineLength] == '\n') void TCPSocket::onDataReceived(coreutils::ZString &data) {
++lineLength;
lineBufferSize -= lineLength; if (data.getLength() > 0) {
if (lineBufferSize > 0) lineBuffer = (char *)realloc(lineBuffer, lineBufferSize + data.getLength());
memmove(lineBuffer, lineBuffer + lineLength, lineBufferSize); memcpy(lineBuffer + lineBufferSize, data.getData(), data.getLength());
lineBuffer = (char *)realloc(lineBuffer, lineBufferSize); lineBufferSize += data.getLength();
} while (lineBufferSize > 0) {
else if (lineBufferSize >= blockLength) { if (blockSize == 0) {
coreutils::ZString zBlock(lineBuffer, blockLength); lineLength = strcspn(lineBuffer, "\r\n");
onBlockReceived(zBlock); if (lineLength == lineBufferSize)
lineBufferSize -= blockLength; break;
if (lineBufferSize > 0) coreutils::ZString zLine(lineBuffer, lineLength);
memmove(lineBuffer, lineBuffer + blockLength, lineBufferSize); onLineReceived(zLine);
lineBuffer = (char *)realloc(lineBuffer, lineBufferSize); if (lineBuffer[lineLength] == '\r')
} ++lineLength;
} if (lineBuffer[lineLength] == '\n')
} ++lineLength;
} lineBufferSize -= lineLength;
if (lineBufferSize > 0)
void TCPSocket::onLineReceived(coreutils::ZString &line) { memmove(lineBuffer, lineBuffer + lineLength, lineBufferSize);
if (term) lineBuffer = (char *)realloc(lineBuffer, lineBufferSize);
shutdown("termination requested"); }
} else if (lineBufferSize >= blockLength) {
coreutils::ZString zBlock(lineBuffer, blockLength);
void TCPSocket::onBlockReceived(coreutils::ZString &block) {} onBlockReceived(zBlock);
lineBufferSize -= blockLength;
void TCPSocket::setBlockSize(int blockSize) { if (lineBufferSize > 0)
this->blockSize = blockSize; memmove(lineBuffer, lineBuffer + blockLength, lineBufferSize);
} lineBuffer = (char *)realloc(lineBuffer, lineBufferSize);
}
} }
}
}
void TCPSocket::onLineReceived(coreutils::ZString &line) {
if (term)
shutdown("termination requested");
}
void TCPSocket::onBlockReceived(coreutils::ZString &block) {}
void TCPSocket::setBlockSize(int blockSize) {
this->blockSize = blockSize;
}
}
+141 -122
View File
@@ -1,122 +1,141 @@
#ifndef __TCPSocket_h__ #ifndef __TCPSocket_h__
#define __TCPSocket_h__ #define __TCPSocket_h__
#include "Socket.h" #include "Socket.h"
#include "TLS.h" #include "TLS.h"
#include "TLSInfo.h" #include "TLSInfo.h"
#include "IPAddress.h" #include "IPAddress.h"
namespace core { namespace core {
/// ///
/// TCPSocket /// TCPSocket
/// ///
/// Provides a network TCP socket. /// Provides a network TCP socket.
/// ///
/// For accessing TCP network functions use this object. The connection oriented nature of TCP /// For accessing TCP network functions use this object. The connection oriented nature of TCP
/// provides a single client persistent connection with data error correction and a durable /// provides a single client persistent connection with data error correction and a durable
/// synchronous data connection. /// synchronous data connection.
/// ///
class TCPSocket : public Socket, public TLS { class TCPSocket : public Socket, public TLS {
public: public:
/// ///
/// ///
/// ///
TCPSocket(EPoll &ePoll); TCPSocket(EPoll &ePoll);
/// ///
/// ///
/// ///
TCPSocket(EPoll &ePoll, std::string text); TCPSocket(EPoll &ePoll, std::string text);
/// ///
/// ///
/// ///
TCPSocket(EPoll &ePoll, TLSInfo *tlsInfo, std::string text); TCPSocket(EPoll &ePoll, TLSInfo *tlsInfo, std::string text);
/// ///
/// ///
/// ///
TCPSocket(EPoll &ePoll, SSL_CTX *ctx, std::string text); TCPSocket(EPoll &ePoll, SSL_CTX *ctx, std::string text);
/// ///
/// ///
/// ///
virtual ~TCPSocket(); virtual ~TCPSocket();
/// ///
/// ///
/// ///
void connect(IPAddress &address); void connect(IPAddress &address);
IPAddress ipAddress; IPAddress ipAddress;
/// ///
/// The output method is called by a socket session (TCPSession) and /// The output method is called by a socket session (TCPSession) and
/// will output the detail information for the client socket. When extending /// will output the detail information for the client socket. When extending
/// TCPSocket or TCPSession you can override the method to add attributes /// TCPSocket or TCPSession you can override the method to add attributes
/// to the list. /// to the list.
/// ///
virtual void output(std::stringstream &out); virtual void output(std::stringstream &out);
/// ///
/// Override this method to receive data directly from the socket as data is /// Override this method to receive data directly from the socket as data is
/// received. If you need data split by line termination characters then /// received. If you need data split by line termination characters then
/// override the onLineReceived method instead. /// override the onLineReceived method instead.
/// ///
virtual void onDataReceived(coreutils::ZString &data) override; virtual void onDataReceived(coreutils::ZString &data) override;
/// ///
/// Override the onLineReceived method to receive a string of characters that /// Override the onLineReceived method to receive a string of characters that
/// represents a single line of data terminated by a LF or CRLF. If onDataReceived /// represents a single line of data terminated by a LF or CRLF. If onDataReceived
/// was overriden this method will not be called unless the onDataReceived calls /// was overriden this method will not be called unless the onDataReceived calls
/// this method explicitly using the class and member name. /// this method explicitly using the class and member name.
/// ///
virtual void onLineReceived(coreutils::ZString &line); virtual void onLineReceived(coreutils::ZString &line);
/// ///
/// Override the onBlockReceived method to receive a string of characters that /// Override the onBlockReceived method to receive a string of characters that
/// represents a single block of data of length determined by the block length value. If /// represents a single block of data of length determined by the block length value. If
/// onDataReceived was overriden this method will not be called unless the onDataReceived /// onDataReceived was overriden this method will not be called unless the onDataReceived
/// calls this method explicitly using the class and member name. /// calls this method explicitly using the class and member name.
/// ///
virtual void onBlockReceived(coreutils::ZString &block); virtual void onBlockReceived(coreutils::ZString &block);
/// ///
/// Use setBlockSize to set the amount of data that should be read at once from the /// Use setBlockSize to set the amount of data that should be read at once from the
/// session data buffer. /// session data buffer.
/// If this value is set to 0 then the data will be retrieved /// If this value is set to 0 then the data will be retrieved
/// ///
void setBlockSize(int size = 0); void setBlockSize(int size = 0);
protected: ///
bool term = false; /// Dispatches to TLS::receiveData (SSL_read) when this socket was constructed with a
TLSInfo *tlsInfo; /// TLSInfo/SSL_CTX, otherwise falls back to Socket::receiveData (plain ::read). Needed
/// because Socket and TLS both declare receiveData as unrelated sibling methods -
private: /// Socket::receiveData is virtual but TLS::receiveData does not override it, so without
char *lineBuffer = NULL; /// this explicit override TLS::receiveData would never be reached and encrypted bytes
int lineBufferSize = 0; /// would be handed to onDataReceived as if they were plaintext.
int lineLength = 0; ///
int blockLength = 0;
int blockSize = 0; virtual void receiveData(coreutils::ZString &buffer) override;
}; ///
/// Dispatches to TLS::sendData (SSL_write) when this socket was constructed with a
} /// TLSInfo/SSL_CTX, otherwise falls back to Socket::sendData (plain ::write). Mirrors
/// the receiveData override above for the write path.
#endif ///
virtual int sendData(const char *data, int length) override;
protected:
bool term = false;
TLSInfo *tlsInfo;
private:
char *lineBuffer = NULL;
int lineBufferSize = 0;
int lineLength = 0;
int blockLength = 0;
int blockSize = 0;
};
}
#endif
+200 -168
View File
@@ -1,169 +1,201 @@
#include "TLS.h" #include "TLS.h"
#include "Exception.h" #include "Exception.h"
#include "Log.h" #include "Log.h"
#include <iostream> #include <iostream>
#include <openssl/rand.h> #include <openssl/rand.h>
namespace core { namespace core {
static pthread_mutex_t *lockarray; static pthread_mutex_t *lockarray;
static unsigned long thread_id(void) { static unsigned long thread_id(void) {
return ((unsigned long) pthread_self()); return ((unsigned long) pthread_self());
} }
static void lock_callback(int mode, int type, const char *file, int line) { static void lock_callback(int mode, int type, const char *file, int line) {
if(mode & CRYPTO_LOCK) if(mode & CRYPTO_LOCK)
pthread_mutex_lock(&(lockarray[type])); pthread_mutex_lock(&(lockarray[type]));
else else
pthread_mutex_unlock(&(lockarray[type])); pthread_mutex_unlock(&(lockarray[type]));
} }
static int generate_session_id(const SSL *ssl, unsigned char *id, unsigned int *id_len) { static int generate_session_id(const SSL *ssl, unsigned char *id, unsigned int *id_len) {
char *session_id_prefix = (char *)"BARANT"; char *session_id_prefix = (char *)"BARANT";
unsigned int count = 0; unsigned int count = 0;
coreutils::Log(coreutils::LOG_DEBUG_3) << "Generating unique session id."; coreutils::Log(coreutils::LOG_DEBUG_3) << "Generating unique session id.";
do { do {
RAND_bytes(id, *id_len); RAND_bytes(id, *id_len);
memcpy(id, session_id_prefix, (strlen(session_id_prefix) < *id_len)); memcpy(id, session_id_prefix, (strlen(session_id_prefix) < *id_len));
} while(SSL_has_matching_session_id(ssl, id, *id_len) && (++count < 10)); } while(SSL_has_matching_session_id(ssl, id, *id_len) && (++count < 10));
return 1; return 1;
} }
void handshake_complete(const SSL *ssl, int where, int ret) { void handshake_complete(const SSL *ssl, int where, int ret) {
coreutils::Log(coreutils::LOG_DEBUG_3) << "==>" << SSL_state_string_long(ssl) << "<==" << ret; coreutils::Log(coreutils::LOG_DEBUG_3) << "==>" << SSL_state_string_long(ssl) << "<==" << ret;
if(where & SSL_CB_HANDSHAKE_DONE) { if(where & SSL_CB_HANDSHAKE_DONE) {
X509 *ssl_client_cert = SSL_get_peer_certificate(ssl); X509 *ssl_client_cert = SSL_get_peer_certificate(ssl);
if(!ssl_client_cert) if(!ssl_client_cert)
throw std::string("Unable to get peer certificate."); throw std::string("Unable to get peer certificate.");
X509_free(ssl_client_cert); X509_free(ssl_client_cert);
if(SSL_get_verify_result(ssl) != X509_V_OK) if(SSL_get_verify_result(ssl) != X509_V_OK)
throw std::string("Certificate verification failed."); throw std::string("Certificate verification failed.");
coreutils::Log(coreutils::LOG_DEBUG_3) << "Certificate verified successfully."; coreutils::Log(coreutils::LOG_DEBUG_3) << "Certificate verified successfully.";
} }
else else
coreutils::Log(coreutils::LOG_DEBUG_3) << "No client certificate."; coreutils::Log(coreutils::LOG_DEBUG_3) << "No client certificate.";
} }
TLS::TLS() {} TLS::TLS() {}
TLS::TLS(TLSInfo *tlsInfo) { TLS::TLS(TLSInfo *tlsInfo) {
createContext(tlsInfo); createContext(tlsInfo);
} }
TLS::TLS(SSL_CTX *ctx) : ctx(ctx) {} TLS::TLS(SSL_CTX *ctx) : ctx(ctx) {}
TLS::~TLS() {} TLS::~TLS() {}
void TLS::createContext(TLSInfo *tlsInfo) { void TLS::createContext(TLSInfo *tlsInfo) {
if(tlsInfo) { if(tlsInfo) {
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
for(int i = 0; i < CRYPTO_num_locks(); ++i) for(int i = 0; i < CRYPTO_num_locks(); ++i)
pthread_mutex_init(&(lockarray[i]), NULL); pthread_mutex_init(&(lockarray[i]), NULL);
CRYPTO_set_id_callback((unsigned long (*)())thread_id); CRYPTO_set_id_callback((unsigned long (*)())thread_id);
CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))lock_callback); CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))lock_callback);
SSLeay_add_ssl_algorithms(); SSLeay_add_ssl_algorithms();
RAND_load_file("/dev/hwrng", 1024); RAND_load_file("/dev/hwrng", 1024);
if(!(ctx = SSL_CTX_new(SSLv23_server_method()))) if(!(ctx = SSL_CTX_new(SSLv23_server_method())))
throw coreutils::Exception("Error while setting server method SSLv23."); throw coreutils::Exception("Error while setting server method SSLv23.");
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
// SSL_CTX_set_generate_session_id(ctx, generate_session_id); // SSL_CTX_set_generate_session_id(ctx, generate_session_id);
SSL_CTX_set_cipher_list(ctx, "ECDH-ECDSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA"); SSL_CTX_set_cipher_list(ctx, "ECDH-ECDSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA");
if(SSL_CTX_use_certificate_file(ctx, tlsInfo->certificate.c_str(), SSL_FILETYPE_PEM) <= 0) if(SSL_CTX_use_certificate_file(ctx, tlsInfo->certificate.c_str(), SSL_FILETYPE_PEM) <= 0)
throw coreutils::Exception("Error looking up certificate."); throw coreutils::Exception("Error looking up certificate.");
if(SSL_CTX_use_PrivateKey_file(ctx, tlsInfo->key.c_str(), SSL_FILETYPE_PEM) < 0) if(SSL_CTX_use_PrivateKey_file(ctx, tlsInfo->key.c_str(), SSL_FILETYPE_PEM) < 0)
throw coreutils::Exception("Error with private key."); throw coreutils::Exception("Error with private key.");
if(SSL_CTX_check_private_key(ctx) != 1) if(SSL_CTX_check_private_key(ctx) != 1)
throw coreutils::Exception("Private key does not match certificate."); throw coreutils::Exception("Private key does not match certificate.");
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(ctx, 1); SSL_CTX_set_verify_depth(ctx, 1);
if(!SSL_CTX_load_verify_locations(ctx, tlsInfo->cACertificate.c_str(), NULL)) if(!SSL_CTX_load_verify_locations(ctx, tlsInfo->cACertificate.c_str(), NULL))
throw coreutils::Exception("Cannot verify locations."); throw coreutils::Exception("Cannot verify locations.");
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(tlsInfo->cACertificate.c_str())); SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(tlsInfo->cACertificate.c_str()));
coreutils::Log(coreutils::LOG_INFO) << "Server key authenticated."; coreutils::Log(coreutils::LOG_INFO) << "Server key authenticated.";
} }
} }
void TLS::registerSocket(int fd) { void TLS::registerSocket(int fd) {
initialized = true; initialized = true;
int ret; int ret;
coreutils::Log(coreutils::LOG_DEBUG_3) << "TLS socket initializing on socket " << fd << "..."; coreutils::Log(coreutils::LOG_DEBUG_3) << "TLS socket initializing on socket " << fd << "...";
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
ssl = SSL_new(ctx); ssl = SSL_new(ctx);
// if(ssl <= 0) // if(ssl <= 0)
// throw std::string("Error creating new TLS socket."); // throw std::string("Error creating new TLS socket.");
SSL_set_info_callback(ssl, handshake_complete); SSL_set_info_callback(ssl, handshake_complete);
if((ret = SSL_set_fd(ssl, fd)) == 0) if((ret = SSL_set_fd(ssl, fd)) == 0)
throw std::string("Error setting TLS socket descriptor."); throw std::string("Error setting TLS socket descriptor.");
// if(!SSL_set_generate_session_id(ssl, generate_session_id)) // if(!SSL_set_generate_session_id(ssl, generate_session_id))
// throw std::string("Error setting session identifier callback."); // throw std::string("Error setting session identifier callback.");
} }
void TLS::acceptSocket() { void TLS::acceptSocket() {
switch (SSL_get_error(ssl, SSL_accept(ssl))) { switch (SSL_get_error(ssl, SSL_accept(ssl))) {
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SSL on ssl_accept. errno=" << errno; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SSL on ssl_accept. errno=" << errno;
break; break;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_READ on ssl_accept."; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_READ on ssl_accept.";
break; break;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_WRITE on ssl_accept."; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_WRITE on ssl_accept.";
break; break;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SYSCALL on ssl_accept. errno=" << errno; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SYSCALL on ssl_accept. errno=" << errno;
// shutdown(); // shutdown();
break; break;
default: default:
coreutils::Log(coreutils::LOG_DEBUG_3) << "Unknown ERROR on ssl_accept."; coreutils::Log(coreutils::LOG_DEBUG_3) << "Unknown ERROR on ssl_accept.";
break; break;
} }
} }
void TLS::receiveData(coreutils::ZString &buffer) { int TLS::receiveData(coreutils::ZString &buffer) {
int len; int len;
std::cout << "receiveData TLS" << std::endl; coreutils::Log(coreutils::LOG_DEBUG_3) << "receiveData TLS on socket.";
if((len = ::SSL_read(ssl, buffer.getData(), buffer.getLength())) >= 0) { if((len = ::SSL_read(ssl, buffer.getData(), buffer.getLength())) >= 0) {
std::cout << "receiveData TLS...len=" << len << ":" << buffer << std::endl; coreutils::Log(coreutils::LOG_DEBUG_3) << "receiveData TLS...len=" << len;
// onDataReceived(buffer); return len;
} }
else { else {
switch (SSL_get_error(ssl, len)) { switch (SSL_get_error(ssl, len)) {
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SSL on ssl_read. error=" << errno; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SSL on ssl_read. error=" << errno;
break; break;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_READ on ssl_read."; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_READ on ssl_read.";
break; break;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_WRITE on ssl_read."; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_WRITE on ssl_read.";
break; break;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SYSCALL on ssl_read. errno=" << errno; coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SYSCALL on ssl_read. errno=" << errno;
break; break;
default: default:
coreutils::Log(coreutils::LOG_DEBUG_3) << "Unknown ERROR on ssl_read."; coreutils::Log(coreutils::LOG_DEBUG_3) << "Unknown ERROR on ssl_read.";
break; break;
} }
} return -1;
}
}
}
}
int TLS::sendData(const char *data, int length) {
int len;
if((len = ::SSL_write(ssl, data, length)) >= 0) {
coreutils::Log(coreutils::LOG_DEBUG_3) << "sendData TLS...len=" << len;
return len;
}
else {
switch (SSL_get_error(ssl, len)) {
case SSL_ERROR_SSL:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SSL on ssl_write. error=" << errno;
break;
case SSL_ERROR_WANT_READ:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_READ on ssl_write.";
break;
case SSL_ERROR_WANT_WRITE:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_WANT_WRITE on ssl_write.";
break;
case SSL_ERROR_SYSCALL:
coreutils::Log(coreutils::LOG_DEBUG_3) << "ERROR_SYSCALL on ssl_write. errno=" << errno;
break;
default:
coreutils::Log(coreutils::LOG_DEBUG_3) << "Unknown ERROR on ssl_write.";
break;
}
return -1;
}
}
}
+68 -67
View File
@@ -1,67 +1,68 @@
#ifndef __TLS_h__ #ifndef __TLS_h__
#define __TLS_h__ #define __TLS_h__
#include "ZString.h" #include "ZString.h"
#include "TLSInfo.h" #include "TLSInfo.h"
#include <openssl/ssl.h> #include <openssl/ssl.h>
namespace core { namespace core {
/// ///
/// TLS /// TLS
/// ///
/// This object provides the support methods to handle TLS on the server core and /// This object provides the support methods to handle TLS on the server core and
/// session environment. /// session environment.
/// ///
class TLS { class TLS {
public: public:
/// ///
/// ///
/// ///
TLS(); TLS();
/// ///
/// Use this constructor when the SSL context needs to be created as when opening /// Use this constructor when the SSL context needs to be created as when opening
/// a server TCPSocket. /// a server TCPSocket.
/// ///
TLS(TLSInfo *tlsInfo); TLS(TLSInfo *tlsInfo);
/// ///
/// Use this constructor on creation of a new TCPSocket that needs access to /// Use this constructor on creation of a new TCPSocket that needs access to
/// the generating server's SSL context. /// the generating server's SSL context.
/// ///
TLS(SSL_CTX *ctx); TLS(SSL_CTX *ctx);
/// ///
/// The destructor for this object. /// The destructor for this object.
/// ///
~TLS(); ~TLS();
void createContext(TLSInfo *tlsInfo); void createContext(TLSInfo *tlsInfo);
SSL_CTX *ctx; SSL_CTX *ctx;
protected: protected:
void receiveData(coreutils::ZString &buffer); int receiveData(coreutils::ZString &buffer);
void registerSocket(int fd); int sendData(const char *data, int length);
void acceptSocket(); void registerSocket(int fd);
void acceptSocket();
private:
char *sip_cacert = (char *)"../testkeys/certs/pbxca.crt"; private:
char *sip_cert = (char *)"../testkeys/certs/pbxserver.crt"; char *sip_cacert = (char *)"../testkeys/certs/pbxca.crt";
char *sip_key = (char *)"../testkeys/certs/pbxserver.key"; char *sip_cert = (char *)"../testkeys/certs/pbxserver.crt";
bool initialized = false; char *sip_key = (char *)"../testkeys/certs/pbxserver.key";
SSL *ssl; bool initialized = false;
SSL *ssl;
};
};
}
}
#endif
#endif