[Commit] rrserver clients.5c,NONE,1.1 send.5c,NONE,1.1 dispatch.5c,1.4,1.5 games.5c,1.2,1.3 lex.5c,1.2,1.3 net.5c,1.1,1.2 readreq.5c,1.2,1.3 server.5c,1.2,1.3 connect.5c,1.2,NONE
Keith Packard
commit@keithp.com
Thu, 29 May 2003 10:46:31 -0700
Committed by: keithp
Update of /local/src/CVS/rrserver
In directory home.keithp.com:/tmp/cvs-serv22376
Modified Files:
dispatch.5c games.5c lex.5c net.5c readreq.5c server.5c
Added Files:
clients.5c send.5c
Removed Files:
connect.5c
Log Message:
Rename Connect namespace to Clients
Use exceptions to manage dispatch errors
Add global lock
Add broadcast/respond functions to simplify responses
Clean up newline handling
--- NEW FILE: clients.5c ---
(This appears to be a binary file; contents omitted.)
--- NEW FILE: send.5c ---
(This appears to be a binary file; contents omitted.)
Index: dispatch.5c
===================================================================
RCS file: /local/src/CVS/rrserver/dispatch.5c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dispatch.5c 29 May 2003 08:32:19 -0000 1.4
+++ dispatch.5c 29 May 2003 17:46:29 -0000 1.5
@@ -23,8 +23,9 @@
*/
autoload RR
+autoload RR::Send
autoload Server
-autoload Server::Connect
+autoload Server::Clients
autoload Server::Readreq
autoload Server::Show
autoload Server::Games
@@ -35,20 +36,40 @@
public void set_server_id (string id) { server_id = id; }
- public void client (file f) {
- &Client c = Connect::new (f);
+ void client_locked (file f) {
+ &Client c = Clients::new (f);
- void helo (string username) {
- c.user.username = username;
- File::fprintf (f, "HELO \"%s\"\n", server_id);
+ exception notactive ();
+ exception notingame ();
+ exception invalidname ();
+ exception nonameset ();
+
+ void broadcast (string fmt, poly args...) {
+ RR::Send::send (stdout, "broadcast: ");
+ RR::Send::send (stdout, fmt, args...);
+ void message_client (&Client o) {
+ if (&o != &c)
+ {
+ RR::Send::send (o.f, fmt, args...);
+ File::flush (o.f);
+ }
+ }
+ Clients::iterate (message_client);
+ RR::Send::send (stdout, "done\n");
}
- void print_client (&Client c) {
- union switch (c.user) {
+ void respond (string fmt, poly args...) {
+ RR::Send::send (stdout, "respond: ");
+ RR::Send::send (stdout, fmt, args...);
+ RR::Send::send (f, fmt, args...);
+ }
+
+ void print_client (&Client o) {
+ union switch (o.user) {
case none:
break;
case username u:
- File::fprintf (f, " \"%s\"", u);
+ respond (" %s", u);
break;
}
}
@@ -58,55 +79,58 @@
case none:
break;
case username u:
- File::fprintf (f, " \"%s\" %d", u, c.score);
+ respond (" %s %d", u, c.score);
break;
}
}
+ void helo (string username) {
+ if (Clients::find (username) != ClientRef.none)
+ raise invalidname ();
+ c.user.username = username;
+ respond ("HELO %s\n", server_id);
+ broadcast ("NOTICE USER %s\n", username);
+ }
+
void who () {
- File::fprintf (f, "WHO");
- Connect::iterate (print_client);
- File::fprintf (f, "\n");
+ respond ("WHO");
+ Clients::iterate (print_client);
+ respond ("\n");
}
void games() {
- File::fprintf (f, "GAMES");
+ respond ("GAMES");
Games::iterate (void func(&Game g) {
- File::fprintf (f, " \"%s\"", g.name);
+ respond (" %s", g.name);
});
- File::fprintf (f, "\n");
+ respond ("\n");
}
void users(string game) {
- try {
- &Game g = Games::find (game);
- File::fprintf (f, "USERS");
- Games::iterate_client (&g, print_client_score);
- File::fprintf (f, "\n");
- } catch Games::no_such_game (string name) {
- File::fprintf (f, "ERROR NOGAME\n");
- }
+ &Game g = Games::find (game);
+ respond ("USERS");
+ Games::iterate_client (&g, print_client_score);
+ respond ("\n");
}
void join (string game) {
- try {
- &Game g = Games::find (game);
- Games::add_client (&g, &c);
- } catch Games::no_such_game (string game) {
- File::fprintf (f, "ERROR NOGAME\n");
- }
+ &Game g = Games::find (game);
+ Games::add_client (&g, &c);
+ respond ("JOIN\n");
+ broadcast ("NOTICE JOIN %s %s\n", g.name, c.user.username);
}
void new(string game) {
- &Game g = Games::new (game);
- join (g.name);
- File::fprintf (f, "NEW \"%s\"\n", g.name);
+ &Game g =Games::new (game);
+ Games::add_client (&g, &c);
+ respond ("NEW %s\n", g.name);
+ broadcast ("NOTICE NEW %s\n", g.name);
}
void show () {
union switch (c.game) {
case none:
- File::fprintf (f, "ERROR NOTINGAME\n");
+ raise notingame ();
break;
case game g:
File::fprintf (f, "SHOW \"\n");
@@ -117,86 +141,73 @@
}
void bid (int number) {
- File::fprintf (f, "BID\n");
+ respond ("BID\n");
+ broadcast ("BID %s %d\n", c.user.username, number);
}
void move (Color color, Direction direction) {
union switch (c.game) {
case none:
- File::fprintf (f, "ERROR NOTINGAME\n");
- break;
+ raise notingame ();
case game g:
- try {
- Games::move (&g, &c, color, direction);
- File::fprintf (f, "MOVE\n");
- } catch Games::notactive (&Game g, &Client c) {
- File::fprintf (f, "ERROR NOTACTIVE\n");
- }
+ Games::move (&g, &c, color, direction);
+ respond ("MOVE\n");
break;
}
+ broadcast ("NOTICE MOVE %C %D\n", color, direction);
}
void undo () {
union switch (c.game) {
case none:
- File::fprintf (f, "ERROR NOTINGAME\n");
+ raise notingame ();
break;
case game g:
- try {
- Games::undo (&g, &c);
- File::fprintf (f, "UNDO\n");
- } catch Games::notactive (&Game g, &Client c) {
- File::fprintf (f, "ERROR NOTACTIVE\n");
- }
+ Games::undo (&g, &c);
+ respond ("UNDO\n");
break;
}
+ broadcast ("NOTICE UNDO\n");
}
void reset () {
union switch (c.game) {
case none:
- File::fprintf (f, "ERROR NOTINGAME\n");
+ raise notingame ();
break;
case game g:
- try {
- Games::reset (&g, &c);
- File::fprintf (f, "RESET\n");
- } catch Games::notactive (&Game g, &Client c) {
- File::fprintf (f, "ERROR NOTACTIVE\n");
- }
+ Games::reset (&g, &c);
+ respond ("RESET\n");
break;
}
+ broadcast ("NOTICE RESET\n");
}
void turn () {
union switch (c.game) {
case none:
- File::fprintf (f, "ERROR NOTINGAME\n");
- break;
+ raise notingame ();
case game g:
if (Games::solved (&g))
- Games::next_target (&g);
- File::fprintf (f, "TURN\n");
+ Games::next_turn (&g);
+ respond ("TURN\n");
break;
}
+ broadcast ("NOTICE TURN\n");
}
void pass () {
}
void message (string text) {
- File::fprintf (f, "MESSAGE\n");
- Connect::iterate (void func (&Client o) {
- string u = c.user == User.none ? "anonymous" :
- c.user.username;
- File::fprintf (o.f, "NOTICE MESSAGE \"%s\" \"%s\"\n",
- u, text);
- File::flush (o.f);
- });
+ respond ("MESSAGE\n");
+ string u = (c.user == User.none ? "anonymous" :
+ c.user.username);
+ broadcast ("NOTICE MESSAGE %s %s\n", u, text);
}
void quit () {
- File::fprintf (f, "QUIT\n");
+ respond ("QUIT\n");
raise Readreq::request_closed();
}
@@ -207,6 +218,15 @@
File::flush (f);
Request r = Readreq::read (f);
union switch (r) {
+ case HELO:
+ case QUIT:
+ break;
+ default:
+ if (c.user == User.none)
+ raise nonameset ();
+ break;
+ }
+ union switch (r) {
case HELO h:
helo (h.username);
break;
@@ -257,26 +277,41 @@
break;
}
} catch Readreq::invalid_request (string w) {
- File::fprintf (f, "ERROR COMMAND %s\n", w);
- } catch Readreq::request_closed () {
- printf ("Client closed\n");
- Connect::dispose (&c);
- File::close (f);
- return;
+ respond ("ERROR COMMAND %s\n", w);
} catch RR::Lex::syntax() {
- File::fprintf (f, "ERROR SYNTAX\n");
- RR::Lex::skipline (f);
+ respond ("ERROR SYNTAX\n");
} catch RR::Lex::invalid_color (string color) {
- File::fprintf (f, "ERROR NOTCOLOR %s\n", color);
- RR::Lex::skipline (f);
+ respond ("ERROR NOTCOLOR %s\n", color);
} catch RR::Lex::invalid_shape (string shape) {
- File::fprintf (f, "ERROR NOTSHAPE %s\n", shape);
- RR::Lex::skipline (f);
+ respond ("ERROR NOTSHAPE %s\n", shape);
} catch RR::Lex::invalid_direction (string direction) {
- File::fprintf (f, "ERROR NOTDIRECTION %s\n", direction);
- RR::Lex::skipline (f);
+ respond ("ERROR NOTDIRECTION %s\n", direction);
+ } catch Games::notactive (&Game g, &Client c) {
+ respond ("ERROR NOTACTIVE\n");
+ } catch notingame () {
+ respond ("ERROR NOTINGAME\n");
+ } catch Games::no_such_game (string name) {
+ respond ("ERROR NOGAME\n");
+ } catch nonameset () {
+ respond ("ERROR NONAMESET\n");
+ } catch invalidname () {
+ respond ("ERROR INVALIDNAME\n");
+ } catch Readreq::request_closed () {
+ User user = c.user;
+ printf ("Client closed %v\n", c.user);
+ Clients::dispose (&c);
+ File::close (f);
+ if (c.user != User.none)
+ broadcast ("NOTICE PART %s\n", c.user.username);
+ return;
}
}
+ }
+
+ public void client (file f)
+ {
+ twixt (lock (); unlock ())
+ client_locked (f);
}
}
}
Index: games.5c
===================================================================
RCS file: /local/src/CVS/rrserver/games.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- games.5c 29 May 2003 08:15:44 -0000 1.2
+++ games.5c 29 May 2003 17:46:29 -0000 1.3
@@ -37,7 +37,7 @@
void remove (&Game g) {
Array::remove (&games, &g);
}
-
+
public void iterate (void (&Game g) f) {
Array::iterate (&games, f);
}
@@ -92,7 +92,7 @@
return t;
}
- public void next_target (&Game g) {
+ void next_target (&Game g) {
Target t = g.targets[0];
g.targets = (Target[dim(g.targets)-1]) { [i] = g.targets[i+1] };
g.history = (ObjectLoc[*]) {};
@@ -100,6 +100,10 @@
Boards::set_target (&g.board, t.color, t.shape);
}
+ public void next_turn (&Game g) {
+ next_target (&g);
+ }
+
public &Game new (string suggestion) {
string name;
for (int n = 0;
@@ -119,7 +123,6 @@
public void remove_client (&Game g, &Client c) {
Array::remove (&g.clients, &c);
- c.score = 0;
}
public &Client add_client (&Game g, &Client c) {
@@ -142,6 +145,8 @@
public exception notactive (&Game g, &Client c);
public bool undo (&Game g, &Client c) {
+ if (g.active != (ClientRef.client) (&c))
+ raise notactive (&g, &c);
try {
ObjectLoc ol = Array::pop (&g.history);
Boards::position_robot (&g.board, ol.object.robot.robot.color,
@@ -153,8 +158,6 @@
}
public void reset (&Game g, &Client c) {
- if (g.active != (ClientRef.client) (&c))
- raise notactive (&g, &c);
while (dim (g.history) > 0)
undo (&g, &c);
}
Index: lex.5c
===================================================================
RCS file: /local/src/CVS/rrserver/lex.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- lex.5c 29 May 2003 08:15:44 -0000 1.2
+++ lex.5c 29 May 2003 17:46:29 -0000 1.3
@@ -44,15 +44,18 @@
return -1;
}
- void skipwhite (file f) {
+ bool skipwhite (file f, bool allow_newline) {
while ((int c = lexc (f)) != -1) {
- if (c == '\n')
- raise syntax ();
+ if (c == '\n' && !allow_newline) {
+ File::ungetc (c, f);
+ return true;
+ }
if (!Ctype::isspace(c)) {
File::ungetc (c, f);
- break;
+ return false;
}
}
+ return true;
}
public void skipline (file f) {
@@ -94,24 +97,8 @@
return s;
}
- public string word (file f) {
- skipwhite (f);
- return next_word (f);
- }
-
- public string firstword (file f) {
- for (;;) {
- try {
- skipwhite (f);
- return next_word (f);
- } catch syntax () {
- ;
- }
- }
- }
-
public bool eol (file f) {
- skipwhite (f);
+ skipwhite (f, false);
int c = lexc (f);
if (c == -1)
return true;
@@ -119,6 +106,17 @@
if (c == '\n')
return true;
return false;
+ }
+
+ public string word (file f) {
+ if (skipwhite (f, false))
+ raise syntax ();
+ return next_word (f);
+ }
+
+ public string firstword (file f) {
+ skipwhite (f, true);
+ return next_word (f);
}
public int number (file f) {
Index: net.5c
===================================================================
RCS file: /local/src/CVS/rrserver/net.5c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- net.5c 29 May 2003 06:45:37 -0000 1.1
+++ net.5c 29 May 2003 17:46:29 -0000 1.2
@@ -23,7 +23,6 @@
*/
autoload RR
-autoload Server::Connect
autoload Server::Readreq
extend namespace Server {
Index: readreq.5c
===================================================================
RCS file: /local/src/CVS/rrserver/readreq.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- readreq.5c 29 May 2003 06:45:37 -0000 1.2
+++ readreq.5c 29 May 2003 17:46:29 -0000 1.3
@@ -24,6 +24,7 @@
autoload RR::Lex
autoload Ctype
+autoload Server
extend namespace Server {
public namespace Readreq {
@@ -41,7 +42,7 @@
return r;
}
- public Request read (file f) {
+ Request read_unlocked (file f) {
struct {} packet;
void username_ (&struct { string username; } packet) {
packet.username = word (f);
@@ -64,62 +65,88 @@
void text_ (&struct { string text; } packet) {
packet.text = word (f);
}
+ Request req;
switch (string w = upper (firstword (f))) {
case "HELO":
packet = (struct { string username; }) {};
username_ (&packet);
- return (Request.HELO) packet;
+ req = (Request.HELO) packet;
+ break;
case "WHO":
- return Request.WHO;
+ req = Request.WHO;
+ break;
case "GAMES":
- return Request.GAMES;
+ req = Request.GAMES;
+ break;
case "USERS":
packet = (struct { string game; }) {};
game_ (&packet);
- return (Request.USERS) packet;
+ req = (Request.USERS) packet;
+ break;
case "NEW":
packet = (struct { string game; }) {};
game_ (&packet);
- return (Request.NEW) packet;
+ req = (Request.NEW) packet;
+ break;
case "JOIN":
packet = (struct { string game; }) {};
game_ (&packet);
- return (Request.JOIN) packet;
+ req = (Request.JOIN) packet;
+ break;
case "WATCH":
packet = (struct { string game; }) {};
game_ (&packet);
- return (Request.WATCH) packet;
+ req = (Request.WATCH) packet;
+ break;
case "SHOW":
- return Request.SHOW;
+ req = Request.SHOW;
+ break;
case "BID":
packet = (struct { int number; }) {};
number_ (&packet);
- return (Request.BID) packet;
+ req = (Request.BID) packet;
+ break;
case "MOVE":
packet = (struct { Color color; Direction direction; }) {};
color_ (&packet);
direction_ (&packet);
- return (Request.MOVE) packet;
+ req = (Request.MOVE) packet;
+ break;
case "UNDO":
- return Request.UNDO;
+ req = Request.UNDO;
+ break;
case "RESET":
- return Request.RESET;
+ req = Request.RESET;
+ break;
case "TURN":
- return Request.TURN;
+ req = Request.TURN;
+ break;
case "PASS":
- return Request.PASS;
+ req = Request.PASS;
+ break;
case "MESSAGE":
packet = (struct { string text; }) {};
text_ (&packet);
- return (Request.MESSAGE) packet;
+ req = (Request.MESSAGE) packet;
+ break;
case "QUIT":
- return Request.QUIT;
+ req = Request.QUIT;
+ break;
case "":
raise request_closed ();
default:
- skipline (f);
raise invalid_request (w);
}
+ if (!eol (f))
+ raise syntax ();
+ return req;
+ }
+
+ public Request read (file f) {
+ twixt (unlock (); lock ())
+ twixt (true; skipline (f))
+ return read_unlocked (f);
+ raise notreached ();
}
}
}
Index: server.5c
===================================================================
RCS file: /local/src/CVS/rrserver/server.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- server.5c 29 May 2003 08:15:44 -0000 1.2
+++ server.5c 29 May 2003 17:46:29 -0000 1.3
@@ -31,6 +31,20 @@
public typedef Client;
public typedef Game;
+ mutex server_mutex = Mutex::new ();
+
+ public bool lock () {
+ Mutex::acquire (server_mutex);
+ printf ("lock %v\n", Thread::current ());
+ return true;
+ }
+
+ public bool unlock () {
+ printf ("unlock %v\n", Thread::current ());
+ Mutex::release (server_mutex);
+ return true;
+ }
+
public typedef struct {
int x, y;
Object object;
@@ -72,4 +86,6 @@
ClientRef active;
ObjectLoc[*] history;
} Game;
+
+ public exception notreached ();
}
--- connect.5c DELETED ---