3 #include <glib/gprintf.h>
6 #include <sys/socket.h>
15 #include "gdkfbmanager.h"
19 int pid; /* -1 if not initialized */
22 GHashTable *clients = NULL;
23 GHashTable *new_clients = NULL;
24 Client *current_owner = NULL;
28 int create_master_socket (void)
31 struct sockaddr_un addr;
33 fd = socket (PF_UNIX, SOCK_STREAM, 0);
37 g_fprintf (stderr, "Error creating socket: %s\n", strerror(errno));
41 unlink ("/tmp/.fb.manager");
43 addr.sun_family = AF_UNIX;
44 strcpy (addr.sun_path, "/tmp/.fb.manager");
46 if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0)
48 g_fprintf (stderr, "Unable to bind socket: %s\n", strerror (errno));
54 if (listen (fd, 10) < 0)
56 g_fprintf (stderr, "Unable to listen on socket: %s\n", strerror (errno));
66 handle_new_client (void)
72 fd = accept (master_socket, NULL, NULL);
74 client = g_new (Client, 1);
79 setsockopt (fd, SOL_SOCKET, SO_PASSCRED,
80 &true_val, sizeof (true_val));
82 g_print ("Handling new client %p conntecting, fd = %d\n", client, fd);
84 g_hash_table_insert (new_clients, client, client);
90 fd_set *exception_fds;
95 send_message (Client *client, enum FBManagerMessageType type, int data)
97 struct FBManagerMessage msg;
102 send (client->socket, &msg, sizeof (msg), 0);
106 wait_for_ack (Client *client, int timeout_secs)
108 struct FBManagerMessage msg;
116 FD_SET(client->socket, &rfds);
118 tv.tv_sec = timeout_secs;
121 res = select (client->socket+1, &rfds, NULL, NULL, &tv);
126 res = recv (client->socket, &msg, sizeof (msg), 0);
127 if (res != sizeof (msg))
130 if (msg.msg_type == FB_MANAGER_ACK)
136 find_another_client (gpointer key,
149 if (client != current_owner)
154 switch_to_client (Client *client)
156 g_print ("Switch_to_client, client=%p, current_owner=%p\n", client, current_owner);
158 if ((current_owner == client) && (client != NULL))
163 g_print ("switching from client fd=%d\n", current_owner->socket);
164 send_message (current_owner, FB_MANAGER_SWITCH_FROM, 0);
165 wait_for_ack (current_owner, 3);
168 current_owner = client;
172 g_print ("switching to client fd=%d\n", current_owner->socket);
173 send_message (current_owner, FB_MANAGER_SWITCH_TO, 0);
178 close_client (Client *client)
180 Client *other_client;
181 g_print ("Closing client %p (fd=%d)\n",
182 client, client->socket);
184 if (current_owner == client)
187 g_hash_table_foreach (clients,
190 current_owner = NULL;
191 /* FIXME: This is a hack around the fact that the serial
192 mouse driver had problems with opening and closing
193 the device almost at the same time.
196 switch_to_client (other_client);
199 close (client->socket);
204 /* Returns TRUE if the client was closed */
206 read_client_data (Client *client)
208 struct FBManagerMessage fb_message;
211 char control_buffer[256];
212 struct cmsghdr *cmsg;
217 iov.iov_base = &fb_message;
218 iov.iov_len = sizeof (fb_message);
220 cmsg = (struct cmsghdr *)control_buffer;
225 msg.msg_control = cmsg;
226 msg.msg_controllen = 256;
229 g_print ("Reading client data:");
230 res = recvmsg (client->socket, &msg, 0);
231 g_print ("%d bytes, (error: %s)\n", res,
239 close_client (client);
243 if (res != sizeof (fb_message))
245 g_warning ("Packet with wrong size %d received", res);
249 switch (fb_message.msg_type) {
250 case FB_MANAGER_NEW_CLIENT:
251 if (client->pid != -1)
253 g_warning ("Got a NEW_CLIENT message from an old client");
257 for (cmsg = CMSG_FIRSTHDR(&msg);
259 cmsg = CMSG_NXTHDR(&msg,cmsg))
261 if (cmsg->cmsg_level == SOL_SOCKET &&
262 cmsg->cmsg_type == SCM_CREDENTIALS)
264 creds = (struct ucred *) CMSG_DATA(cmsg);
270 g_warning ("Got no credentials in NEW_CLIENT message");
271 close_client (client);
274 client->pid = creds->pid;
276 g_hash_table_insert (clients, GINT_TO_POINTER (client->pid), client);
278 g_print ("New client connected. Pid=%d\n", (int)creds->pid);
281 case FB_MANAGER_REQUEST_SWITCH_TO_PID:
282 if (client->pid == -1)
284 g_warning ("Got a message from an uninitialized client");
288 new_client = g_hash_table_lookup (clients, GINT_TO_POINTER (fb_message.data));
290 switch_to_client (new_client);
292 g_warning ("Switchto unknown PID");
295 if (client->pid == -1)
297 g_warning ("Got a message from an uninitialized client");
300 g_warning ("Got an unexpected ACK");
303 g_warning ("Got unknown package type %d", fb_message.msg_type);
309 /* Returns TRUE if the client was closed */
311 handle_client_data (gpointer key,
316 struct fd_data *data;
321 if (FD_ISSET (client->socket, data->exception_fds))
323 close_client (client);
326 else if (FD_ISSET (client->socket, data->read_fds))
328 return read_client_data (client);
335 set_fds (gpointer key,
339 struct fd_data *data;
345 FD_SET (client->socket, data->read_fds);
346 FD_SET (client->socket, data->exception_fds);
347 data->max_fd = MAX (data->max_fd,
355 fd_set exception_fds;
362 FD_ZERO (&exception_fds);
363 FD_SET (master_socket, &read_fds);
365 data.read_fds = &read_fds;
366 data.exception_fds = &exception_fds;
367 data.max_fd = master_socket;
369 g_hash_table_foreach (clients,
372 g_hash_table_foreach (new_clients,
377 res = select (data.max_fd+1,
378 &read_fds, NULL, &exception_fds,
381 if (FD_ISSET (master_socket, &read_fds))
382 handle_new_client ();
384 g_hash_table_foreach_remove (clients,
387 g_hash_table_foreach_remove (new_clients,
395 main (int argc, char *argv[])
397 clients = g_hash_table_new (g_direct_hash,
399 new_clients = g_hash_table_new (g_direct_hash,
402 create_master_socket ();