My apologies to Corona688 and others following this.
Please remember, over 90% of this is Lrrr's code as found here.
epoll_wait: Linux sockets example
I've commented out moving fd BACK to where it had recently been taken FROM and it seems to work great.
I've also found one spot to free the SessionData and plug the memory leak.
// 10,000 to solve C10K problem, yes? YES. see http://lse.sourceforge.net/epoll/
#define EPOLL_ARRAY_SIZE 64
void sprint_buffer(const char *buffer, int size)
{
int i;
for (i = 0; i < size; i++)
{
if (isprint(buffer))
printf("%c", buffer);
else
printf("\\0x%02X", buffer);
}
}
struct SessionData
{
int FileDescriptor;
int Data1;
int Data2;
int Data3;
};
void Tests()
{
//http://epollwait.blogspot.com/2010/11/linux-sockets-example.html
//
//int main(int argc, char *argv[])
//{
int sd, efd, clientsd, fd; // socket descriptor, epoll file descriptor, client socket descriptor, file descriptor
struct sockaddr_in bindaddr, peeraddr;
socklen_t salen = sizeof(peeraddr);
int pollsize = 1;
struct epoll_event ev;
struct epoll_event epoll_events[EPOLL_ARRAY_SIZE];
uint32_t events;
//unsigned short port = 20000;
unsigned short port = 3333;
int i, rval, on = 1;
ssize_t rc;
char buffer[1024];
struct SessionData * SessionData;
efd = epoll_create(pollsize);
if (efd < 0)
{
printf("Could not create the epoll fd: %m");
//return 1;
return;
}
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0)
{
printf("Could not create new socket: %m\n");
//return 2;
return ;
}
printf("New socket created with sd %d\n", sd);
if (fcntl(sd, F_SETFL, O_NONBLOCK))
{
printf("Could not make the socket non-blocking: %m\n");
close(sd);
//return 3;
return ;
}
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
{
printf("Could not set socket %d option for reusability: %m\n", sd);
close(sd);
//return 4;
return ;
}
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_family= AF_INET;
bindaddr.sin_port = htons(port);
if (bind(sd, (struct sockaddr *) &bindaddr, sizeof(struct sockaddr_in)) < 0)
{
printf("Could not bind socket %d to address 'INADDR_ANY' and port %u: %m", sd, port);
close(sd);
//return 5;
return ;
}
else
{
printf("Bound socket %d to address 'INADDR_ANY' and port %u\n", sd, port);
}
if (listen(sd, SOMAXCONN))
{
printf("Could not start listening on server socket %d: %m\n", sd);
goto cleanup;
}
else
{
printf("Server socket %d started listening to address 'INADDR_ANY' and port %u\n", sd, port);
}
ev.events = EPOLLIN;
//ev.data.u64 = 0LL; // 0 Long Long
//ev.data.fd = sd;
SessionData = malloc(sizeof(SessionData));
SessionData->FileDescriptor = sd;
//SessionData->Data1 = 1;
//SessionData->Data2 = 2;
//SessionData->Data3 = 3;
ev.data.ptr = SessionData;
//ev.data.ptr = 0;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sd, &ev) < 0)
{
printf("Couldn't add server socket %d to epoll set: %m\n", sd);
goto cleanup;
}
for (;;)
{
//ReWait:
printf("Starting epoll_wait on %d fds\n", pollsize);
//while ((rval = epoll_wait(efd, epoll_events, EPOLL_ARRAY_SIZE, -1)) < 0)
while ((rval = epoll_wait(efd, epoll_events, EPOLL_ARRAY_SIZE, 10000)) < 0) // 10 second timeout
{
if ((rval < 0) && (errno != EINTR))
{
printf("EPoll on %d fds failed: %m\n", pollsize);
goto cleanup;
}
}
//if we include a timeout
if (rval == 0)
{
// handle timeout and return to wait
printf("EPoll timeout\n");
//goto ReWait;
}
for (i = 0; i < rval; i++)
{
events = epoll_events.events;
//fd = epoll_events.data.fd;
fd = ((struct SessionData *) epoll_events.data.ptr)->FileDescriptor;
if (events & EPOLLERR)
{
if (fd == sd)
{
printf("EPoll on %d fds failed: %m\n", pollsize);
// could free SessionData here but why bother?
goto cleanup;
} else
{
printf("Closing socket with sd %d\n", fd);
shutdown(fd, SHUT_RDWR);
close(fd);
free(((struct SessionData *) epoll_events.data.ptr)); // is free needed anywhere else?
continue;
}
}
if (events & EPOLLWAKEUP) // MY ADDITION
{
printf("EPoll timeout\n");
}
if (events & EPOLLHUP)
{
if (fd == sd)
{
printf("EPoll on %d fds failed: %m\n", pollsize);
goto cleanup;
} else
{
printf("Closing socket with sd %d\n", fd);
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (events & EPOLLRDHUP)
{
if (fd == sd)
{
printf("EPoll on %d fds failed: %m\n", pollsize);
goto cleanup;
} else
{
printf("Closing socket with sd %d\n", fd);
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (events & EPOLLOUT)
{
if (fd != sd)
{
//rc = snprintf(buffer, sizeof(buffer), "Hello socket %d from server socket %d!\n", fd, sd);
//rc = snprintf(buffer, sizeof(buffer), "Hello socket %d from server socket %d!\n", fd, sd);
//rc = snprintf(buffer, sizeof(buffer), "Hello socket %d from server socket %d!\n", fd, sd);
//rc = snprintf(buffer, sizeof(buffer), "Hello socket %d from server socket %d!\n", fd, sd);
rc = snprintf(buffer, sizeof(buffer), "Hello socket %d from server socket %d! Session data: %d\n", fd, sd, ((struct SessionData *) epoll_events.data.ptr)->Data1 ++);
while ((rc = send(fd, buffer, rc, 0)) < 0)
{
if ((fd < 0) && (errno != EINTR))
{
printf("Send to socket %d failed: %m\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (rc == 0)
{
printf("Closing socket with sd %d\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
} else if (rc > 0)
{
printf("Sent '");
sprint_buffer(buffer, rc);
printf("' to socket with sd %d\n", fd);
ev.events = EPOLLIN;
//ev.data.u64 = 0LL;
//ev.data.fd = fd;
//(struct SessionData *) ev.data.ptr->FileDescriptor = fd;
// ((struct SessionData *) ev.data.ptr)->FileDescriptor = fd;
if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev) < 0)
{
printf("Couldn't modify client socket %d in epoll set: %m\n", fd);
goto cleanup;
}
}
}
}
if (events & EPOLLIN)
{
if (fd == sd)
{
while ((clientsd = accept(sd, (struct sockaddr *) &peeraddr, &salen)) < 0)
{
if ((clientsd < 0) && (errno != EINTR))
{
printf("Accept on socket %d failed: %m\n", sd);
goto cleanup;
}
}
if (inet_ntop(AF_INET, &peeraddr.sin_addr.s_addr, buffer, sizeof(buffer)) != NULL)
{
printf("Accepted connection from %s:%u, assigned new sd %d\n", buffer, ntohs(peeraddr.sin_port), clientsd);
} else
{
printf("Failed to convert address from binary to text form: %m\n");
}
ev.events = EPOLLIN;
//ev.data.u64 = 0LL;
//ev.data.fd = clientsd;
//((struct SessionData *) ev.data.ptr)->FileDescriptor = clientsd;
SessionData = malloc(sizeof(SessionData));
SessionData->FileDescriptor = clientsd;
SessionData->Data1 = 1;
SessionData->Data2 = 2;
SessionData->Data3 = 3;
ev.data.ptr = SessionData;
if (epoll_ctl(efd, EPOLL_CTL_ADD, clientsd, &ev) < 0)
{
printf("Couldn't add client socket %d to epoll set: %m\n", clientsd);
goto cleanup;
}
pollsize++;
} else
{
while ((rc = recv(fd, buffer, sizeof(buffer), 0)) < 0)
{
if ((fd < 0) && (errno != EINTR))
{
printf("Receive from socket %d failed: %m\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (rc == 0)
{
printf("Closing socket with sd %d\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
} else if (rc > 0)
{
//printf("Received '");
//printf("Received '");
//printf("Received '");
//printf("Received '");
//printf("Received '");
printf("Received '");
sprint_buffer(buffer, rc);
printf("' from socket with sd %d\n", fd);
ev.events = EPOLLIN | EPOLLOUT;
//ev.data.u64 = 0LL;
//ev.data.fd = fd;
// ((struct SessionData *) ev.data.ptr)->FileDescriptor = fd;
if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev) < 0)
{
printf("Couldn't modify client socket %d in epoll set: %m\n", fd);
goto cleanup;
}
}
}
}
}
}
cleanup:
shutdown(sd, SHUT_RDWR);
close(sd);
return ;