Fix network support
Multiple clients can now connect. (For now two first clients will play)
This commit is contained in:
parent
b00565ea66
commit
160e63e91c
@ -5,11 +5,15 @@ all: server
|
||||
server: server.o net.o asciiart.o game.o
|
||||
|
||||
clean:
|
||||
-rm -f *.o
|
||||
-rm -f server *.o *~
|
||||
|
||||
depend:
|
||||
makedepend *.c -Y. 2>/dev/null
|
||||
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
asciiart.o: game.h asciiart.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
|
||||
|
179
src/net.c
179
src/net.c
@ -13,11 +13,20 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "net.h"
|
||||
#include "server.h"
|
||||
|
||||
#define MAX_CLIENTS 2
|
||||
#define MAX_CLIENTS 10
|
||||
#define SRV_FDS 1
|
||||
|
||||
struct client {
|
||||
int fd;
|
||||
char buf[BUFSIZ];
|
||||
int bufend;
|
||||
int linetoolong;
|
||||
};
|
||||
|
||||
int servsock;
|
||||
struct client clients[MAX_CLIENTS];
|
||||
struct pollfd pollfds[SRV_FDS+MAX_CLIENTS];
|
||||
int nclients = 0;
|
||||
|
||||
@ -32,6 +41,19 @@ errx(int eval, const char *fmt, ...) {
|
||||
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];
|
||||
|
||||
void
|
||||
@ -55,7 +77,7 @@ net_server(int port) {
|
||||
errx(1, "bind port %d: %s\n", port, strerror(errno));
|
||||
if (listen(servsock, 10) < 0)
|
||||
errx(1, "listen: %s\n", strerror(errno));
|
||||
#if 1
|
||||
#if 0
|
||||
// FIXME Temporary startup. Use net_poll for this later:
|
||||
printf("Waiting for connections on port %d...\n", port);
|
||||
for (int i=0; i<2; i++) {
|
||||
@ -72,18 +94,19 @@ net_server(int port) {
|
||||
sfile[i].iend=0;
|
||||
sfile[i].oend=0;
|
||||
|
||||
net_side_printf(i, "Welcome!\n");
|
||||
net_client_printf(i, "Welcome!\n");
|
||||
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");
|
||||
#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;
|
||||
for (int i=0; i<MAX_CLIENTS; i++) {
|
||||
pollfds[SRV_FDS+i].fd=-1;
|
||||
pollfds[SRV_FDS+i].events=0;
|
||||
}
|
||||
printf("Waiting for connections on port %d...\n", port);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -106,11 +129,12 @@ net_all_flush() {
|
||||
}
|
||||
|
||||
void
|
||||
net_side_printf(int side, const char *fmt, ...) {
|
||||
net_client_printf(int clientid, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char buf[BUFSIZ];
|
||||
int len, n;
|
||||
assert((side==0) || (side==1));
|
||||
struct client *c = &clients[clientid];
|
||||
|
||||
va_start(ap, fmt);
|
||||
len=vsnprintf(buf, sizeof(buf)-1, fmt, ap);
|
||||
va_end(ap);
|
||||
@ -118,7 +142,7 @@ net_side_printf(int side, const char *fmt, ...) {
|
||||
errx(1, "BUFSIZ too small\n");
|
||||
char *bufp=buf;
|
||||
do {
|
||||
n=write(sfile[side].fd, bufp, len);
|
||||
n=write(c->fd, bufp, len);
|
||||
if (n<0)
|
||||
errx(1, "write: %s\n", strerror(errno));
|
||||
bufp+=n;
|
||||
@ -135,10 +159,11 @@ net_all_printf(const char *fmt, ...) {
|
||||
va_end(ap);
|
||||
if (len > BUFSIZ-1)
|
||||
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;
|
||||
do {
|
||||
n=write(sfile[side].fd, bufp, len);
|
||||
n=write(c->fd, bufp, len);
|
||||
if (n<0)
|
||||
errx(1, "write: %s\n", strerror(errno));
|
||||
bufp+=n;
|
||||
@ -148,6 +173,8 @@ net_all_printf(const char *fmt, ...) {
|
||||
#endif
|
||||
|
||||
|
||||
#define min(a,b) ((a<b) ? (a) : (b))
|
||||
|
||||
int
|
||||
net_getc_fillbuf(struct file *f) {
|
||||
int n;
|
||||
@ -174,7 +201,7 @@ net_getc(int side) {
|
||||
|
||||
#if 0
|
||||
void
|
||||
net_side_flush(int side) {
|
||||
net_client_flush(int side) {
|
||||
start=0;
|
||||
do start+=write(fd[side], obuf[side]+start, obufend);
|
||||
while (start < obufend);
|
||||
@ -183,16 +210,16 @@ net_side_flush(int side) {
|
||||
void
|
||||
net_all_flush() {
|
||||
for (int i=0; i<2; i++)
|
||||
net_side_flush(i);
|
||||
net_client_flush(i);
|
||||
}
|
||||
|
||||
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);
|
||||
if (n > (BUFSIZ-obufend-1)) {
|
||||
if (n > BUFSIZ-1)
|
||||
errx(1, "BUFSIZ too small\n");
|
||||
net_side_flush(side);
|
||||
net_client_flush(side);
|
||||
n=vsnprintf(obuf[side], BUFSIZ-obufend, fmt, ap);
|
||||
}
|
||||
obufend[side]+=n;
|
||||
@ -203,20 +230,22 @@ net_all_printf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
for (int i=0; i<2; i++)
|
||||
net_side_vprintf(i, fmt, ap);
|
||||
net_client_vprintf(i, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
net_side_printf(int side, const char *fmt, ...) {
|
||||
net_client_printf(int side, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
assert((side==0) || (side==1));
|
||||
va_start(ap, fmt);
|
||||
net_side_vprintf(side, fmt, ap);
|
||||
net_client_vprintf(side, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
void net_client_accept(int servsock);
|
||||
void net_client_read(int clientid);
|
||||
|
||||
void
|
||||
net_poll() {
|
||||
@ -225,6 +254,20 @@ net_poll() {
|
||||
if (npoll<0)
|
||||
errx(1, "poll: %s", strerror(errno));
|
||||
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;
|
||||
int cfd;
|
||||
socklen_t slen;
|
||||
@ -233,26 +276,98 @@ net_poll() {
|
||||
errx(1, "accept: %s", strerror(errno));
|
||||
// FIXME log, shout, or something
|
||||
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);
|
||||
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;
|
||||
int clientid;
|
||||
for (clientid=0; clientid<MAX_CLIENTS; clientid++)
|
||||
if (pollfds[SRV_FDS+clientid].fd == -1) break;
|
||||
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
char buf[100];
|
||||
n=read(pollfds[SRV_FDS+i].fd, &buf, sizeof(buf));
|
||||
// parse buf
|
||||
// handle disconnections
|
||||
|
||||
n = read(c->fd, c->buf + len, BUFSIZ - len);
|
||||
// printf("read client %d %d\n", clientid, n);
|
||||
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();
|
||||
}
|
||||
*/
|
||||
|
@ -18,6 +18,7 @@ extern struct file sfile[2];
|
||||
|
||||
|
||||
extern void net_server(int port);
|
||||
extern void net_poll();
|
||||
|
||||
#if 1
|
||||
extern int net_getc_fillbuf(struct file *f);
|
||||
@ -30,7 +31,7 @@ extern int _net_getc(int side);
|
||||
#endif
|
||||
|
||||
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();
|
||||
|
||||
#endif
|
||||
|
85
src/server.c
85
src/server.c
@ -200,17 +200,17 @@ simple_game(void)
|
||||
|
||||
net_all_printf("%s's move\n", sideinfo[side].name);
|
||||
prompt:
|
||||
net_side_printf(side, "> ");
|
||||
net_client_printf(side, "> ");
|
||||
net_all_flush();
|
||||
|
||||
r = read_move(side, &m);
|
||||
if (r != HUGE_SUCCESS) {
|
||||
net_side_printf(side, "unknown command\n");
|
||||
net_client_printf(side, "unknown command\n");
|
||||
goto prompt;
|
||||
}
|
||||
|
||||
if (perform_move(&game, side, m) != HUGE_SUCCESS) {
|
||||
net_side_printf(side, "illegal move\n");
|
||||
net_client_printf(side, "illegal move\n");
|
||||
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
|
||||
main(int argc, char **argv) {
|
||||
if (argc > 1 && strcmp(argv[1], "local")==0) {
|
||||
terminal_game();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
net_server(15239);
|
||||
simple_game();
|
||||
for (;;)
|
||||
net_poll();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user