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
|
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
|
||||||
|
181
src/net.c
181
src/net.c
@ -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++) {
|
void
|
||||||
if (pollfds[SRV_FDS+i].revents) {
|
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();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -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
|
||||||
|
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);
|
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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user