From 5d56d3cd8b4685e905ed604277ac9cb32c876127 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sat, 12 Nov 2005 01:21:21 +0000 Subject: [PATCH] 2005-11-11 Carl Worth * src/ttt-server.h: * src/ttt-server.c: (ttt_server_init), (ttt_server_add_client), (_accept_client), (main): Add a new ttt_server_t object with a mutex-protected list of clients. Move client handling code down into new ttt-client.c. * src/ttt-client.h: * src/ttt-client.c: (ttt_client_create), (ttt_client_destroy), (ttt_client_handle_requests): New ttt_client_t object that simply holds a pointer back to the server as well as the client socket file descriptor. * src/ttt-socket.h: * src/ttt-socket.c: (ttt_socket_accept): Add closure argument. Add a call to fork before calling the accept callback. * src/ttt-args.c: Hide unused ttt_args_usage from the compiler to keep it from complaining. * src/ttt.c: (main): Rename the client main program from ttt-client to ttt.c, (since the server code now has its own ttt-client.c). * src/ttt.h: * src/Makefile.am: Include and link with pthread now that we have pthread-based mutex locking. --- ChangeLog | 29 +++++++++++++++++++ src/Makefile.am | 5 ++-- src/ttt-args.c | 2 ++ src/ttt-client.c | 48 ++++++++++++++++++++++++++------ src/ttt-client.h | 50 +++++++++++++++++++++++++++++++++ src/ttt-server.c | 72 ++++++++++++++++++++++++++++++++++-------------- src/ttt-server.h | 29 +++++++++++++++++++ src/ttt-socket.c | 13 +++++++-- src/ttt-socket.h | 12 +++++--- src/ttt.c | 34 +++++++++++++++++++++++ src/ttt.h | 1 + 11 files changed, 258 insertions(+), 37 deletions(-) create mode 100644 src/ttt-client.h create mode 100644 src/ttt-server.h create mode 100644 src/ttt.c diff --git a/ChangeLog b/ChangeLog index d7cc7f9..85d24c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2005-11-11 Carl Worth + + * src/ttt-server.h: + * src/ttt-server.c: (ttt_server_init), (ttt_server_add_client), + (_accept_client), (main): Add a new ttt_server_t object with a + mutex-protected list of clients. Move client handling code down + into new ttt-client.c. + + * src/ttt-client.h: + * src/ttt-client.c: (ttt_client_create), (ttt_client_destroy), + (ttt_client_handle_requests): New ttt_client_t object that simply + holds a pointer back to the server as well as the client socket + file descriptor. + + * src/ttt-socket.h: + * src/ttt-socket.c: (ttt_socket_accept): Add closure argument. Add + a call to fork before calling the accept callback. + + * src/ttt-args.c: Hide unused ttt_args_usage from the compiler to + keep it from complaining. + + * src/ttt.c: (main): Rename the client main program from + ttt-client to ttt.c, (since the server code now has its own + ttt-client.c). + + * src/ttt.h: + * src/Makefile.am: Include and link with pthread now that we have + pthread-based mutex locking. + 2005-11-11 Carl Worth * src/ttt-server.c: (main): Don't assign to stderr which is diff --git a/src/Makefile.am b/src/Makefile.am index 792b1ec..5619e52 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,12 +12,13 @@ ttt_common_sources = \ ttt_client_SOURCES = \ $(ttt_common_sources) \ - ttt-client.c + ttt.c ttt_server_SOURCES = \ $(ttt_common_sources) \ + ttt-client.c \ ttt-server.c AM_CFLAGS = $(WARN_CFLAGS) $(TTT_CFLAGS) ttt_client_LDFLAGS = $(TTT_LIBS) -ttt_server_LDFLAGS = $(TTT_LIBS) +ttt_server_LDFLAGS = $(TTT_LIBS) -lpthread diff --git a/src/ttt-args.c b/src/ttt-args.c index 18a7d25..54cc0db 100644 --- a/src/ttt-args.c +++ b/src/ttt-args.c @@ -81,12 +81,14 @@ ttt_args_help (const char *argv0) printf (" --log-file=FILE\tFile to use for logging\n"); } +#if 0 static void ttt_args_usage (const char *argv0) { printf ("Usage: %s [OPTION] %s\n", argv0, TTT_ARGS_PROGRAM_ARGDOC); printf ("Try `%s --help' for more information.\n", argv0); } +#endif int ttt_args_parse(ttt_args_t *args, int argc, char *argv[]) diff --git a/src/ttt-client.c b/src/ttt-client.c index d6b6fe7..80fca84 100644 --- a/src/ttt-client.c +++ b/src/ttt-client.c @@ -1,4 +1,4 @@ -/* ttt.c - client-server tic-tac-toe game +/* ttt-client.c - client handling code for tic-tac-toe game server * * Copyright © 2005 Carl Worth * @@ -19,16 +19,48 @@ * Author: Carl Worth */ -#include "ttt.h" +#include "ttt-client.h" -int -main (int argc, char **argv) +struct _ttt_client { + ttt_server_t *server; + int socket; +}; + +ttt_client_t * +ttt_client_create (ttt_server_t *server, int socket) { - ttt_args_t args; + ttt_client_t *client; + + client = xmalloc (sizeof (ttt_client_t)); + + client->server = server; + client->socket = socket; - ttt_args_parse (&args, argc, argv); + return client; +} - /* XXX: insert code here */ +void +ttt_client_destroy (ttt_client_t *client) +{ + close (client->socket); - return 0; + free (client); } + +void +ttt_client_handle_requests (ttt_client_t *client) +{ +#define BUF_SIZE 1024 + + while (1) { + char buf[BUF_SIZE]; + int cnt; + cnt = read (client->socket, buf, BUF_SIZE); + if (cnt == 0) + break; + write (0, buf, cnt); + write (client->socket, buf, cnt); + } +} + + diff --git a/src/ttt-client.h b/src/ttt-client.h new file mode 100644 index 0000000..b067674 --- /dev/null +++ b/src/ttt-client.h @@ -0,0 +1,50 @@ +/* ttt-client.c - client handling code for tic-tac-toe game server + * + * Copyright © 2005 Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Carl Worth + */ + +#include "ttt.h" + +#include "ttt-server.h" + +#ifndef _TTT_CLIENT_H_ +#define _TTT_CLIENT_H_ + +typedef struct _ttt_client ttt_client_t; + +/* Create a new ttt_client_t for the given server and given a + * connected socket. + * + * Returns: A new ttt_client_t. Call ttt_client_destroy when finished + * with it. + * + * Errors: If any error occurs, (such as out-of-memory), this function + * will not return. + */ +ttt_client_t * +ttt_client_create (ttt_server_t *server, int socket); + +void +ttt_client_destroy (ttt_client_t *client); + +/* Loop forever handling client requests. Never returns. */ +void +ttt_client_handle_requests (ttt_client_t *client); + +#endif /* _TTT_CLIENT_H_ */ diff --git a/src/ttt-server.c b/src/ttt-server.c index 62c02cc..316a270 100644 --- a/src/ttt-server.c +++ b/src/ttt-server.c @@ -1,4 +1,4 @@ -/* ttt.c - client-server tic-tac-toe game +/* ttt-server.c - tic-tac-toe game server * * Copyright © 2005 Carl Worth * @@ -20,28 +20,56 @@ */ #include "ttt.h" +#include "ttt-client.h" #include "ttt-socket.h" +struct _ttt_server { + pthread_mutex_t mutex; + + ttt_client_t **clients; + int num_clients; +}; + static void -ttt_dispatch (int connected_socket) +ttt_server_init (ttt_server_t *server) { -#define BUF_SIZE 1024 - - while (1) { - char buf[BUF_SIZE]; - int cnt; - cnt = read (connected_socket, buf, BUF_SIZE); - if (cnt == 0) - break; - write (0, buf, cnt); - write (connected_socket, buf, cnt); - } + pthread_mutex_init (&server->mutex, NULL); + + server->clients = NULL; + server->num_clients = 0; +} + +static void +ttt_server_add_client (ttt_server_t *server, ttt_client_t *client) +{ + pthread_mutex_lock (&server->mutex); + + server->num_clients++; + server->clients = xrealloc (server->clients, + server->num_clients * sizeof (ttt_client_t *)); + + server->clients [server->num_clients - 1] = client; + + pthread_mutex_unlock (&server->mutex); +} + +static void +_accept_client (void *closure, int client_socket) +{ + ttt_server_t *server = closure; + ttt_client_t *client; + + client = ttt_client_create (server, client_socket); + + ttt_server_add_client (server, client); + + ttt_client_handle_requests (client); } static const char *WELCOME_MESSAGE = "Welcome to ttt-server. So far, this program is simply a demonstration\n" -"of a TCP/IP server that handles one client at a time. The server is\n" -"currently listening on:\n" +"of a TCP/IP server capable of handling multiple simultaneous clients.\n" +"The server is currently listening on:\n" "\n %s:%s\n" "\nTo test this program, simply connect a client to that host and port.\n" "For example:\n" @@ -52,16 +80,16 @@ static const char *WELCOME_MESSAGE = ", then \"close\" (and ) at the \"telnet> \" prompt.\n" "\nHave fun!\n" "-Carl\n" -"\nPS. The server handles only one client at a time, but multiple clients\n" -"may be able to connect simultaneously. Subsequent clients will see no\n" -"output from the server until all previous clients exit.\n" -"\nExtending the server to fork a new process for each client would be a fun\n" -"project for a motivated student (as would writing a custom client program).\n\n"; +"\nPS. The server does support multiple clients, but there is not yet any\n" +"interaction between the clients. The next step is probably to turn the\n" +"server into a simple chat server. After that, we should have the necessary\n" +"structure in place to start implementing the real tic-tac-toe protocol.\n\n"; int main (int argc, char **argv) { ttt_args_t args; + ttt_server_t server; int socket; ttt_args_parse (&args, argc, argv); @@ -73,8 +101,10 @@ main (int argc, char **argv) printf (WELCOME_MESSAGE, args.host, args.port, args.host, args.port); + ttt_server_init (&server); + while (1) - ttt_socket_accept (socket, ttt_dispatch); + ttt_socket_accept (socket, _accept_client, &server); /* We only reach here if something bad happened. */ return 1; diff --git a/src/ttt-server.h b/src/ttt-server.h new file mode 100644 index 0000000..773b034 --- /dev/null +++ b/src/ttt-server.h @@ -0,0 +1,29 @@ +/* ttt-server.c - tic-tac-toe game server + * + * Copyright © 2005 Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Carl Worth + */ + +#include "ttt.h" + +#ifndef _TTT_SERVER_H_ +#define _TTT_SERVER_H_ + +typedef struct _ttt_server ttt_server_t; + +#endif /* _TTT_SERVER_H_ */ diff --git a/src/ttt-socket.c b/src/ttt-socket.c index 18577ff..f185d36 100644 --- a/src/ttt-socket.c +++ b/src/ttt-socket.c @@ -146,11 +146,20 @@ ttt_socket_create_server (const char *host, const char *port) /* Exported: see ttt-socket.h for documentation. */ void -ttt_socket_accept (int listen_socket, ttt_socket_dispatch_func_t dispatch) +ttt_socket_accept (int listen_socket, + ttt_socket_accept_func_t accept, + void *closure) { + pid_t pid; int connected_socket; connected_socket = _wait_for_connection (listen_socket); - (dispatch) (connected_socket); + pid = xfork(); + + if (pid == 0) { + /* Child process. */ + (accept) (closure, connected_socket); + return; + } } diff --git a/src/ttt-socket.h b/src/ttt-socket.h index 59e89a5..909501e 100644 --- a/src/ttt-socket.h +++ b/src/ttt-socket.h @@ -24,7 +24,8 @@ #include "ttt.h" -typedef void (*ttt_socket_dispatch_func_t) (int connected_socket); +typedef void (*ttt_socket_accept_func_t) (void *closure, + int connected_socket); /* Create a socket, bind it to the given host and port, and listen in * preparation for incoming connections. See ttt_socket_accept for a @@ -45,10 +46,13 @@ ttt_socket_create_server (const char *host, const char *port); /* Wait for an incoming connection on listen_socket, (which should be * a valid socket on which bind and listen have already been - * called---see ttt_socket_create_server), then call the dispatch - * function with the new socket from the connection. + * called---see ttt_socket_create_server), then call the accept + * function with the closure argument and the new socket from the + * connection. */ void -ttt_socket_accept (int listen_socket, ttt_socket_dispatch_func_t dispatch); +ttt_socket_accept (int listen_socket, + ttt_socket_accept_func_t accept, + void *closure); #endif diff --git a/src/ttt.c b/src/ttt.c new file mode 100644 index 0000000..f211ae6 --- /dev/null +++ b/src/ttt.c @@ -0,0 +1,34 @@ +/* ttt.c - tic-tac-toe game client + * + * Copyright © 2005 Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Carl Worth + */ + +#include "ttt.h" + +int +main (int argc, char **argv) +{ + ttt_args_t args; + + ttt_args_parse (&args, argc, argv); + + /* XXX: insert code here */ + + return 0; +} diff --git a/src/ttt.h b/src/ttt.h index 203c637..316d744 100644 --- a/src/ttt.h +++ b/src/ttt.h @@ -40,6 +40,7 @@ #include #include #include +#include #define ASSERT_NOT_REACHED \ do { \ -- 2.43.0