Skip to content

Instantly share code, notes, and snippets.

@mrpossoms
Created September 17, 2018 13:54
Show Gist options
  • Save mrpossoms/48b0bf825239df352435da09e1c340af to your computer and use it in GitHub Desktop.
Save mrpossoms/48b0bf825239df352435da09e1c340af to your computer and use it in GitHub Desktop.
detect connection closure
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define ME "[server] "
void add(int* list, int* size, int val)
{
list[(*size)++] = val;
}
void delete(int* list, int* size, int idx)
{
list[idx] = list[*size - 1];
(*size)--;
}
void child_echo(int sock)
{
while(1)
{
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
switch(select(sock + 1, &rfds, NULL, NULL, NULL))
{
case 0:
continue;
case -1:
fprintf(stderr, ME "select error %d\n", errno);
break;
default:
{
char msg_buf[256] = {};
// select will return the closed file descriptor as being
// set. Even if the connection has been closed. So what we
// then do is MSG_PEEK at the queue of the socket. If there
// are no bytes to read, then the connection is closed and
// we can clean up
if (recv(sock, msg_buf, sizeof(msg_buf), MSG_PEEK) == 0)
{
goto done;
}
size_t bytes = read(sock, msg_buf, sizeof(msg_buf));
write(sock, "echo: ", 7);
write(sock, msg_buf, bytes);
}
}
}
done:
fprintf(stderr, ME "connection closed %d\n", errno);
close(sock);
exit(0);
}
int main()
{
int host_fd = socket(PF_INET, SOCK_STREAM, 0);
int client_fds[10] = {};
int client_idx = 0;
{ // bind to port, get address
const struct sockaddr_in name = {
.sin_family = AF_INET,
.sin_port = htons(1337),
.sin_addr.s_addr = htonl(INADDR_ANY),
};
if (bind(host_fd, (const struct sockaddr*)&name, sizeof(name)))
{
fprintf(stderr, ME "Error binding %d\n", errno);
return __COUNTER__;
}
}
if (listen(host_fd, 10))
{
fprintf(stderr, ME "Error listening %d", errno);
return __COUNTER__;
}
fprintf(stderr, ME "listening\n");
while(1)
{
struct sockaddr_in client_name = {};
socklen_t client_name_len = 0;
int fd = accept(host_fd, (struct sockaddr*)&client_name, &client_name_len);
add(client_fds, &client_idx, fd);
fprintf(stderr, ME "connection accepted\n");
pid_t pid = fork();
if (pid == 0)
{
child_echo(fd);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment