|
CS473 - Computer Networks
| Displaying exercises/e8a/solution/server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 47350
#define K 1024
typedef enum { ST_GETUSERNAME, ST_GETPASSWD, ST_AUTHENTICATED } cstate_t;
struct client {
int fd, dead;
cstate_t state;
struct client *next;
} *clients;
void newclient(int epfd, int sock) {
struct client *c;
int fd;
fd = accept(sock, NULL, NULL);
if (fd < 0) {
perror("accept");
return;
}
printf("New connection on %d\n", fd);
c = malloc(sizeof(struct client));
c->fd = fd;
c->dead = 0;
c->state = ST_GETUSERNAME;
c->next = clients;
clients = c;
watch(epfd, fd);
write(fd, "Login: ", 7);
}
struct client *disconnect(struct client *dead) {
struct client *c, *p;
for(p = c = clients; c; c = c->next) {
if (c == dead) break;
p = c;
}
printf("Disconnecting %d\n", dead->fd);
if (p == dead) clients = dead->next;
else p->next = dead->next;
p = dead->next;
close(dead->fd);
remove(epfd, dead->fd);
free(dead);
return p;
}
void broadcast(int from, char *msg, int len) {
struct client *c = clients;
printf("->%d) %.*s", from, len, msg);
for(c=clients; c != NULL; c=c->next) {
if (c->dead || from == c->fd) continue;
if (write(c->fd, msg, len) < 0) c->dead = 1;
}
}
void watch(int epfd, int fd) {
struct epoll_event epv = { .events = EPOLLIN, .data.fd = fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epv);
}
void remove(int epfd, int fd) {
struct epoll_event epv;
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &epv);
}
int main(int argc, char *argv[])
{
struct epoll_event epv;
struct sockaddr_in server;
struct client *c;
char buf[K];
int sock, r;
fd_set rfds;
clients = NULL;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(1);
}
r = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &r, sizeof(r)) < 0)
perror("setsockopt");
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
if (bind(sock, (struct sockaddr *)&server, sizeof(server))) {
perror("bind");
exit(1);
}
if (listen(sock, 5) < 0) {
perror("listen");
exit(1);
}
watch(epfd, sock);
printf("Server starting...\n");
for(;;) {
r = select(highfd, &rfds, NULL, NULL, NULL);
if (r < 0) perror("select");
if (r <= 0) continue;
if (FD_ISSET(sock, &rfds)) newclient(sock);
for(c=clients; c;) {
if (c->dead) {
c = disconnect(c);
continue;
}
if (FD_ISSET(c->fd, &rfds)) {
r = read(c->fd, buf, K);
if (r <= 0) {
c = disconnect(c);
continue;
}
broadcast(c->fd, buf, r);
}
c = c->next;
}
}
// Not reached:
return 0;
}
|