ServerCore/Socket.cpp
2019-02-07 13:28:21 -08:00

193 lines
5.3 KiB
C++

#include "EPoll.h"
#include "Socket.h"
#include "Exception.h"
#include "Log.h"
namespace core {
Socket::Socket(EPoll &ePoll) : ePoll(ePoll) {
Log(LOG_DEBUG_2) << "BMASocket object created.";
Log(LOG_DEBUG_3) << "Buffer size set to default (4096).";
buffer = (char *)malloc(4096);
length = 4096;
}
Socket::~Socket() {
ePoll.unregisterSocket(this);
close(descriptor);
free(buffer);
}
void Socket::setDescriptor(int descriptor) {
Log(LOG_DEBUG_3) << "Descriptor set to " << descriptor << " for Socket.";
if(descriptor < 3)
throw Exception("Descriptor out of range", __FILE__, __LINE__);
this->descriptor = descriptor;
onTLSInit();
}
int Socket::getDescriptor() {
return descriptor;
}
void Socket::onTLSInit() {}
void Socket::setBufferSize(int length) {
buffer = (char *)realloc(buffer, length);
this->length = length;
}
void Socket::onRegistered() {
onConnected();
}
void Socket::onUnregistered() {
// onDisconnected();
}
void Socket::eventReceived(struct epoll_event event) {
// std::stringstream stream;
// stream << "Event received on socket " << event.data.fd << ": ";
// if(event.events & EPOLLRDHUP) stream << "EPOLLRDHUP ";
// if(event.events & EPOLLIN) stream << "EPOLLIN ";
// if(event.events & EPOLLOUT) stream << "EPOLLOUT ";
// if(event.events & EPOLLERR) stream << "EPOLLERR ";
// stream << "[" << event.events << "]";
// BMALog(LOG_DEBUG_4) << stream.str();
//
if(event.events & EPOLLRDHUP) {
Log(LOG_DEBUG_2) << "Socket " << descriptor << " received disconnect from client.";
shutdown();
return;
}
if(event.events & EPOLLIN)
receiveData(buffer, length);
if(event.events & EPOLLOUT)
writeSocket();
enable(true);
}
void Socket::enable(bool mode) {
if(mode) {
if(fifo.empty())
active ? resetRead(): setRead();
else
active ? resetReadWrite(5): setReadWrite();
active = true;
}
else
clear();
}
void Socket::receiveData(char *buffer, int bufferLength) {
if(bufferLength <= 0)
throw Exception("Request to receive data with a zero buffer length.", __FILE__, __LINE__, -1);
int len;
int error = -1;
if((len = ::read(getDescriptor(), buffer, bufferLength)) >= 0)
onDataReceived(std::string(buffer, len));
else {
error = errno;
switch (error) {
// When a listening socket receives a connection
// request we get one of these.
//
case ENOTCONN:
onDataReceived(std::string(buffer, 0));
break;
case ECONNRESET:
break;
default:
throw Exception("Error in read of data from socket.", __FILE__, __LINE__, error);
}
}
}
void Socket::onConnected() {
}
void Socket::writeSocket() {
lock.lock();
if(fifo.size() > 0) {
::write(descriptor, fifo.front().c_str(), fifo.front().length());
fifo.pop();
enable(true);
}
lock.unlock();
}
void Socket::write(std::string data) {
lock.lock();
fifo.emplace(data);
enable(true);
lock.unlock();
}
void Socket::output(std::stringstream &out) {
out << "|" << descriptor << "|";
}
void Socket::setRead() {
event.data.fd = descriptor;
event.events = EPOLLIN | EPOLLONESHOT | EPOLLRDHUP | EPOLLET;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_DEL, descriptor, NULL);
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_ADD, event.data.fd, &event);
}
void Socket::setWrite() {
event.data.fd = descriptor;
event.events = EPOLLOUT | EPOLLONESHOT | EPOLLRDHUP | EPOLLET;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_DEL, descriptor, NULL);
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_ADD, descriptor, &event);
}
void Socket::setReadWrite() {
event.data.fd = descriptor;
event.events = EPOLLIN | EPOLLWRNORM | EPOLLONESHOT | EPOLLRDHUP | EPOLLET;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_DEL, descriptor, NULL);
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_ADD, descriptor, &event);
}
void Socket::resetRead() {
event.data.fd = descriptor;
event.events = EPOLLIN | EPOLLONESHOT | EPOLLRDHUP | EPOLLET;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_MOD, descriptor, &event);
}
void Socket::resetWrite() {
event.data.fd = descriptor;
event.events = EPOLLOUT | EPOLLONESHOT | EPOLLRDHUP | EPOLLET;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_MOD, descriptor, &event);
}
void Socket::resetReadWrite(int x) {
event.data.fd = descriptor;
event.events = EPOLLIN | EPOLLOUT | EPOLLONESHOT | EPOLLRDHUP | EPOLLET;
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_MOD, descriptor, &event);
}
void Socket::clear() {
epoll_ctl(ePoll.getDescriptor(), EPOLL_CTL_DEL, descriptor, NULL);
}
void Socket::shutdown() {
Log (LOG_DEBUG_2) << "Shutdown requested on socket " << descriptor << ".";
shutDown = true;
enable(false);
delete this;
}
}