This repository has been archived on 2024-07-04. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
khet/src/net.c

151 lines
3.4 KiB
C

/* -*- c-basic-offset: 4 -*- */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include "net.h"
#define MAX_CLIENTS 2
#define SRV_FDS 1
int servsock;
struct pollfd pollfds[SRV_FDS+MAX_CLIENTS];
int nclients = 0;
FILE *net_side[2];
int
errx(int eval, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(eval);
}
void
net_server(int port) {
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(port);
servsock=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (servsock<0)
errx(1, "socket: %s\n", strerror(errno));
int r;
do r=bind(servsock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
while ((r<0) && (errno==EADDRINUSE));
if (r < 0)
errx(1, "bind port %d: %s\n", port, strerror(errno));
if (listen(servsock, 10) < 0)
errx(1, "listen: %s\n", strerror(errno));
#if 1
// FIXME Temporary startup. Use net_poll for this later:
printf("Waiting for connections...\n");
for (int i=0; i<2; i++) {
struct sockaddr_in clientaddr;
int cfd;
socklen_t slen;
FILE *f;
cfd=accept(servsock, (struct sockaddr *)&clientaddr, &slen);
if (cfd<0)
errx(1, "accept: %s\n", strerror(errno));
// FIXME log, shout, or something
printf("client log on...\n");
f = fdopen(cfd, "r+");
if (!f)
errx(1, "fdopen: %s\n", strerror(errno));
setlinebuf(f);
fprintf(f, "Welcome!\n");
if (i==0)
fprintf(f, "Waiting for another player...\n");
fflush(f);
net_side[i]=f;
}
net_all_printf("Starting game\n");
#else
pollfds[0].fd=servsock;
pollfds[0].events=POLLIN|POLLERR|POLLHUP;
for (int i=SRV_FDS; i<(SRV_FDS+MAX_CLIENTS); i++) {
pollfds[0].fd=-1;
pollfds[0].events=0;
}
#endif
}
void
net_all_flush() {
for (int i=0; i<2; i++)
fflush(net_side[i]);
}
void
net_all_printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
for (int i=0; i<2; i++)
vfprintf(net_side[i], fmt, ap);
va_end(ap);
}
void
net_side_printf(int side, const char *fmt, ...) {
va_list ap;
assert((side==0) || (side==1));
va_start(ap, fmt);
vfprintf(net_side[side], fmt, ap);
va_end(ap);
}
void
net_poll() {
int npoll;
npoll=poll(pollfds, SRV_FDS+MAX_CLIENTS, -1);
if (npoll<0)
errx(1, "poll: %s", strerror(errno));
if (pollfds[0].revents) {
struct sockaddr_in clientaddr;
int cfd;
socklen_t slen;
cfd=accept(servsock, (struct sockaddr *)&clientaddr, &slen);
if (cfd<0)
errx(1, "accept: %s", strerror(errno));
// FIXME log, shout, or something
if (nclients>MAX_CLIENTS) {
#define STR_SERVER_FULL "Sorry, the server is full"
write(cfd, STR_SERVER_FULL, sizeof(STR_SERVER_FULL)-1);
close(cfd);
} else {
int i;
for (i=SRV_FDS; i<(SRV_FDS+MAX_CLIENTS); i++)
if (pollfds[i].fd==-1) break;
pollfds[i].fd=cfd;
pollfds[i].events=POLLIN|POLLERR|POLLHUP;
nclients++;
}
npoll--;
}
for (int i=SRV_FDS; npoll && i<(SRV_FDS+MAX_CLIENTS); i++) {
if (pollfds[SRV_FDS+i].revents) {
int n;
char buf[100];
n=read(pollfds[SRV_FDS+i].fd, &buf, sizeof(buf));
// parse buf
// handle disconnections
}
}
}