Reputation: 11
I'm writing a simple webserver in cpp 98 when i receive a keep-alive request i didn't close the socket and recycle it (as you can see in the if statement reported here). The event is already set to EPOLLIN so the epoll_wait give me it back and after some read(recv) with zero byte the server terminate is execution. if i resend a request on the same sock of the keep-alive with connection close header all is good. I've to simply remove the event(epoll_ctl EPOLL_CTL_DELL)? but the socket is already accepted i don't understand which is the right way to handle event with "keep-alive" header (i know all header from http1.1 request is keep-alive)
this is the mainloop:
bool Webserver::_mainLoop() {
int eventNumber=0;
epoll_event events[MAX_EVENTS];
do{
// std::cout<<"main loop"<<std::endl;
eventNumber= epoll_wait(this->_epollFd,events,MAX_EVENTS,EPOLL_TIMEOUT);
std::cout<<RED<<"event number: "<<eventNumber<<RESET_COLOR<<std::endl;
if(eventNumber>0)
{
if(!_handleEpollEvents(eventNumber,events)) {
std::cout<<RED<<"Error handling epoll events"<<RESET_COLOR<<std::endl;
return false;
}
}
} while (eventNumber>=0);
std::cout<<RED<<"out of do while loop"<<RESET_COLOR<<std::endl;
if(eventNumber<0) {
std::cout<<RED<<"Error epoll wait"<<RESET_COLOR<<std::endl;
return false;
}
}
and this the handle event:
bool Webserver::_handleEpollEvents(int &eventNumber, epoll_event (&events)[MAX_EVENTS]) {
std::cout<<BLUE<<"handling epoll events"<<RESET_COLOR<<std::endl;
for (int i = 0; i < eventNumber; ++i)
{
std::cout<<"handling event number: "<<i<<std::endl;
sType *type =static_cast<sType*>(events[i].data.ptr);
if(type->socketType==SERVER_SOCK)
{
Server *server = static_cast<Server *>(events[i].data.ptr);
if(!this->_acceptConnection(server))
{
std::cout<<"Error accepting connection"<<std::endl;
return false;
}
}else if(((events[i].events & EPOLLIN) || (events[i].events & EPOLLOUT)) && _handleConnection(events[i]) )
{
std::cout<<YELLOW<<"out of handling connection"<<RESET_COLOR<<std::endl;
return true;
}
}
return true;
}
and this is what i do now to handle keep-alive inside the handle connection function:
if(client.request()->connection()=="keep-alive"&& client.response()->complete()) {
std::cout<<GREEN<<"Connection keep-alive"<<RESET_COLOR<<std::endl;
if(client.request()){
delete client.request();
client.set_request(NULL);
}
if(client.response()){
delete client.response();
client.set_response(NULL);
}
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
int flags = fcntl(client.getClientSock()->getFdSock(), F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(client.getClientSock()->getFdSock(), F_SETFL, flags);
if (setsockopt(client.getClientSock()->getFdSock(), SOL_SOCKET, SO_KEEPALIVE,(char *) &tv, sizeof(tv)) ==SOCKET_ERROR) {
std::cout<<RED << "cannot set socket option" << RESET_COLOR<<std::endl;
return false;
}
every time i read(recv) i change with EPOLL_CTL_MOD from epollin to epollout and viceversa for every time i write(send)
this is a snippet of what happen when i run it with a keep-alive get request to an index.html:
send 3251 bytes
Response ended set to epollin
k e e p - a l i v e
Connection keep-alive
Request : Destructor Called
Response : Destructor Called
out of handling connection
event number: 1
handling epoll events
handling event number: 0
handling connection
Request : Default Constructor Called
Response : Default Constructor Called
receiving data
client socket fd: 10
client socket service: 8090
client socket service: 127.1.0.1
client socket size: 16
Service sin family: 2
read 0 byte
Request ended set to epollout
response status code: 204client request connection:
The socket is in non-blocking mode
response:
�^ response size:4
send 4 bytes
Response ended set to epollin
response complete: truerequest error: false
connection: complete: true
event number: 1
handling epoll events
handling event number: 0
handling connection
ptr->socketType: 2
socket type: 2
Request : Default Constructor Called
Response : Default Constructor Called
receiving data
client socket fd: 10
client socket service: 8090
client socket service: 127.1.0.1
client socket size: 16
Service sin family: 2
read 0 byte
Request ended set to epollout
response status code: 204client request connection:
The socket is in non-blocking mode
response:
�^ response size:4
and after this it stopped the execution if is needed the code is on a public repo on github but i don't know if i can post the link maybe the 4 bytes sent in response is a pointer not nulled? don't know
Upvotes: 0
Views: 64
Reputation: 123531
It is very hard to understand what you want. But you seem to assume that the "Connection: keep-alive" header in a HTTP request means some keep-alive "event" which the server needs to immediately respond to whenever it occurs.
This assumption is wrong. HTTP keep-alive is not some kind of heartbeat which expects a response. It just informs the server that the client can handle multiple requests within the same TCP connection. This means that the server might (not must) keep the TCP connection open (for some time) after the HTTP response was send in order to receive another HTTP request from the client. Note that the client does not even need to specify this header in all cases, it is needed with HTTP/1.0 but implicit with HTTP/1.1.
Upvotes: 1