Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions includes/Server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Server {
void removeClientSocketPfd_(int const fd, std::string const &msg);
void storePollFd_(int const socketFd, bool srvSocket);
void removePollFd_(int const fd);
void setPolloutInterest_(int const fd);
void log_(std::string const &msg, Logger::logMode const lm);

Server(Server const &other);
Expand Down
2 changes: 2 additions & 0 deletions includes/Socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class Socket {
bool checkSocketData(int const fd);
std::string getCRLFLineFromBuffer(int const fd, bool &buffHasMoreCmds,
bool &msgTooLong);
bool hasPendingWrite(int const fd);
bool flushWriteBuffer(int const fd);
void sendMsg(int const fd, std::string const &msg);
bool socketCloseMarker(int const fd);
void closeSocket(int const fd);
Expand Down
19 changes: 19 additions & 0 deletions srcs/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ void Server::processClientSockets_() {
continue;
}

if (pfd.revents & (POLLOUT))
sockets_.flushWriteBuffer(pfd.fd);
setPolloutInterest_(pfd.fd);

if (!(pfd.revents & (POLLIN | POLLERR | POLLHUP)))
continue;

Expand Down Expand Up @@ -211,6 +215,10 @@ void Server::removeClientSocketPfd_(int const fd, std::string const &msg) {
}
clients_.remove(fd, channels_);
}
// TODO: socket is closed without flush. So loop cannot send the message
// Fix line below :
// sockets_.flushWriteBuffer(fd);
// But, is it okay to flush without checking POLLOUT here?
sockets_.closeSocket(fd);
removePollFd_(fd);
}
Expand Down Expand Up @@ -343,6 +351,17 @@ void Server::sendMsg(int const fd, std::string const &msg) {
logger_.logMsg(oss.str(), Logger::lmOut);
}
sockets_.sendMsg(fd, msg);
setPolloutInterest_(fd);
}

void Server::setPolloutInterest_(int const fd) {
std::vector<pollfd>::iterator it =
std::find_if(pollFds_.begin(), pollFds_.end(), srvHelp::PfdHasFd(fd));
if (it == pollFds_.end())
return;
short const pollout = static_cast<short>(POLLOUT);
short const interest = sockets_.hasPendingWrite(fd) ? pollout : 0;
it->events = static_cast<short>((it->events & ~pollout) | interest);
}

#ifdef BONUS
Expand Down
43 changes: 29 additions & 14 deletions srcs/server/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,37 +121,52 @@ size_t Socket::bufferLengthAndSanityCheck_(SocketIOData &sIOD, bool &msgTooLong,
return std::string::npos;
}

bool Socket::hasPendingWrite(int const fd) {
SocketIOData *sIODptr = getSockIOData(fd);
return sIODptr && !sIODptr->closeFd && !sIODptr->writeBuffer.empty();
}

// return true if nothing to write
// returns false on error
bool Socket::flushWriteBuffer(int const fd) {
SocketIOData *sIODptr = getSockIOData(fd);
if (!sIODptr)
return true;
SocketIOData &sIOD = *sIODptr;
while (!sIOD.writeBuffer.empty() && !sIOD.closeFd) {
ssize_t bytesSent = send(fd, sIOD.writeBuffer.c_str(),
sIOD.writeBuffer.length(), MSG_NOSIGNAL);
if (bytesSent > 0) {
sIOD.writeBuffer.erase(0, static_cast<size_t>(bytesSent));
continue;
}
// No errror count to make sure slow clients are not killed.
// Errors EAGAIN/EWOULDBLOCK are acceptable
return false;
}
return sIOD.writeBuffer.empty();
}

/*
sendMsg
* send string msg to a network socket
* uses i/o buffers and error counters in SocketIOData
* only queue no send. sent in poll loop after checking POLLOUT
*/
void Socket::sendMsg(int const fd, std::string const &msg) {
SocketIOData *sIODptr = getSockIOData(fd);
if (!sIODptr)
return;

SocketIOData &sIOD = *sIODptr;
if (sIOD.closeFd)
return;
if (msg.length() >
sIOD.writeBuffer.max_size() - sIOD.writeBuffer.length()) {
sIOD.closeFd = true;
return;
}
sIOD.writeBuffer += msg;
ssize_t bytesSent = send(fd, sIOD.writeBuffer.c_str(),
sIOD.writeBuffer.length(), MSG_NOSIGNAL);
if (bytesSent <= 0) {
++sIOD.sendErrorCount;
if (sIOD.sendErrorCount >= SOCKETERRORLIMIT)
sIOD.closeFd = true;
return;
}

sIOD.sendErrorCount = 0;
if (static_cast<size_t>(bytesSent) < sIOD.writeBuffer.length())
sIOD.writeBuffer.erase(0, bytesSent);
else
sIOD.writeBuffer.clear();
}

bool Socket::socketCloseMarker(int const fd) {
Expand Down
Loading