]> git.cworth.org Git - ttt/blob - src/ttt-server.c
* Missing files from rev235
[ttt] / src / ttt-server.c
1 /* ttt-server.c - tic-tac-toe game server
2  *
3  * Copyright © 2005 Carl Worth
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Author: Carl Worth <cworth@cworth.org>
20  */
21
22 #include "ttt-server.h"
23
24 #include "ttt-args.h"
25 #include "ttt-client.h"
26 #include "ttt-error.h"
27 #include "ttt-socket.h"
28
29 struct _ttt_server {
30     pthread_mutex_t mutex;
31
32     const char *host;
33     const char *port;
34
35     int next_client_id;
36
37     ttt_client_t **clients;
38     int clients_size;
39     int num_clients;
40 };
41
42 static void
43 ttt_server_init (ttt_server_t *server, const char *host, const char *port)
44 {
45     pthread_mutex_init (&server->mutex, NULL);
46
47     server->host = host;
48     server->port = port;
49
50     server->next_client_id = 0;
51
52     server->clients = NULL;
53     server->clients_size = 0;
54     server->num_clients = 0;
55 }
56
57 /* Exported: See ttt-server.h for documentation. */
58 ttt_error_t
59 ttt_server_register_client (ttt_server_t *server, ttt_client_t *client)
60 {
61     int i;
62     ttt_error_t error = TTT_ERROR_NONE;
63     char *name;
64
65     pthread_mutex_lock (&server->mutex);
66
67     name = xstrdup (ttt_client_get_name (client));
68
69     if (name == NULL) {
70         xasprintf(&name, "user%03d", server->next_client_id++);
71         ttt_client_set_name (client, name);
72     }
73
74     /* XXX: If generated name is not unique, this will return an error,
75        which violates the protocol. */
76     for (i = 0; i < server->num_clients; i++) {
77         if (strcmp (ttt_client_get_name (server->clients[i]), name) == 0) {
78             error = TTT_ERROR_INVALIDNAME;
79             goto CLEANUP_LOCK;
80         }
81     }
82
83     printf ("Client %s has joined.\n", name);
84     free (name);
85
86     server->num_clients++;
87
88     if (server->num_clients > server->clients_size) {
89         if (server->clients_size == 0)
90             server->clients_size = 1;
91         else
92             server->clients_size *= 2;
93
94         server->clients = xrealloc (server->clients,
95                                     server->clients_size * sizeof (ttt_client_t *));
96     }
97
98     server->clients [server->num_clients - 1] = client;
99
100  CLEANUP_LOCK:
101     pthread_mutex_unlock (&server->mutex);
102
103     return error;
104 }
105
106 /* Exported: See ttt-server.h for documentation. */
107 void
108 ttt_server_unregister_client (ttt_server_t *server, ttt_client_t *client)
109 {
110     int i;
111
112     pthread_mutex_lock (&server->mutex);
113
114     for (i = 0; i < server->num_clients; i++)
115         if (server->clients[i] == client)
116             break;
117
118     assert (i < server->num_clients);
119
120     printf ("Client %s has left.\n", ttt_client_get_name (client));
121
122     memmove (&server->clients[i], &server->clients[i+1],
123              (server->num_clients - i - 1) * sizeof (ttt_client_t *));
124
125     server->num_clients--;
126
127     pthread_mutex_unlock (&server->mutex);
128 }
129
130 void
131 ttt_server_broadcast (ttt_server_t *server, const char *message)
132 {
133     int i;
134
135     pthread_mutex_lock (&server->mutex);
136
137     for (i = 0; i < server->num_clients; i++)
138         ttt_client_send (server->clients[i], message);
139
140     pthread_mutex_unlock (&server->mutex);
141 }
142
143 /* Exported: See ttt-server.h for documentation. */
144 const char*
145 ttt_server_get_host (ttt_server_t *server)
146 {
147     return server->host;
148 }
149
150 /* Exported: See ttt-server.h for documentation. */
151 const char*
152 ttt_server_get_port (ttt_server_t *server)
153 {
154     return server->port;
155 }
156
157 static const char *WELCOME_MESSAGE = 
158 "Welcome to ttt-server. So far, this program is still a demonstration\n"
159 "TCP/IP server, acting something like a rather braindead chat server.\n"
160 "The server is currently listening on:\n"
161 "\n     %s:%s\n"
162 "\nTo test this, simply connect one or more clients to that host and port.\n"
163 "For example:\n"
164 "\n     telnet %s %s\n"
165 "\nOnce you have connected a client, the server will send each line of text\n"
166 "it receives to all connected clients. The server reports client joins and\n"
167 "departures on stdout.\n"
168 "\nNote that to terminate the telnet client you type Control-], then\n"
169 "<Enter>, then \"close\" (and <Enter>) at the \"telnet> \" prompt.\n"
170 "\nHave fun!\n"
171 "-Carl\n"
172 "\nPS. At this point we're ready to leave the demonstration phase and to\n"
173 "begin implementing TTTP (tic-tac-toe protocol) as well as fixing the\n"
174 "protocol specifcation. We don't need a custom client to move forward on\n"
175 "the server (that is one of the ideas behind using a telnet-compatible\n"
176 "protocol), but a custom client would still be a fine project for a\n"
177 "motivated beginning programmer.\n\n";
178
179 static void
180 _ttt_server_accept (void *closure, int client_socket)
181 {
182     ttt_server_t *server = closure;
183
184     ttt_client_new (server, client_socket);
185 }
186
187 int 
188 main (int argc, char **argv)
189 {
190     ttt_args_t args;
191     ttt_server_t server;
192     int socket;
193
194     ttt_args_parse (&args, argc, argv);
195
196     if (args.log_file)
197         xfreopen (args.log_file, "a", stderr);
198
199     socket = ttt_socket_create_server (args.host, args.port);
200
201     printf (WELCOME_MESSAGE, args.host, args.port, args.host, args.port);
202
203     ttt_server_init (&server, args.host, args.port);
204
205     while (1)
206         ttt_socket_accept (socket, _ttt_server_accept, &server);
207
208     /* We only reach here if something bad happened. */
209     return 1;
210 }