ref: 2e921a4b2dba62b849b1b9be8abaca8db1ef7872
dir: /btsd.c/
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <geometry.h>
#include "dat.h"
#include "fns.h"
int debug;
Playerq playerq;
void
pushplayer(Player *p)
{
qlock(&playerq);
if(++playerq.nplayers > playerq.cap){
playerq.cap = playerq.nplayers;
playerq.players = erealloc(playerq.players, playerq.cap * sizeof p);
}
playerq.players[playerq.nplayers-1] = p;
qunlock(&playerq);
if(debug)
fprint(2, "pushed fd %d sfd %d o %p\n", p->fd, p->sfd, p->o);
}
Player *
popplayer(void)
{
Player *p;
p = nil;
if(playerq.nplayers > 0){
qlock(&playerq);
p = playerq.players[--playerq.nplayers];
qunlock(&playerq);
}
if(debug)
fprint(2, "poppin fd %d sfd %d o %p\n", p->fd, p->sfd, p->o);
return p;
}
void
netrecvthread(void *arg)
{
Chanpipe *cp;
Ioproc *io;
char buf[256];
int n;
cp = arg;
io = ioproc();
while((n = ioread(io, cp->fd, buf, sizeof(buf)-1)) > 0){
buf[n] = 0;
chanprint(cp->c, "%s", buf);
}
chanclose(cp->c);
if(debug)
fprint(2, "[%d] lost connection\n", getpid());
}
void
serveproc(void *arg)
{
NetConnInfo *nci[2];
Player **m;
Chanpipe cp[2];
Alt a[3];
int i, n0, tid[2];
char *s;
threadsetname("serveproc ");
m = arg;
s = nil;
nci[0] = getnetconninfo(nil, m[0]->fd);
nci[1] = getnetconninfo(nil, m[1]->fd);
if(nci[0] == nil || nci[1] == nil)
sysfatal("getnetconninfo: %r");
threadsetname("serveproc %s ↔ %s", nci[0]->raddr, nci[1]->raddr);
freenetconninfo(nci[0]);
freenetconninfo(nci[1]);
cp[0].c = chancreate(sizeof(char*), 1);
cp[0].fd = m[0]->fd;
cp[1].c = chancreate(sizeof(char*), 1);
cp[1].fd = m[1]->fd;
a[0].c = cp[0].c; a[0].v = &s; a[0].op = CHANRCV;
a[1].c = cp[1].c; a[1].v = &s; a[1].op = CHANRCV;
a[2].op = CHANEND;
tid[0] = threadcreate(netrecvthread, &cp[0], mainstacksize);
tid[1] = threadcreate(netrecvthread, &cp[1], mainstacksize);
n0 = truerand();
write(m[n0%2]->fd, "wait", 4);
write(m[(n0+1)%2]->fd, "play", 4);
while((i = alt(a)) >= 0){
if(debug)
fprint(2, "[%d] said '%s'\n", getpid(), s);
if(a[i].err != nil){
write(m[i^1]->fd, "won", 3);
pushplayer(m[i^1]);
free(m[i]);
goto out;
}
if(write(m[i^1]->fd, s, strlen(s)) != strlen(s)){
write(m[i]->fd, "won", 3);
/* TODO free the player */
pushplayer(m[i]);
free(m[i^1]);
goto out;
}
free(s);
}
out:
if(debug)
fprint(2, "[%d] serveproc ending\n", getpid());
chanclose(cp[0].c);
chanclose(cp[1].c);
close(cp[i].fd);
/* TODO make sure this is the last thread to exit */
// recv(cp[0].done)
// recv(cp[1].done)
free(m);
yield();
}
void
reaper(void *)
{
char buf[8];
ulong i;
int n;
threadsetname("reaper");
for(;;){
for(i = 0; i < playerq.nplayers; i++){
if(debug)
fprint(2, "reapin fd %d sfd %d o %p?",
playerq.players[i]->fd, playerq.players[i]->sfd, playerq.players[i]->o);
n = read(playerq.players[i]->sfd, buf, sizeof buf);
if(n < 0 || strncmp(buf, "Closed", 6) == 0){
if(debug)
fprint(2, " yes\n");
qlock(&playerq);
close(playerq.players[i]->fd);
close(playerq.players[i]->sfd);
free(playerq.players[i]);
memmove(&playerq.players[i], &playerq.players[i+1], (--playerq.nplayers-i)*sizeof(Player*));
qunlock(&playerq);
}else if(debug)
fprint(2, " no\n");
}
sleep(HZ2MS(1));
}
}
void
matchmaker(void *)
{
Player **match;
threadsetname("matchmaker");
for(;;){
if(playerq.nplayers < 2){
sleep(100);
continue;
}
match = emalloc(2*sizeof(Player*));
match[0] = popplayer();
match[1] = popplayer();
match[1]->o = match[0];
match[0]->o = match[1];
proccreate(serveproc, match, mainstacksize);
}
}
void
playerproc(void *arg)
{
char buf[256];
int fd, n;
threadsetname("playerproc");
fd = *(int*)arg;
while((n = read(fd, buf, sizeof(buf)-1)) > 0){
buf[n] = 0;
if(debug)
fprint(2, "[%d] rcvd '%s'\n", getpid(), buf);
}
if(debug)
fprint(2, "[%d] lost connection\n", getpid());
}
void
listenthread(void *arg)
{
char *addr, adir[40], ldir[40]/*, aux[128], *s*/;
int acfd, lcfd, dfd/*, sfd*/;
// Player *p;
addr = arg;
acfd = announce(addr, adir);
if(acfd < 0)
sysfatal("announce: %r");
if(debug)
fprint(2, "listening on %s\n", addr);
while((lcfd = listen(adir, ldir)) >= 0){
if((dfd = accept(lcfd, ldir)) >= 0){
// fd2path(dfd, aux, sizeof aux);
// s = strrchr(aux, '/');
// *s = 0;
// snprint(aux, sizeof aux, "%s/status", aux);
// sfd = open(aux, OREAD);
// if(sfd < 0)
// sysfatal("open: %r");
//
// p = emalloc(sizeof *p);
// p->fd = dfd;
// p->sfd = sfd;
// p->mc = nil;
// pushplayer(p);
proccreate(playerproc, &dfd, mainstacksize);
}
close(lcfd);
}
threadexitsall("listen: %r");
}
void
usage(void)
{
fprint(2, "usage: %s [-d] [-a addr]\n", argv0);
threadexitsall("usage");
}
void
threadmain(int argc, char *argv[])
{
char *addr;
addr = "tcp!*!3047";
ARGBEGIN{
case 'd':
debug++;
break;
case 'a':
addr = EARGF(usage());
break;
}ARGEND
if(argc != 0)
usage();
// proccreate(matchmaker, nil, mainstacksize);
// proccreate(reaper, nil, mainstacksize);
threadcreate(listenthread, addr, mainstacksize);
yield();
}