Created
September 17, 2018 13:54
-
-
Save mrpossoms/48b0bf825239df352435da09e1c340af to your computer and use it in GitHub Desktop.
detect connection closure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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