#include "ttt-client.h"
+#include "ttt-command.h"
#include "ttt-error.h"
#include "ttt-lex.h"
#include "ttt-server.h"
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);
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
ttt_server_unregister_client (client->server, client);
+ free (client->name);
+ client->name = NULL;
+
yylex_destroy (client->scanner);
shutdown (client->socket, SHUT_RDWR);
{
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 *
}
/* 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);
}
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_ */
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
#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 */
#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;
};
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;
}
/* 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++;
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. */
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 *));
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"
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);
*/
#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.
* 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.
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_ */
{
char *ret;
+ if (s == NULL)
+ return NULL;
+
ret = strdup (s);
if (ret == NULL) {