From 84db9bf52aa25c19f7d547ea2dbec69ca4452300 Mon Sep 17 00:00:00 2001
From: Richard Worth <richard@theworths.org>
Date: Wed, 23 Nov 2005 22:11:28 +0000
Subject: [PATCH]         * PROTOCOL: Removed unused servername

        * src/ttt-client.h: * src/ttt-client.c:
        (_ttt_client_execute_helo), (_ttt_client_init),
        (_ttt_client_fini), (_execute_request), (ttt_client_get_name),
        (ttt_client_set_name): Added command descriptions structure. Match
        command case-insensitively, dispatch to execute
        function. Implement HELO command. Register on HELO instead of on
        connect.

        * src/ttt-server.h: * src/ttt-server.c: (ttt_server_init),
        (ttt_server_register_client), (ttt_server_unregister_client),
        (ttt_server_get_host), (ttt_server_get_port), (main): Added host
        and port to server. Make client registration name-based rather
        than id-based.

        * src/x.c: (xstrdup): Return NULL on NULL

        * src/ttt-lex.h: Regenerated
---
 src/ttt-client.c | 92 ++++++++++++++++++++++++++++++++++++++++++------
 src/ttt-client.h | 10 ++++--
 src/ttt-lex.h    |  7 ++--
 src/ttt-server.c | 55 ++++++++++++++++++++++++-----
 src/ttt-server.h | 20 +++++++++--
 src/x.c          |  3 ++
 6 files changed, 160 insertions(+), 27 deletions(-)

diff --git a/src/ttt-client.c b/src/ttt-client.c
index 8139ada..3fdcf83 100644
--- a/src/ttt-client.c
+++ b/src/ttt-client.c
@@ -21,6 +21,7 @@
 
 #include "ttt-client.h"
 
+#include "ttt-command.h"
 #include "ttt-error.h"
 #include "ttt-lex.h"
 #include "ttt-server.h"
@@ -35,12 +36,60 @@ struct _ttt_client {
     int socket;
     yyscan_t scanner;
 
-    int id;
+    char *name;
 
     char **request_strings;
     int num_request_strings;
 };
 
+typedef ttt_error_t (*ttt_command_func_t) (ttt_client_t *client,
+					   char **args,
+					   int num_args);
+
+static ttt_error_t
+_ttt_client_execute_helo (ttt_client_t *client,
+			  char         **args,
+			  int          num_args);
+
+typedef struct _ttt_command_description {
+    const char *command;
+    int args_min;
+    int args_max;
+    ttt_command_func_t execute;
+} ttt_command_description_t;
+
+ttt_command_description_t command_descriptions[] = {
+    {"HELO", 0, 1, _ttt_client_execute_helo}
+};
+
+static ttt_error_t
+_ttt_client_execute_helo (ttt_client_t *client,
+			  char         **args,
+			  int          num_args)
+{
+    ttt_error_t error;
+    char *response;
+
+    if (num_args == 1)
+	ttt_client_set_name (client, args[0]);
+
+    error = ttt_server_register_client (client->server, client);
+    if (error)
+	return error;
+
+    xasprintf (&response, "HELO %s %s %s\n", client->name,
+	       ttt_server_get_host (client->server),
+	       ttt_server_get_port (client->server));
+
+    ttt_client_send (client, response);
+
+    free (response);
+
+    return TTT_ERROR_NONE;
+}
+
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
 static void
 _free_request (ttt_client_t *client);
 
@@ -63,10 +112,7 @@ _ttt_client_init (ttt_client_t	*client,
     client->request_strings = NULL;
     client->num_request_strings = 0;
 
-    /* XXX: Probably want to register only as the result of the HELO
-       command.  Not only will that match the protocol correctly, but
-       it will also eliminate a race condition here. */
-    client->id = ttt_server_register_client (server, client);
+    client->name = NULL;
 }
 
 static void
@@ -76,6 +122,9 @@ _ttt_client_fini (ttt_client_t *client)
 
     ttt_server_unregister_client (client->server, client);
 
+    free (client->name);
+    client->name = NULL;
+
     yylex_destroy (client->scanner);
     shutdown (client->socket, SHUT_RDWR);
 
