Fix network support

Multiple clients can now connect.
(For now two first clients will play)
This commit is contained in:
Steinar Hamre 2008-10-10 23:47:41 +00:00
parent b00565ea66
commit 160e63e91c
4 changed files with 246 additions and 53 deletions

View File

@ -5,11 +5,15 @@ all: server
server: server.o net.o asciiart.o game.o server: server.o net.o asciiart.o game.o
clean: clean:
-rm -f *.o -rm -f server *.o *~
depend:
makedepend *.c -Y. 2>/dev/null
# DO NOT DELETE # DO NOT DELETE
asciiart.o: game.h asciiart.h asciiart.o: game.h asciiart.h
game.o: net.h game.h game.o: net.h game.h
net.o: net.h net.o: net.h server.h
server.o: net.h game.h asciiart.h server.o: net.h game.h asciiart.h

179
src/net.c
View File

@ -13,11 +13,20 @@
#include <assert.h> #include <assert.h>
#include "net.h" #include "net.h"
#include "server.h"
#define MAX_CLIENTS 2 #define MAX_CLIENTS 10
#define SRV_FDS 1 #define SRV_FDS 1
struct client {
int fd;
char buf[BUFSIZ];
int bufend;
int linetoolong;
};
int servsock; int servsock;
struct client clients[MAX_CLIENTS];
struct pollfd pollfds[SRV_FDS+MAX_CLIENTS]; struct pollfd pollfds[SRV_FDS+MAX_CLIENTS];
int nclients = 0; int nclients = 0;
@ -32,6 +41,19 @@ errx(int eval, const char *fmt, ...) {
exit(eval); exit(eval);
} }
/*
void
parse_line(int clientid, char *line) {
printf("line: %d \"%s\"\n", clientid, line);
}
*/
void
parse_linetoolong(int clientid, char *line) {
printf("linetoolong: %d \"%s\"\n", clientid, line);
}
struct file sfile[2]; struct file sfile[2];
void void
@ -55,7 +77,7 @@ net_server(int port) {
errx(1, "bind port %d: %s\n", port, strerror(errno)); errx(1, "bind port %d: %s\n", port, strerror(errno));
if (listen(servsock, 10) < 0) if (listen(servsock, 10) < 0)
errx(1, "listen: %s\n", strerror(errno)); errx(1, "listen: %s\n", strerror(errno));
#if 1 #if 0
// FIXME Temporary startup. Use net_poll for this later: // FIXME Temporary startup. Use net_poll for this later:
printf("Waiting for connections on port %d...\n", port); printf("Waiting for connections on port %d...\n", port);
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
@ -72,18 +94,19 @@ net_server(int port) {
sfile[i].iend=0; sfile[i].iend=0;
sfile[i].oend=0; sfile[i].oend=0;
net_side_printf(i, "Welcome!\n"); net_client_printf(i, "Welcome!\n");
if (i==0) if (i==0)
net_side_printf(i, "Waiting for another player...\n"); net_client_printf(i, "Waiting for another player...\n");
} }
net_all_printf("Starting game\n"); net_all_printf("Starting game\n");
#else #else
pollfds[0].fd=servsock; pollfds[0].fd=servsock;
pollfds[0].events=POLLIN|POLLERR|POLLHUP; pollfds[0].events=POLLIN|POLLERR|POLLHUP;
for (int i=SRV_FDS; i<(SRV_FDS+MAX_CLIENTS); i++) { for (int i=0; i<MAX_CLIENTS; i++) {
pollfds[0].fd=-1; pollfds[SRV_FDS+i].fd=-1;
pollfds[0].events=0; pollfds[SRV_FDS+i].events=0;
} }
printf("Waiting for connections on port %d...\n", port);
#endif #endif
} }
@ -106,11 +129,12 @@ net_all_flush() {
} }
void void
net_side_printf(int side, const char *fmt, ...) { net_client_printf(int clientid, const char *fmt, ...) {
va_list ap; va_list ap;
char buf[BUFSIZ]; char buf[BUFSIZ];
int len, n; int len, n;
assert((side==0) || (side==1)); struct client *c = &clients[clientid];
va_start(ap, fmt); va_start(ap, fmt);
len=vsnprintf(buf, sizeof(buf)-1, fmt, ap); len=vsnprintf(buf, sizeof(buf)-1, fmt, ap);
va_end(ap); va_end(ap);
@ -118,7 +142,7 @@ net_side_printf(int side, const char *fmt, ...) {
errx(1, "BUFSIZ too small\n"); errx(1, "BUFSIZ too small\n");
char *bufp=buf; char *bufp=buf;
do { do {
n=write(sfile[side].fd, bufp, len); n=write(c->fd, bufp, len);
if (n<0) if (n<0)
errx(1, "write: %s\n", strerror(errno)); errx(1, "write: %s\n", strerror(errno));
bufp+=n; bufp+=n;
@ -135,10 +159,11 @@ net_all_printf(const char *fmt, ...) {
va_end(ap); va_end(ap);
if (len > BUFSIZ-1) if (len > BUFSIZ-1)
errx(1, "BUFSIZ too small\n"); errx(1, "BUFSIZ too small\n");
for (int side=0; side<2; side++) { for (int clientid=0; clientid<2; clientid++) {
struct client *c = &clients[clientid];
char *bufp=buf; char *bufp=buf;
do { do {
n=write(sfile[side].fd, bufp, len); n=write(c->fd, bufp, len);
if (n<0) if (n<0)
errx(1, "write: %s\n", strerror(errno)); errx(1, "write: %s\n", strerror(errno));
bufp+=n; bufp+=n;
@ -148,6 +173,8 @@ net_all_printf(const char *fmt, ...) {
#endif #endif
#define min(a,b) ((a<b) ? (a) : (b))
int int
net_getc_fillbuf(struct file *f) { net_getc_fillbuf(struct file *f) {
int n; int n;
@ -174,7 +201,7 @@ net_getc(int side) {
#if 0 #if 0
void void
net_side_flush(int side) { net_client_flush(int side) {
start=0; start=0;
do start+=write(fd[side], obuf[side]+start, obufend); do start+=write(fd[side], obuf[side]+start, obufend);
while (start < obufend); while (start < obufend);
@ -183,16 +210,16 @@ net_side_flush(int side) {
void void
net_all_flush() { net_all_flush() {
for (int i=0; i<2; i++) for (int i=0; i<2; i++)
net_side_flush(i); net_client_flush(i);
} }
static void static void
net_side_vprintf(int side, const char *fmt, va_list ap) { net_client_vprintf(int side, const char *fmt, va_list ap) {
n=vsnprintf(obuf[side], BUFSIZ-obufend, fmt, ap); n=vsnprintf(obuf[side], BUFSIZ-obufend, fmt, ap);
if (n > (BUFSIZ-obufend-1)) { if (n > (BUFSIZ-obufend-1)) {
if (n > BUFSIZ-1) if (n > BUFSIZ-1)
errx(1, "BUFSIZ too small\n"); errx(1, "BUFSIZ too small\n");
net_side_flush(side); net_client_flush(side);
n=vsnprintf(obuf[side], BUFSIZ-obufend, fmt, ap); n=vsnprintf(obuf[side], BUFSIZ-obufend, fmt, ap);
} }
obufend[side]+=n; obufend[side]+=n;
@ -203,20 +230,22 @@ net_all_printf(const char *fmt, ...) {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
for (int i=0; i<2; i++) for (int i=0; i<2; i++)
net_side_vprintf(i, fmt, ap); net_client_vprintf(i, fmt, ap);
va_end(ap); va_end(ap);
} }
void void
net_side_printf(int side, const char *fmt, ...) { net_client_printf(int side, const char *fmt, ...) {
va_list ap; va_list ap;
assert((side==0) || (side==1)); assert((side==0) || (side==1));
va_start(ap, fmt); va_start(ap, fmt);
net_side_vprintf(side, fmt, ap); net_client_vprintf(side, fmt, ap);
va_end(ap); va_end(ap);
} }
#endif #endif
void net_client_accept(int servsock);
void net_client_read(int clientid);
void void
net_poll() { net_poll() {
@ -225,6 +254,20 @@ net_poll() {
if (npoll<0) if (npoll<0)
errx(1, "poll: %s", strerror(errno)); errx(1, "poll: %s", strerror(errno));
if (pollfds[0].revents) { if (pollfds[0].revents) {
net_client_accept(pollfds[0].fd);
npoll--;
}
for (int i=0; npoll && i<MAX_CLIENTS; i++) {
if (pollfds[SRV_FDS+i].revents) {
net_client_read(i);
npoll--;
}
}
}
void
net_client_accept(int servsock) {
struct sockaddr_in clientaddr; struct sockaddr_in clientaddr;
int cfd; int cfd;
socklen_t slen; socklen_t slen;
@ -233,26 +276,98 @@ net_poll() {
errx(1, "accept: %s", strerror(errno)); errx(1, "accept: %s", strerror(errno));
// FIXME log, shout, or something // FIXME log, shout, or something
if (nclients>MAX_CLIENTS) { if (nclients>MAX_CLIENTS) {
#define STR_SERVER_FULL "Sorry, the server is full" #define STR_SERVER_FULL "Sorry, the server is full\n"
write(cfd, STR_SERVER_FULL, sizeof(STR_SERVER_FULL)-1); write(cfd, STR_SERVER_FULL, sizeof(STR_SERVER_FULL)-1);
close(cfd); close(cfd);
} else { } else {
int i; int clientid;
for (i=SRV_FDS; i<(SRV_FDS+MAX_CLIENTS); i++) for (clientid=0; clientid<MAX_CLIENTS; clientid++)
if (pollfds[i].fd==-1) break; if (pollfds[SRV_FDS+clientid].fd == -1) break;
pollfds[i].fd=cfd;
pollfds[i].events=POLLIN|POLLERR|POLLHUP; printf("Client %d connected...\n", clientid);
pollfds[SRV_FDS+clientid].fd=cfd;
pollfds[SRV_FDS+clientid].events=POLLIN|POLLERR|POLLHUP;
clients[clientid].fd = cfd;
clients[clientid].linetoolong = 0;
clients[clientid].bufend = 0;
server_client_connect(clientid);
nclients++; nclients++;
} }
npoll--;
} }
for (int i=SRV_FDS; npoll && i<(SRV_FDS+MAX_CLIENTS); i++) {
if (pollfds[SRV_FDS+i].revents) { void
net_client_close(int clientid) {
printf("Closing down client %d...\n", clientid);
close(pollfds[SRV_FDS+clientid].fd);
pollfds[SRV_FDS+clientid].revents = 0;
pollfds[SRV_FDS+clientid].fd = -1;
clients[clientid].fd = -1;
clients[clientid].linetoolong = 0;
clients[clientid].bufend = 0;
nclients--;
}
void
net_client_read(int clientid) {
struct client *c = &clients[clientid];
int len = c->bufend;
int n; int n;
char buf[100];
n=read(pollfds[SRV_FDS+i].fd, &buf, sizeof(buf)); n = read(c->fd, c->buf + len, BUFSIZ - len);
// parse buf // printf("read client %d %d\n", clientid, n);
// handle disconnections if (n==0) {
net_client_close(clientid);
return;
}
if (n<0)
errx(1, "read fail: %s\n", strerror(errno));
char *line = c->buf;
char *bufend = c->buf + n;
char *p = c->buf + len; /* start search for '\n' at end of last buffer */
while ((p = memchr(p, '\n', bufend - p))) {
*p='\0';
if ((p - line > 0) && (*(p-1) == '\r'))
*(p-1)='\0';
if (c->linetoolong) {
c->linetoolong = 0;
} else {
parse_line(clientid, line);
}
line=++p; // start of unparsed buffer
}
if (line == c->buf) {
/* linestart at start of buffer ie nothing was parsed */
if ((bufend == c->buf + BUFSIZ) && !c->linetoolong) {
/* buffer is full with overlong line
* send to parser for error msg or partial parsing */
c->linetoolong = 1;
c->buf[BUFSIZ-1]='\0';
parse_linetoolong(clientid, line);
}
if (c->linetoolong)
c->bufend = 0;
} else {
if (bufend - line) {
/* move partial line to beginning of buffer */
memmove(c->buf, line, bufend - line);
c->bufend = bufend - line;
} }
} }
} }
/*
int
main() {
net_server(6243);
for (;;)
net_poll();
}
*/

View File

@ -18,6 +18,7 @@ extern struct file sfile[2];
extern void net_server(int port); extern void net_server(int port);
extern void net_poll();
#if 1 #if 1
extern int net_getc_fillbuf(struct file *f); extern int net_getc_fillbuf(struct file *f);
@ -30,7 +31,7 @@ extern int _net_getc(int side);
#endif #endif
extern void net_all_printf(const char *fmt, ...); extern void net_all_printf(const char *fmt, ...);
extern void net_side_printf(int side, const char *fmt, ...); extern void net_client_printf(int side, const char *fmt, ...);
extern void net_all_flush(); extern void net_all_flush();
#endif #endif

View File

@ -200,17 +200,17 @@ simple_game(void)
net_all_printf("%s's move\n", sideinfo[side].name); net_all_printf("%s's move\n", sideinfo[side].name);
prompt: prompt:
net_side_printf(side, "> "); net_client_printf(side, "> ");
net_all_flush(); net_all_flush();
r = read_move(side, &m); r = read_move(side, &m);
if (r != HUGE_SUCCESS) { if (r != HUGE_SUCCESS) {
net_side_printf(side, "unknown command\n"); net_client_printf(side, "unknown command\n");
goto prompt; goto prompt;
} }
if (perform_move(&game, side, m) != HUGE_SUCCESS) { if (perform_move(&game, side, m) != HUGE_SUCCESS) {
net_side_printf(side, "illegal move\n"); net_client_printf(side, "illegal move\n");
goto prompt; goto prompt;
} }
@ -229,14 +229,87 @@ simple_game(void)
} }
} }
game_t game;
void
parse_line(int clientid, char *line) {
move_t move;
if (parse_move(line, &move) != HUGE_SUCCESS) {
net_client_printf(clientid, "not a valid move description: '%s'\n", line);
return;
}
if (perform_move(&game, clientid, move) != HUGE_SUCCESS) {
net_client_printf(clientid, "invalid move\n");
return;
}
if (game.last_move.type == M_ROTATE) {
net_all_printf("move: %c%c rotated %s\n",
game.last_move.y+'A',
game.last_move.x+'0',
game.last_move.dir==R_CW ? "R" : "L");
} else {
int nx, ny;
move_dest(game.last_move, &nx, &ny);
net_all_printf("move: %c%c moved to %c%c\n",
game.last_move.y+'A',
game.last_move.x+'0',
ny+'A', nx+'0');
}
if (game.last_hit.piece != NONE) {
net_all_printf("laser hits %s %s at %c%c\n",
sideinfo[game.last_hit.side].name,
pieceinfo[game.last_hit.piece].name,
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
} else {
net_all_printf("laser hits wall at %c%c\n",
game.laser_pos[1]+'A', game.laser_pos[0]+'0');
}
char aabuf[ASCIIART_SMALL_BUFSZ];
asciiart_small_draw_board(aabuf, &game);
net_all_printf("%s", aabuf);
switch (game.winner) {
case SILVER:
net_all_printf("SILVER WINS!\n");
exit(0);
case RED:
net_all_printf("RED WINS!\n");
exit(0);
}
}
int player[2]={0, 0};
void
server_client_connect(int clientid) {
assert(clientid<2);
player[clientid]=1;
if (player[0] && player[1]) {
char aabuf[ASCIIART_SMALL_BUFSZ];
init_game(&game);
setup_board(&game, classic_setup);
asciiart_small_draw_board(aabuf, &game);
net_all_printf("%s", aabuf);
}
}
int int
main(int argc, char **argv) { main(int argc, char **argv) {
if (argc > 1 && strcmp(argv[1], "local")==0) { if (argc > 1 && strcmp(argv[1], "local")==0) {
terminal_game(); terminal_game();
return 0; return 0;
} } else {
net_server(15239); net_server(15239);
simple_game(); for (;;)
net_poll();
}
return 0; return 0;
} }