#include "EPoll.h" #include "Socket.h" #include "Exception.h" #include "Log.h" namespace core { Socket::Socket(EPoll &ePoll) : ePoll(ePoll) { coreutils::Log(coreutils::LOG_DEBUG_2) << "BMASocket object created."; buffer = (char *)malloc(4096); length = 4096; } Socket::~Socket() { ePoll.unregisterSocket(this); close(descriptor); free(buffer); onUnregister(); } void Socket::setDescriptor(int descriptor) { coreutils::Log(coreutils::LOG_DEBUG_3) << "Descriptor set to " << descriptor << " for Socket."; if(descriptor < 3) throw coreutils::Exception("Descriptor out of range", __FILE__, __LINE__); this->descriptor = descriptor; onRegister(); ePoll.registerSocket(this); onRegistered(); } int Socket::getDescriptor() { return descriptor; } void Socket::setBufferSize(int length) { buffer = (char *)realloc(buffer, length); this->length = length; } void Socket::onRegister() {} void Socket::onRegistered() {} void Socket::onUnregister() {} void Socket::eventReceived(struct epoll_event event) { if(event.events & EPOLLRDHUP) { readHangup = true; enable(false); shutdown(); return; } if(event.events & EPOLLIN) receiveData(buffer, length); if(event.events & EPOLLOUT) writeSocket(); if(event.events & EPOLLHUP) { shutdown(); return; } enable(true); } void Socket::enable(bool mode) { if(mode) { if(fifo.empty()) { if(!readHangup) { active ? resetRead(): setRead(); } } else { active ? resetReadWrite(): setReadWrite(); } active = true; } else clear(); } void Socket::receiveData(char *buffer, int bufferLength) { if(bufferLength <= 0) throw coreutils::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 coreutils::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() { 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() { coreutils::Log(coreutils::LOG_DEBUG_2) << "Shutdown requested on socket " << descriptor << "."; shutDown = true; enable(false); delete this; } }