@@ -144,10 +193,23 @@ _execute_request (ttt_client_t *client)
 {
     int i;
 
-    for (i=0; i < client->num_request_strings; i++)
-	ttt_server_broadcast (client->server, client->request_strings[i]);
+    char *command = client->request_strings[0];
+    int num_args = client->num_request_strings-1;
+    ttt_command_description_t *desc;
 
-    return TTT_ERROR_NONE;
+    for (i=0; i < strlen (command); i++)
+	command[i] = toupper (command[i]);
+
+    for (i=0; i < ARRAY_SIZE(command_descriptions); i++) {
+	desc = &command_descriptions[i];
+	if (strcmp(command, desc->command) == 0) {
+	    if ((num_args < desc->args_min) || (num_args > desc->args_max))
+		return TTT_ERROR_SYNTAX;
+	    return (desc->execute) (client, &client->request_strings[1], num_args);
+	    }
+	}
+
+    return TTT_ERROR_COMMAND;
 }
 
 static void *
@@ -209,8 +271,16 @@ ttt_client_send (ttt_client_t *client, const char *message)
 }
 
 /* Exported: See ttt-client.h for documentation. */
-int
-ttt_client_get_id (ttt_client_t *client)
+const char*
+ttt_client_get_name (ttt_client_t *client)
+{
+    return client->name;
+}
+
+/* Exported: See ttt-client.h for documentation. */
+void
+ttt_client_set_name (ttt_client_t *client, const char *name)
 {
-    return client->id;
+    free (client->name);
+    client->name = xstrdup (name);
 }
diff --git a/src/ttt-client.h b/src/ttt-client.h
index ef74b87..06af64b 100644
--- a/src/ttt-client.h
+++ b/src/ttt-client.h
@@ -41,8 +41,12 @@ ttt_client_new (void *closure, int client_socket);
 void
 ttt_client_send (ttt_client_t *client, const char *message);
 
-/* Get a client's unique ID. */
-int
-ttt_client_get_id (ttt_client_t *client);
+/* Get a client's name. */
+const char*
+ttt_client_get_name (ttt_client_t *client);
+
+/* Set a client's name. */
+void
+ttt_client_set_name (ttt_client_t *client, const char *name);
 
 #endif /* _TTT_CLIENT_H_ */
diff --git a/src/ttt-lex.h b/src/ttt-lex.h
index 84463a2..964b6a0 100644
--- a/src/ttt-lex.h
+++ b/src/ttt-lex.h
@@ -202,6 +202,9 @@ void *yyalloc (yy_size_t ,yyscan_t yyscanner );
 void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
 void yyfree (void * ,yyscan_t yyscanner );
 
+#define yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
 #define yytext_ptr yytext_r
 
 #ifdef YY_HEADER_EXPORT_START_CONDITIONS
@@ -309,8 +312,8 @@ extern int yylex (yyscan_t yyscanner);
 #undef YY_DECL_IS_OURS
 #undef YY_DECL
 #endif
-#line 15 "ttt-lex.l"
+#line 17 "ttt-lex.l"
 
-#line 317 "ttt-lex.h"
+#line 320 "ttt-lex.h"
 #undef yyIN_HEADER
 #endif /* yyHEADER_H */
diff --git a/src/ttt-server.c b/src/ttt-server.c
index c50a797..e9043b4 100644
--- a/src/ttt-server.c
+++ b/src/ttt-server.c
@@ -23,11 +23,15 @@
 
 #include "ttt-args.h"
 #include "ttt-client.h"
