#include #include #include #include #include #include #include #define TETRINGOD_PORT 75198 typedef struct { GConn *conn; TetringoGameEngine *game_engine; gboolean registered; char *name; guint score; } ClientData; typedef void (*CommandFunc)(ClientData *client, gchar **args); typedef struct { const char *command; gint num_args; CommandFunc func; } Command; static GServer *_server; static GList *_clients = NULL; static void quit(void) { gnet_server_delete(_server); exit(EXIT_FAILURE); } static void destroy_client_data(ClientData *client_data) { g_free(client_data->name); g_free(client_data); } static void command_place_func(ClientData *client, gchar **args) { printf("PLACE %s, %s\n", args[0], args[1]); } static void command_start_func(ClientData *client, gchar **args) { printf("START\n"); } static void command_stop_func(ClientData *client, gchar **args) { printf("STOP\n"); } static void command_register_func(ClientData *client, gchar **args) { /* TODO: Check if the name is already registered. */ client->name = g_strdup(args[0]); client->registered = TRUE; client->game_engine = tetringo_game_engine_local_new(); _clients = g_list_append(_clients, client); } static const Command commands[] = { { "PLACE", 2, command_place_func }, { "START", 0, command_start_func }, { "STOP", 0, command_stop_func }, { "REGISTER", -1, command_register_func }, { NULL, -1, NULL } }; static void handle_command(ClientData *client_data, const char *line) { const Command *cmd; gchar **tokens; gboolean found = FALSE; tokens = g_strsplit(line, " ", 2); if (tokens != NULL && tokens[0] != NULL) { for (cmd = commands; cmd->command != NULL && !found; cmd++) { if (!strcmp(tokens[0], cmd->command)) { if (cmd->num_args > 0) { gchar **args = g_strsplit(tokens[1], " ", cmd->num_args); cmd->func(client_data, args); g_strfreev(args); } else cmd->func(client_data, tokens + 1); found = TRUE; } } } if (!found) { gnet_conn_delete(client_data->conn); destroy_client_data(client_data); } g_strfreev(tokens); } static void client_func(GConn *conn, GConnEvent *event, ClientData *client_data) { switch (event->type) { case GNET_CONN_READ: handle_command(client_data, event->buffer); gnet_conn_readline(conn); break; case GNET_CONN_WRITE: /* Do nothing */ break; case GNET_CONN_CLOSE: case GNET_CONN_TIMEOUT: case GNET_CONN_ERROR: destroy_client_data(client_data); gnet_conn_delete(conn); break; default: g_assert_not_reached(); } } static void server_func(GServer *server, GConn *conn, gpointer user_data) { ClientData *client_data; if (conn == NULL) quit(); printf("Got a client!\n"); client_data = g_new0(ClientData, 1); client_data->conn = conn; gnet_conn_set_callback(conn, (GConnFunc)client_func, client_data); gnet_conn_set_watch_error(conn, TRUE); gnet_conn_readline(conn); } static void sigint_cb(int signum) { quit(); } int main(int argc, char **argv) { GMainLoop *mainloop; gnet_init(); mainloop = g_main_loop_new(NULL, FALSE); _server = gnet_server_new(NULL, TETRINGOD_PORT, server_func, NULL); if (_server == NULL) { fprintf(stderr, "Error: Unable to start server\n"); exit(EXIT_FAILURE); } signal(SIGINT, sigint_cb); g_main_loop_run(mainloop); return 0; }