1 /* Unique - Single Instance Backendlication library
2 * uniquebackend-bacon.c: Unix domain socket implementation of UniqueBackend
3 *
4 * Copyright (C) 2007 Emmanuele Bassi <ebassi@gnome.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 * Based on libbacon implementation in Totem
22 * Copyright (C) 2003 Bastien Nocera
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <sys/socket.h>
39 #include <sys/un.h>
40 #include <errno.h>
41 #include <glib/gstdio.h>
42
43 #include "../uniqueinternals.h"
44 #include "uniquefactory-bacon.h"
45 #include "uniquemessage-bacon.h"
46 #include "uniquebackend-bacon.h"
47
48 #ifndef UNIX_PATH_MAX
49 #define UNIX_PATH_MAX 108
50 #endif
51
52 struct _UniqueBackendBacon
53 {
54 UniqueBackend parent_instance;
55
56 gchar *socket_path;
57 gint socket_fd;
58
59 GIOChannel *channel;
60 guint source_id;
61
62 GSList *connections;
63
64 guint is_server : 1;
65 };
66
67 struct _UniqueBackendBaconClass
68 {
69 UniqueBackendClass parent_class;
70 };
71
72 G_DEFINE_TYPE (UniqueBackendBacon, unique_backend_bacon, UNIQUE_TYPE_BACKEND);
73
74
75 static gboolean
is_socket(const gchar * path)76 is_socket (const gchar *path)
77 {
78 struct stat stat_buf;
79
80 if (g_stat (path, &stat_buf) == -1)
81 return FALSE;
82
83 return (S_ISSOCK (stat_buf.st_mode));
84 }
85
86 static gboolean
is_socket_owned_by_user(const gchar * path)87 is_socket_owned_by_user (const gchar *path)
88 {
89 struct stat stat_buf;
90
91 if (g_stat (path, &stat_buf) == -1)
92 return FALSE;
93
94 return (S_ISSOCK (stat_buf.st_mode) && stat_buf.st_uid == geteuid ());
95 }
96
97 /* free the return value */
98 static gchar *
find_file_with_pattern(const gchar * path,const gchar * pattern)99 find_file_with_pattern (const gchar *path,
100 const gchar *pattern)
101 {
102 GDir *dir;
103 gchar *retval;
104 const gchar *file;
105 GPatternSpec *pat;
106
107 dir = g_dir_open (path, 0, NULL);
108 if (!dir)
109 return NULL;
110
111 pat = g_pattern_spec_new (pattern);
112 if (!pat)
113 {
114 g_dir_close (dir);
115 return NULL;
116 }
117
118 retval = NULL;
119 while ((file = g_dir_read_name (dir)) != NULL)
120 {
121 if (g_pattern_match_string (pat, file))
122 {
123 gchar *temp = g_build_filename (path, file, NULL);
124
125 if (is_socket_owned_by_user (temp))
126 {
127 retval = temp;
128 break;
129 }
130
131 g_free (temp);
132 }
133 }
134
135 g_pattern_spec_free (pat);
136 g_dir_close (dir);
137
138 return retval;
139 }
140
141 /* free the returned value */
142 static gchar *
find_socket_file(const gchar * name)143 find_socket_file (const gchar *name)
144 {
145 const gchar *token;
146 gchar *basename, *path;
147 gchar *tmpdir;
148
149 /* socket file name template:
150 * /tmp/unique/org.gnome.YourApplication.token.process-id
151 */
152 token = g_getenv ("DISPLAY");
153 if (!token || *token == '\0')
154 {
155 g_warning ("The $DISPLAY environment variable is not set. You must "
156 "set it in order for the application '%s' to run correctly.",
157 g_get_prgname ());
158 return NULL;
159 }
160
161 basename = g_strconcat (name, ".", token, ".*", NULL);
162 tmpdir = g_build_path (G_DIR_SEPARATOR_S,
163 g_get_tmp_dir (),
164 "unique",
165 NULL);
166
167 if (g_mkdir_with_parents (tmpdir, 0777) == -1)
168 {
169 if (errno != EEXIST)
170 {
171 g_warning ("Unable to create socket path `%s': %s",
172 tmpdir,
173 g_strerror (errno));
174 return NULL;
175 }
176 }
177
178 path = find_file_with_pattern (tmpdir, basename);
179 if (path)
180 {
181 g_free (tmpdir);
182 g_free (basename);
183
184 return path;
185 }
186
187 g_free (basename);
188
189 basename = g_strdup_printf ("%s.%s.%d", name, token, getpid ());
190
191 path = g_build_filename (tmpdir, basename, NULL);
192
193 g_free (tmpdir);
194 g_free (basename);
195
196 return path;
197 }
198
199 static gboolean
server_socket_cb(GIOChannel * source,GIOCondition condition,gpointer data)200 server_socket_cb (GIOChannel *source,
201 GIOCondition condition,
202 gpointer data)
203 {
204 UniqueBackendBacon *backend_bacon = data;
205
206 if (!backend_bacon)
207 return FALSE;
208
209 if (!backend_bacon->channel)
210 return FALSE;
211
212 if (condition & G_IO_IN)
213 {
214 UniqueFactoryBacon *factory;
215
216 factory = g_object_new (UNIQUE_TYPE_FACTORY_BACON, NULL);
217 factory->parent = UNIQUE_BACKEND (backend_bacon)->parent;
218
219 if (unique_factory_bacon_accept (factory, backend_bacon->socket_fd))
220 backend_bacon->connections = g_slist_prepend (backend_bacon->connections, factory);
221 else
222 {
223 g_warning ("Could not accept the connection");
224 g_object_unref (factory);
225 }
226 }
227
228 if (condition & G_IO_HUP)
229 g_debug (G_STRLOC ": factory hung up");
230 else if (condition & G_IO_ERR)
231 g_warning ("Server error");
232
233 return TRUE;
234 }
235
236 static gboolean
setup_connection(UniqueBackendBacon * backend_bacon)237 setup_connection (UniqueBackendBacon *backend_bacon)
238 {
239 g_assert (backend_bacon->socket_fd != -1);
240 g_assert (backend_bacon->channel == NULL);
241
242 backend_bacon->channel = g_io_channel_unix_new (backend_bacon->socket_fd);
243 g_io_channel_set_line_term (backend_bacon->channel, "\r\n", 2);
244
245 backend_bacon->source_id = g_io_add_watch (backend_bacon->channel,
246 G_IO_IN | G_IO_ERR | G_IO_HUP,
247 server_socket_cb,
248 backend_bacon);
249 return (backend_bacon->source_id > 0);
250 }
251
252 static gboolean
try_client(UniqueBackendBacon * backend)253 try_client (UniqueBackendBacon *backend)
254 {
255 struct sockaddr_un uaddr;
256 size_t path_len;
257 int res;
258
259 g_assert (backend->socket_path != NULL);
260
261 path_len = MIN (strlen (backend->socket_path) + 1, UNIX_PATH_MAX);
262
263 uaddr.sun_family = AF_UNIX;
264 strncpy (uaddr.sun_path, backend->socket_path, path_len);
265
266 backend->socket_fd = socket (PF_UNIX, SOCK_STREAM, 0);
267
268 res = connect (backend->socket_fd,
269 (struct sockaddr *) &uaddr,
270 sizeof (uaddr));
271
272 if (res == -1)
273 {
274 backend->socket_fd = -1;
275 return FALSE;
276 }
277
278 return TRUE;
279 }
280
281 #define MAX_CONNECTIONS 5
282
283 static void
create_server(UniqueBackendBacon * backend)284 create_server (UniqueBackendBacon *backend)
285 {
286 struct sockaddr_un uaddr;
287 size_t path_len;
288 int res;
289
290 g_assert (backend->socket_path != NULL);
291
292 path_len = MIN (strlen (backend->socket_path) + 1, UNIX_PATH_MAX);
293
294 uaddr.sun_family = AF_UNIX;
295 strncpy (uaddr.sun_path, backend->socket_path, path_len);
296
297 backend->socket_fd = socket (PF_UNIX, SOCK_STREAM, 0);
298 res = bind (backend->socket_fd, (struct sockaddr *) &uaddr, sizeof (uaddr));
299 if (res == -1)
300 {
301 backend->socket_fd = -1;
302 return;
303 }
304
305 /* For security concern, the socket files should be set 700 */
306 g_chmod (backend->socket_path, 0700);
307
308 listen (backend->socket_fd, MAX_CONNECTIONS);
309 setup_connection (backend);
310 }
311
312 static void
unique_backend_bacon_close_connection(UniqueBackendBacon * backend)313 unique_backend_bacon_close_connection (UniqueBackendBacon *backend)
314 {
315 if (backend->source_id)
316 {
317 g_source_remove (backend->source_id);
318 backend->source_id = 0;
319 }
320
321 if (backend->channel)
322 {
323 g_io_channel_shutdown (backend->channel, FALSE, NULL);
324 g_io_channel_unref (backend->channel);
325 backend->channel = NULL;
326 }
327
328 if (backend->socket_fd != -1)
329 close (backend->socket_fd);
330
331 if (g_unlink (backend->socket_path) == -1)
332 {
333 if (errno != ENOENT)
334 g_warning ("Unable to remove old socket file: %s",
335 g_strerror (errno));
336 }
337
338 g_slist_foreach (backend->connections, (GFunc) g_object_unref, NULL);
339 g_slist_free (backend->connections);
340 }
341
342 static void
unique_backend_bacon_finalize(GObject * gobject)343 unique_backend_bacon_finalize (GObject *gobject)
344 {
345 UniqueBackendBacon *backend_bacon;
346
347 backend_bacon = UNIQUE_BACKEND_BACON (gobject);
348
349 if (backend_bacon->is_server || backend_bacon->connections)
350 unique_backend_bacon_close_connection (backend_bacon);
351
352 g_free (backend_bacon->socket_path);
353
354 G_OBJECT_CLASS (unique_backend_bacon_parent_class)->finalize (gobject);
355 }
356
357 static UniqueResponse
unique_backend_bacon_send_message(UniqueBackend * backend,gint command_id,UniqueMessageData * message,guint time_)358 unique_backend_bacon_send_message (UniqueBackend *backend,
359 gint command_id,
360 UniqueMessageData *message,
361 guint time_)
362 {
363 UniqueBackendBacon *backend_bacon;
364 UniqueResponse response_id;
365 gchar *packed, *response;
366 gsize packed_len;
367 GString *resp_buffer;
368 gsize res, term;
369 gchar buf;
370
371 backend_bacon = UNIQUE_BACKEND_BACON (backend);
372
373 if (!try_client (backend_bacon))
374 {
375 g_warning ("Unable to send message: no connection to the "
376 "running instance found (stale named pipe)");
377
378 /* force removal of the named pipe */
379 if (g_unlink (backend_bacon->socket_path) == -1)
380 {
381 if (errno != ENOENT)
382 {
383 g_warning ("Unable to remove stale named pipe: %s",
384 g_strerror (errno));
385 }
386 }
387
388 if (!try_client (backend_bacon))
389 return UNIQUE_RESPONSE_FAIL;
390 }
391
392 packed = unique_message_data_pack (backend->parent,
393 command_id, message, time_,
394 &packed_len);
395 if (write (backend_bacon->socket_fd, packed, packed_len) == -1)
396 {
397 g_warning ("Unable to send message: %s", g_strerror (errno));
398 g_free (packed);
399
400 return UNIQUE_RESPONSE_FAIL;
401 }
402 else
403 fsync (backend_bacon->socket_fd);
404
405 g_free (packed);
406
407 resp_buffer = g_string_new (NULL);
408 buf = term = res = 0;
409
410 res = read (backend_bacon->socket_fd, &buf, 1);
411 while (res > 0 && buf != '\n')
412 {
413 resp_buffer = g_string_append_c (resp_buffer, buf);
414 term += res;
415
416 res = read (backend_bacon->socket_fd, &buf, 1);
417 if (res < 0)
418 {
419 g_warning ("Unable to receive the response: %s", g_strerror (errno));
420
421 close (backend_bacon->socket_fd);
422 backend_bacon->socket_fd = -1;
423
424 g_string_free (resp_buffer, TRUE);
425
426 return UNIQUE_RESPONSE_FAIL;
427 }
428 }
429
430 response = g_string_free (resp_buffer, FALSE);
431 response[term - 1] = '\0';
432
433 response_id = unique_response_from_string (response);
434
435 g_free (response);
436
437 return response_id;
438 }
439
440 static gboolean
unique_backend_bacon_request_name(UniqueBackend * backend)441 unique_backend_bacon_request_name (UniqueBackend *backend)
442 {
443 UniqueBackendBacon *backend_bacon;
444 const gchar *name;
445
446 g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), FALSE);
447
448 name = unique_backend_get_name (backend);
449 g_assert (name != NULL);
450
451 backend_bacon = UNIQUE_BACKEND_BACON (backend);
452
453 g_assert (backend_bacon->socket_path == NULL);
454 backend_bacon->socket_path = find_socket_file (name);
455 if (!is_socket (backend_bacon->socket_path))
456 {
457 create_server (backend_bacon);
458 backend_bacon->is_server = TRUE;
459 }
460 else
461 {
462 if (!try_client (backend_bacon))
463 {
464 if (g_unlink (backend_bacon->socket_path) == -1)
465 {
466 if (errno != ENOENT)
467 g_warning ("Unable to remove stale pipe: %s",
468 g_strerror (errno));
469 }
470
471 create_server (backend_bacon);
472 backend_bacon->is_server = TRUE;
473 }
474 else
475 backend_bacon->is_server = FALSE;
476 }
477
478 return backend_bacon->is_server;
479 }
480
481 static void
unique_backend_bacon_class_init(UniqueBackendBaconClass * klass)482 unique_backend_bacon_class_init (UniqueBackendBaconClass *klass)
483 {
484 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
485 UniqueBackendClass *backend_class = UNIQUE_BACKEND_CLASS (klass);
486
487 gobject_class->finalize = unique_backend_bacon_finalize;
488
489 backend_class->request_name = unique_backend_bacon_request_name;
490 backend_class->send_message = unique_backend_bacon_send_message;
491 }
492
493 static void
unique_backend_bacon_init(UniqueBackendBacon * backend_bacon)494 unique_backend_bacon_init (UniqueBackendBacon *backend_bacon)
495 {
496 backend_bacon->is_server = FALSE;
497
498 backend_bacon->socket_fd = -1;
499 backend_bacon->socket_path = NULL;
500 }
501