X-Git-Url: https://git.cworth.org/git?p=ttt;a=blobdiff_plain;f=src%2Fttt-client.c;h=8139ada1de03cb04a2e7c7c986ebd0aa1d136983;hp=b42db7a95064811b95fff78b4f0070236b4fe69c;hb=c6398c6a1b59f6eddefc9f9ce577017b15677251;hpb=80c3009d01077a141a0803267a1f0aff217ed61c diff --git a/src/ttt-client.c b/src/ttt-client.c index b42db7a..8139ada 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,17 +19,198 @@ * Author: Carl Worth */ -#include "ttt.h" +#include "ttt-client.h" -int -main (int argc, char **argv) +#include "ttt-error.h" +#include "ttt-lex.h" +#include "ttt-server.h" +#include "ttt-socket.h" +#include "ttt-token.h" + +struct _ttt_client { + pthread_mutex_t mutex; + pthread_t thread; + + ttt_server_t *server; + int socket; + yyscan_t scanner; + + int id; + + char **request_strings; + int num_request_strings; +}; + +static void +_free_request (ttt_client_t *client); + +static void +_ttt_client_init (ttt_client_t *client, + ttt_server_t *server, + int socket) +{ + FILE *file; + + pthread_mutex_init (&client->mutex, NULL); + + client->server = server; + client->socket = socket; + + file = xfdopen (socket, "r"); + yylex_init(&client->scanner); + yyset_in (file, client->scanner); + + 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); +} + +static void +_ttt_client_fini (ttt_client_t *client) +{ + pthread_mutex_lock (&client->mutex); + + ttt_server_unregister_client (client->server, client); + + yylex_destroy (client->scanner); + shutdown (client->socket, SHUT_RDWR); + + _free_request (client); + + pthread_mutex_unlock (&client->mutex); + + pthread_mutex_destroy (&client->mutex); +} + +/* XXX: The memory management for the request strings is pretty cheesy. */ +static void +_append_to_request (ttt_client_t *client, + const char *string) +{ + client->num_request_strings++; + client->request_strings = + xrealloc (client->request_strings, + client->num_request_strings * sizeof (char *)); + + client->request_strings[client->num_request_strings - 1] = xstrdup (string); +} + +static void +_free_request (ttt_client_t *client) +{ + int i; + + for (i = 0; i < client->num_request_strings; i++) + free (client->request_strings[i]); + + free (client->request_strings); + + client->request_strings = NULL; + client->num_request_strings = 0; +} + +static ttt_status_t +_read_request (ttt_client_t *client) +{ + ttt_token_t token; + + _free_request (client); + + while (1) { + token = yylex (client->scanner); + /* Yes, EOF in two different enums is pretty ugly. */ + if (token == TTT_TOKEN_EOF) + return TTT_STATUS_EOF; + + if (token == TTT_TOKEN_NEWLINE) { + if (client->num_request_strings) + return TTT_STATUS_SUCCESS; + else + continue; + } + + assert (token == TTT_TOKEN_STRING); + + _append_to_request (client, yyget_text (client->scanner)); + } +} + +static ttt_error_t +_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]); + + return TTT_ERROR_NONE; +} + +static void * +_handle_requests_thread (void *closure) { - ttt_args_t args; - int args_first; + ttt_status_t status; + ttt_error_t error; + ttt_client_t *client = closure; - ttt_args_parse (&args, argc, argv, &args_first); + while (1) { - /* XXX: insert code here */ + status = _read_request (client); + if (status == TTT_STATUS_EOF) + break; + if (status) + ASSERT_NOT_REACHED; - return 0; + error = _execute_request (client); + if (error) + ttt_client_send (client, ttt_error_string (error)); + } + + _ttt_client_fini (client); + free (client); + + return (void *) 0; +} + +/* Exported: See ttt-client.h for documentation. */ +void +ttt_client_new (void *closure, int client_socket) +{ + ttt_server_t *server = closure; + ttt_client_t *client; + int err; + + client = xmalloc (sizeof (ttt_client_t)); + + _ttt_client_init (client, server, client_socket); + + err = pthread_create (&client->thread, NULL, + _handle_requests_thread, client); + if (err != 0) { + fprintf (stderr, "Error: pthread_create failed: %s. Aborting.\n", + strerror (err)); + exit (1); + } +} + +/* Exported: See ttt-client.h for documentation. */ +void +ttt_client_send (ttt_client_t *client, const char *message) +{ + pthread_mutex_lock (&client->mutex); + + ttt_socket_write (client->socket, message, strlen (message)); + + pthread_mutex_unlock (&client->mutex); +} + +/* Exported: See ttt-client.h for documentation. */ +int +ttt_client_get_id (ttt_client_t *client) +{ + return client->id; }