+#include "ttt-error.h"
 #include "ttt-socket.h"
 
 struct _ttt_server {
     pthread_mutex_t mutex;
 
+    const char *host;
+    const char *port;
+
     int next_client_id;
 
     ttt_client_t **clients;
@@ -36,10 +40,13 @@ struct _ttt_server {
 };
 
 static void
-ttt_server_init (ttt_server_t *server)
+ttt_server_init (ttt_server_t *server, const char *host, const char *port)
 {
     pthread_mutex_init (&server->mutex, NULL);
 
+    server->host = host;
+    server->port = port;
+
     server->next_client_id = 0;
 
     server->clients = NULL;
@@ -48,16 +55,33 @@ ttt_server_init (ttt_server_t *server)
 }
 
 /* Exported: See ttt-server.h for documentation. */
-int
+ttt_error_t
 ttt_server_register_client (ttt_server_t *server, ttt_client_t *client)
 {
-    int id;
+    int i;
+    ttt_error_t error = TTT_ERROR_NONE;
+    char *name;
 
     pthread_mutex_lock (&server->mutex);
 
-    id = server->next_client_id++;
+    name = xstrdup (ttt_client_get_name (client));
+
+    if (name == NULL) {
+	xasprintf(&name, "user%03d", server->next_client_id++);
+	ttt_client_set_name (client, name);
+    }
+
+    /* XXX: If generated name is not unique, this will return an error,
+       which violates the protocol. */
+    for (i = 0; i < server->num_clients; i++) {
+	if (strcmp (ttt_client_get_name (server->clients[i]), name) == 0) {
+	    error = TTT_ERROR_INVALIDNAME;
+	    goto CLEANUP_LOCK;
+	}
+    }
 
-    printf ("Client %d has joined.\n", id);
+    printf ("Client %s has joined.\n", name);
+    free (name);
 
     server->num_clients++;
 
@@ -73,9 +97,10 @@ ttt_server_register_client (ttt_server_t *server, ttt_client_t *client)
 
     server->clients [server->num_clients - 1] = client;
 
+ CLEANUP_LOCK:
     pthread_mutex_unlock (&server->mutex);
 
-    return id;
+    return error;
 }
 
 /* Exported: See ttt-server.h for documentation. */
@@ -92,7 +117,7 @@ ttt_server_unregister_client (ttt_server_t *server, ttt_client_t *client)
 
     assert (i < server->num_clients);
 
-    printf ("Client %d has left.\n", ttt_client_get_id (client));
+    printf ("Client %s has left.\n", ttt_client_get_name (client));
 
     memmove (&server->clients[i], &server->clients[i+1],
 	     (server->num_clients - i - 1) * sizeof (ttt_client_t *));
@@ -115,6 +140,20 @@ ttt_server_broadcast (ttt_server_t *server, const char *message)
     pthread_mutex_unlock (&server->mutex);
 }
 
+/* Exported: See ttt-server.h for documentation. */
+const char*
+ttt_server_get_host (ttt_server_t *server)
+{
+    return server->host;
+}
+
+/* Exported: See ttt-server.h for documentation. */
+const char*
+ttt_server_get_port (ttt_server_t *server)
+{
+    return server->port;
+}
+
 static const char *WELCOME_MESSAGE = 
 "Welcome to ttt-server. So far, this program is still a demonstration\n"
 "TCP/IP server, acting something like a rather braindead chat server.\n"
@@ -161,7 +200,7 @@ main (int argc, char **argv)
 
     printf (WELCOME_MESSAGE, args.host, args.port, args.host, args.port);
 
-    ttt_server_init (&server);
+    ttt_server_init (&server, args.host, args.port);
 
     while (1)
 	ttt_socket_accept (socket, _ttt_server_accept, &server);
diff --git a/src/ttt-server.h b/src/ttt-server.h
index 77fb4bf..7cf3d97 100644
--- a/src/ttt-server.h
+++ b/src/ttt-server.h
@@ -20,13 +20,15 @@
  */
 
 #include "ttt.h"
+#include "ttt-error.h"
 
 #ifndef _TTT_SERVER_H_
 #define _TTT_SERVER_H_
 
 /* Register a new client with the server.
- *
- * Returns: the unique id of the client.
+ * 
+ * Returns: TTT_ERROR_NONE on success, else TTT_ERROR_INVALIDNAME if client's
+ * name is not unique.
  *
  * Locking: The server mutex will be acquired and held throughout the
  * execution of this function.
@@ -34,7 +36,7 @@
  * Errors: If an error (such as out-of-memory) occurs, this function
  * will not return.
  */
-int
+ttt_error_t
 ttt_server_register_client (ttt_server_t *server, ttt_client_t *client);
 
 /* Un-register a client from the server.
@@ -57,4 +59,16 @@ ttt_server_unregister_client (ttt_server_t *server, ttt_client_t *client);
 void
 ttt_server_broadcast (ttt_server_t *server, const char *message);
 
+/* Gets the server hostname.
+ *
+ */
+const char*
+ttt_server_get_host (ttt_server_t *server);
+
+/* Gets the server port
+ *
+ */
+const char*
+ttt_server_get_port (ttt_server_t *server);
+
 #endif /* _TTT_SERVER_H_ */
diff --git a/src/x.c b/src/x.c
index 8da355e..dc5c1dd 100644
--- a/src/x.c
+++ b/src/x.c
@@ -151,6 +151,9 @@ xstrdup (const char *s)
 {
     char *ret;
 
+    if (s == NULL)
+	return NULL;
+
     ret = strdup (s);
 
     if (ret == NULL) {
-- 
2.45.2