1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2007 Novell, Inc.
4 * Copyright (C) 2008 Red Hat, Inc.
5 * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "config.h"
23
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <string.h>
32
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <glib-object.h>
36
37 #include <X11/ICE/ICElib.h>
38 #include <X11/ICE/ICEutil.h>
39 #include <X11/ICE/ICEconn.h>
40 #include <X11/SM/SMlib.h>
41
42 /* Get the proto for _IceTransNoListen */
43 #define ICE_t
44 #define TRANS_SERVER
45 #include <X11/Xtrans/Xtrans.h>
46 #undef ICE_t
47 #undef TRANS_SERVER
48
49 #include "gsm-xsmp-server.h"
50 #include "gsm-xsmp-client.h"
51 #include "gsm-util.h"
52
53 /* ICEauthority stuff */
54 /* Various magic numbers stolen from iceauth.c */
55 #define GSM_ICE_AUTH_RETRIES 10
56 #define GSM_ICE_AUTH_INTERVAL 2 /* 2 seconds */
57 #define GSM_ICE_AUTH_LOCK_TIMEOUT 600 /* 10 minutes */
58
59 #define GSM_ICE_MAGIC_COOKIE_AUTH_NAME "MIT-MAGIC-COOKIE-1"
60 #define GSM_ICE_MAGIC_COOKIE_LEN 16
61
62 #define GSM_XSMP_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_XSMP_SERVER, GsmXsmpServerPrivate))
63
64 struct GsmXsmpServerPrivate
65 {
66 GsmStore *client_store;
67
68 IceListenObj *xsmp_sockets;
69 int num_xsmp_sockets;
70 int num_local_xsmp_sockets;
71 gboolean stopping;
72 };
73
74 enum {
75 PROP_0,
76 PROP_CLIENT_STORE
77 };
78
79 static void gsm_xsmp_server_class_init (GsmXsmpServerClass *klass);
80 static void gsm_xsmp_server_init (GsmXsmpServer *xsmp_server);
81 static void gsm_xsmp_server_finalize (GObject *object);
82
83 static gpointer xsmp_server_object = NULL;
84
85 G_DEFINE_TYPE (GsmXsmpServer, gsm_xsmp_server, G_TYPE_OBJECT)
86
87 typedef struct {
88 GsmXsmpServer *server;
89 IceListenObj listener;
90 } GsmIceConnectionData;
91
92 typedef struct {
93 guint watch_id;
94 guint protocol_timeout;
95 } GsmIceConnectionWatch;
96
97 static void
disconnect_ice_connection(IceConn ice_conn)98 disconnect_ice_connection (IceConn ice_conn)
99 {
100 IceSetShutdownNegotiation (ice_conn, FALSE);
101 IceCloseConnection (ice_conn);
102 }
103
104 static void
free_ice_connection_watch(GsmIceConnectionWatch * data)105 free_ice_connection_watch (GsmIceConnectionWatch *data)
106 {
107 if (data->watch_id) {
108 g_source_remove (data->watch_id);
109 data->watch_id = 0;
110 }
111
112 if (data->protocol_timeout) {
113 g_source_remove (data->protocol_timeout);
114 data->protocol_timeout = 0;
115 }
116
117 g_free (data);
118 }
119
120 static gboolean
ice_protocol_timeout(IceConn ice_conn)121 ice_protocol_timeout (IceConn ice_conn)
122 {
123 GsmIceConnectionWatch *data;
124
125 g_debug ("GsmXsmpServer: ice_protocol_timeout for IceConn %p with status %d",
126 ice_conn, IceConnectionStatus (ice_conn));
127
128 data = ice_conn->context;
129
130 free_ice_connection_watch (data);
131 disconnect_ice_connection (ice_conn);
132
133 return FALSE;
134 }
135
136 static gboolean
auth_iochannel_watch(GIOChannel * source,GIOCondition condition,IceConn ice_conn)137 auth_iochannel_watch (GIOChannel *source,
138 GIOCondition condition,
139 IceConn ice_conn)
140 {
141
142 GsmIceConnectionWatch *data;
143 gboolean keep_going;
144
145 data = ice_conn->context;
146
147 switch (IceProcessMessages (ice_conn, NULL, NULL)) {
148 case IceProcessMessagesSuccess:
149 keep_going = TRUE;
150 break;
151 case IceProcessMessagesIOError:
152 g_debug ("GsmXsmpServer: IceProcessMessages returned IceProcessMessagesIOError");
153 free_ice_connection_watch (data);
154 disconnect_ice_connection (ice_conn);
155 keep_going = FALSE;
156 break;
157 case IceProcessMessagesConnectionClosed:
158 g_debug ("GsmXsmpServer: IceProcessMessages returned IceProcessMessagesConnectionClosed");
159 free_ice_connection_watch (data);
160 keep_going = FALSE;
161 break;
162 default:
163 g_assert_not_reached ();
164 }
165
166 return keep_going;
167 }
168
169 /* IceAcceptConnection returns a new ICE connection that is in a "pending" state,
170 * this is because authentification may be necessary.
171 * So we've to authenticate it, before accept_xsmp_connection() is called.
172 * Then each GsmXSMPClient will have its own IceConn watcher
173 */
174 static void
auth_ice_connection(IceConn ice_conn)175 auth_ice_connection (IceConn ice_conn)
176 {
177 GIOChannel *channel;
178 GsmIceConnectionWatch *data;
179 int fd;
180
181 g_debug ("GsmXsmpServer: auth_ice_connection()");
182
183 fd = IceConnectionNumber (ice_conn);
184 fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
185 channel = g_io_channel_unix_new (fd);
186
187 data = g_new0 (GsmIceConnectionWatch, 1);
188 ice_conn->context = data;
189
190 data->protocol_timeout = g_timeout_add_seconds (5,
191 (GSourceFunc)ice_protocol_timeout,
192 ice_conn);
193 data->watch_id = g_io_add_watch (channel,
194 G_IO_IN | G_IO_ERR,
195 (GIOFunc)auth_iochannel_watch,
196 ice_conn);
197 g_io_channel_unref (channel);
198 }
199
200 /* This is called (by glib via xsmp->ice_connection_watch) when a
201 * connection is first received on the ICE listening socket.
202 */
203 static gboolean
accept_ice_connection(GIOChannel * source,GIOCondition condition,GsmIceConnectionData * data)204 accept_ice_connection (GIOChannel *source,
205 GIOCondition condition,
206 GsmIceConnectionData *data)
207 {
208 IceConn ice_conn;
209 IceAcceptStatus status;
210
211 g_debug ("GsmXsmpServer: accept_ice_connection()");
212
213 ice_conn = IceAcceptConnection (data->listener, &status);
214 if (status != IceAcceptSuccess) {
215 g_debug ("GsmXsmpServer: IceAcceptConnection returned %d", status);
216 return TRUE;
217 }
218
219 auth_ice_connection (ice_conn);
220
221 return TRUE;
222 }
223
224 void
gsm_xsmp_server_start(GsmXsmpServer * server)225 gsm_xsmp_server_start (GsmXsmpServer *server)
226 {
227 GIOChannel *channel;
228 int i;
229
230 for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
231 GsmIceConnectionData *data;
232
233 data = g_new0 (GsmIceConnectionData, 1);
234 data->server = server;
235 data->listener = server->priv->xsmp_sockets[i];
236
237 channel = g_io_channel_unix_new (IceGetListenConnectionNumber (server->priv->xsmp_sockets[i]));
238 g_io_add_watch_full (channel,
239 G_PRIORITY_DEFAULT,
240 G_IO_IN | G_IO_HUP | G_IO_ERR,
241 (GIOFunc)accept_ice_connection,
242 data,
243 (GDestroyNotify)g_free);
244 g_io_channel_unref (channel);
245 }
246 }
247
248 void
gsm_xsmp_server_stop_accepting_new_clients(GsmXsmpServer * server)249 gsm_xsmp_server_stop_accepting_new_clients (GsmXsmpServer *server)
250 {
251 g_return_if_fail (GSM_IS_XSMP_SERVER (server));
252 g_debug ("gsm_xsmp_server_stop_accepting_new_clients");
253 server->priv->stopping = TRUE;
254 }
255
256 void
gsm_xsmp_server_start_accepting_new_clients(GsmXsmpServer * server)257 gsm_xsmp_server_start_accepting_new_clients (GsmXsmpServer *server)
258 {
259 g_return_if_fail (GSM_IS_XSMP_SERVER (server));
260 g_debug ("gsm_xsmp_server_start");
261 server->priv->stopping = FALSE;
262 }
263
264 static void
gsm_xsmp_server_set_client_store(GsmXsmpServer * xsmp_server,GsmStore * store)265 gsm_xsmp_server_set_client_store (GsmXsmpServer *xsmp_server,
266 GsmStore *store)
267 {
268 g_return_if_fail (GSM_IS_XSMP_SERVER (xsmp_server));
269
270 if (store != NULL) {
271 g_object_ref (store);
272 }
273
274 if (xsmp_server->priv->client_store != NULL) {
275 g_object_unref (xsmp_server->priv->client_store);
276 }
277
278 xsmp_server->priv->client_store = store;
279 }
280
281 static void
gsm_xsmp_server_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)282 gsm_xsmp_server_set_property (GObject *object,
283 guint prop_id,
284 const GValue *value,
285 GParamSpec *pspec)
286 {
287 GsmXsmpServer *self;
288
289 self = GSM_XSMP_SERVER (object);
290
291 switch (prop_id) {
292 case PROP_CLIENT_STORE:
293 gsm_xsmp_server_set_client_store (self, g_value_get_object (value));
294 break;
295 default:
296 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
297 break;
298 }
299 }
300
301 static void
gsm_xsmp_server_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)302 gsm_xsmp_server_get_property (GObject *object,
303 guint prop_id,
304 GValue *value,
305 GParamSpec *pspec)
306 {
307 GsmXsmpServer *self;
308
309 self = GSM_XSMP_SERVER (object);
310
311 switch (prop_id) {
312 case PROP_CLIENT_STORE:
313 g_value_set_object (value, self->priv->client_store);
314 break;
315 default:
316 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
317 break;
318 }
319 }
320
321 /* This is called (by libSM) when XSMP is initiated on an ICE
322 * connection that was already accepted by accept_ice_connection.
323 */
324 static Status
accept_xsmp_connection(SmsConn sms_conn,GsmXsmpServer * server,unsigned long * mask_ret,SmsCallbacks * callbacks_ret,char ** failure_reason_ret)325 accept_xsmp_connection (SmsConn sms_conn,
326 GsmXsmpServer *server,
327 unsigned long *mask_ret,
328 SmsCallbacks *callbacks_ret,
329 char **failure_reason_ret)
330 {
331 IceConn ice_conn;
332 GsmClient *client;
333 GsmIceConnectionWatch *data;
334
335 if (server->priv->stopping) {
336 g_debug ("GsmXsmpServer: In shutdown, rejecting new client");
337
338 *failure_reason_ret = strdup (_("Refusing new client connection because the session is currently being shut down\n"));
339 return FALSE;
340 }
341
342 ice_conn = SmsGetIceConnection (sms_conn);
343 data = ice_conn->context;
344
345 /* Each GsmXSMPClient has its own IceConn watcher */
346 free_ice_connection_watch (data);
347
348 client = gsm_xsmp_client_new (ice_conn);
349
350 gsm_store_add (server->priv->client_store, gsm_client_peek_id (client), G_OBJECT (client));
351 /* the store will own the ref */
352 g_object_unref (client);
353
354 gsm_xsmp_client_connect (GSM_XSMP_CLIENT (client), sms_conn, mask_ret, callbacks_ret);
355
356 return TRUE;
357 }
358
359 static void
ice_error_handler(IceConn conn,Bool swap,int offending_minor_opcode,unsigned long offending_sequence,int error_class,int severity,IcePointer values)360 ice_error_handler (IceConn conn,
361 Bool swap,
362 int offending_minor_opcode,
363 unsigned long offending_sequence,
364 int error_class,
365 int severity,
366 IcePointer values)
367 {
368 g_debug ("GsmXsmpServer: ice_error_handler (%p, %s, %d, %lx, %d, %d)",
369 conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
370 offending_sequence, error_class, severity);
371
372 if (severity == IceCanContinue) {
373 return;
374 }
375
376 /* FIXME: the ICElib docs are completely vague about what we're
377 * supposed to do in this case. Need to verify that calling
378 * IceCloseConnection() here is guaranteed to cause neither
379 * free-memory-reads nor leaks.
380 */
381 IceCloseConnection (conn);
382 }
383
384 static void
ice_io_error_handler(IceConn conn)385 ice_io_error_handler (IceConn conn)
386 {
387 g_debug ("GsmXsmpServer: ice_io_error_handler (%p)", conn);
388
389 /* We don't need to do anything here; the next call to
390 * IceProcessMessages() for this connection will receive
391 * IceProcessMessagesIOError and we can handle the error there.
392 */
393 }
394
395 static void
sms_error_handler(SmsConn conn,Bool swap,int offending_minor_opcode,unsigned long offending_sequence_num,int error_class,int severity,IcePointer values)396 sms_error_handler (SmsConn conn,
397 Bool swap,
398 int offending_minor_opcode,
399 unsigned long offending_sequence_num,
400 int error_class,
401 int severity,
402 IcePointer values)
403 {
404 g_debug ("GsmXsmpServer: sms_error_handler (%p, %s, %d, %lx, %d, %d)",
405 conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
406 offending_sequence_num, error_class, severity);
407
408 /* We don't need to do anything here; if the connection needs to be
409 * closed, libSM will do that itself.
410 */
411 }
412
413 static IceAuthFileEntry *
auth_entry_new(const char * protocol,const char * network_id)414 auth_entry_new (const char *protocol,
415 const char *network_id)
416 {
417 IceAuthFileEntry *file_entry;
418 IceAuthDataEntry data_entry;
419
420 file_entry = malloc (sizeof (IceAuthFileEntry));
421
422 file_entry->protocol_name = strdup (protocol);
423 file_entry->protocol_data = NULL;
424 file_entry->protocol_data_length = 0;
425 file_entry->network_id = strdup (network_id);
426 file_entry->auth_name = strdup (GSM_ICE_MAGIC_COOKIE_AUTH_NAME);
427 file_entry->auth_data = IceGenerateMagicCookie (GSM_ICE_MAGIC_COOKIE_LEN);
428 file_entry->auth_data_length = GSM_ICE_MAGIC_COOKIE_LEN;
429
430 /* Also create an in-memory copy, which is what the server will
431 * actually use for checking client auth.
432 */
433 data_entry.protocol_name = file_entry->protocol_name;
434 data_entry.network_id = file_entry->network_id;
435 data_entry.auth_name = file_entry->auth_name;
436 data_entry.auth_data = file_entry->auth_data;
437 data_entry.auth_data_length = file_entry->auth_data_length;
438 IceSetPaAuthData (1, &data_entry);
439
440 return file_entry;
441 }
442
443 static gboolean
update_iceauthority(GsmXsmpServer * server,gboolean adding)444 update_iceauthority (GsmXsmpServer *server,
445 gboolean adding)
446 {
447 char *filename;
448 char **our_network_ids;
449 FILE *fp;
450 IceAuthFileEntry *auth_entry;
451 GSList *entries;
452 GSList *e;
453 int i;
454 int ret;
455 gboolean ok = FALSE;
456
457 filename = IceAuthFileName ();
458 do {
459 ret = IceLockAuthFile (filename,
460 GSM_ICE_AUTH_RETRIES,
461 GSM_ICE_AUTH_INTERVAL,
462 GSM_ICE_AUTH_LOCK_TIMEOUT);
463
464 } while (ret != IceAuthLockSuccess && errno == EINTR);
465
466 if (ret != IceAuthLockSuccess) {
467 g_warning ("IceLockAuthFile failed: %m");
468 return FALSE;
469 }
470
471 our_network_ids = g_malloc (server->priv->num_local_xsmp_sockets * sizeof (char *));
472 for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
473 our_network_ids[i] = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);
474 }
475
476 entries = NULL;
477
478 fp = fopen (filename, "r+");
479 if (fp != NULL) {
480 while ((auth_entry = IceReadAuthFileEntry (fp)) != NULL) {
481 /* Skip/delete entries with no network ID (invalid), or with
482 * our network ID; if we're starting up, an entry with our
483 * ID must be a stale entry left behind by an old process,
484 * and if we're shutting down, it won't be valid in the
485 * future, so either way we want to remove it from the list.
486 */
487 if (!auth_entry->network_id) {
488 IceFreeAuthFileEntry (auth_entry);
489 continue;
490 }
491
492 for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
493 if (!strcmp (auth_entry->network_id, our_network_ids[i])) {
494 IceFreeAuthFileEntry (auth_entry);
495 break;
496 }
497 }
498 if (i != server->priv->num_local_xsmp_sockets) {
499 continue;
500 }
501
502 entries = g_slist_prepend (entries, auth_entry);
503 }
504
505 rewind (fp);
506 } else {
507 int fd;
508
509 if (errno != ENOENT) {
510 g_warning ("Unable to read ICE authority file %s: %m", filename);
511 goto cleanup;
512 }
513
514 fd = open (filename, O_CREAT | O_WRONLY, 0600);
515 fp = fdopen (fd, "w");
516 if (!fp) {
517 g_warning ("Unable to write to ICE authority file: %s", filename);
518 if (fd != -1) {
519 close (fd);
520 }
521 goto cleanup;
522 }
523 }
524
525 if (adding) {
526 for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
527 entries = g_slist_append (entries,
528 auth_entry_new ("ICE", our_network_ids[i]));
529 entries = g_slist_prepend (entries,
530 auth_entry_new ("XSMP", our_network_ids[i]));
531 }
532 }
533
534 for (e = entries; e; e = e->next) {
535 IceAuthFileEntry *auth_entry = e->data;
536 IceWriteAuthFileEntry (fp, auth_entry);
537 IceFreeAuthFileEntry (auth_entry);
538 }
539 g_slist_free (entries);
540
541 fclose (fp);
542 ok = TRUE;
543
544 cleanup:
545 IceUnlockAuthFile (filename);
546 for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
547 free (our_network_ids[i]);
548 }
549 g_free (our_network_ids);
550
551 return ok;
552 }
553
554
555 static void
setup_listener(GsmXsmpServer * server)556 setup_listener (GsmXsmpServer *server)
557 {
558 char error[256];
559 mode_t saved_umask;
560 char *network_id_list;
561 int i;
562 int res;
563
564 /* Set up sane error handlers */
565 IceSetErrorHandler (ice_error_handler);
566 IceSetIOErrorHandler (ice_io_error_handler);
567 SmsSetErrorHandler (sms_error_handler);
568
569 /* Initialize libSM; we pass NULL for hostBasedAuthProc to disable
570 * host-based authentication.
571 */
572 res = SmsInitialize (PACKAGE,
573 VERSION,
574 (SmsNewClientProc)accept_xsmp_connection,
575 server,
576 NULL,
577 sizeof (error),
578 error);
579 if (! res) {
580 gsm_util_init_error (TRUE, "Could not initialize libSM: %s", error);
581 }
582
583 /* By default, IceListenForConnections will open one socket for each
584 * transport type known to X. We don't want connections from remote
585 * hosts, so for security reasons it would be best if ICE didn't
586 * even open any non-local sockets. So we use an internal ICElib
587 * method to disable them here. Unfortunately, there is no way to
588 * ask X what transport types it knows about, so we're forced to
589 * guess.
590 */
591 _IceTransNoListen ("tcp");
592
593 /* Create the XSMP socket. Older versions of IceListenForConnections
594 * have a bug which causes the umask to be set to 0 on certain types
595 * of failures. Probably not an issue on any modern systems, but
596 * we'll play it safe.
597 */
598 saved_umask = umask (0);
599 umask (saved_umask);
600 res = IceListenForConnections (&server->priv->num_xsmp_sockets,
601 &server->priv->xsmp_sockets,
602 sizeof (error),
603 error);
604 if (! res) {
605 gsm_util_init_error (TRUE, _("Could not create ICE listening socket: %s"), error);
606 }
607
608 umask (saved_umask);
609
610 /* Find the local sockets in the returned socket list and move them
611 * to the start of the list.
612 */
613 for (i = server->priv->num_local_xsmp_sockets = 0; i < server->priv->num_xsmp_sockets; i++) {
614 char *id = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);
615
616 if (!strncmp (id, "local/", sizeof ("local/") - 1) ||
617 !strncmp (id, "unix/", sizeof ("unix/") - 1)) {
618 if (i > server->priv->num_local_xsmp_sockets) {
619 IceListenObj tmp;
620 tmp = server->priv->xsmp_sockets[i];
621 server->priv->xsmp_sockets[i] = server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets];
622 server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets] = tmp;
623 }
624 server->priv->num_local_xsmp_sockets++;
625 }
626 free (id);
627 }
628
629 if (server->priv->num_local_xsmp_sockets == 0) {
630 gsm_util_init_error (TRUE, "IceListenForConnections did not return a local listener!");
631 }
632
633 if (server->priv->num_local_xsmp_sockets != server->priv->num_xsmp_sockets) {
634 /* Xtrans was apparently compiled with support for some
635 * non-local transport besides TCP (which we disabled above); we
636 * won't create IO watches on those extra sockets, so
637 * connections to them will never be noticed, but they're still
638 * there, which is inelegant.
639 *
640 * If the g_warning below is triggering for you and you want to
641 * stop it, the fix is to add additional _IceTransNoListen()
642 * calls above.
643 */
644 network_id_list = IceComposeNetworkIdList (server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
645 server->priv->xsmp_sockets + server->priv->num_local_xsmp_sockets);
646 g_warning ("IceListenForConnections returned %d non-local listeners: %s",
647 server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
648 network_id_list);
649 free (network_id_list);
650 }
651
652 /* Update .ICEauthority with new auth entries for our socket */
653 if (!update_iceauthority (server, TRUE)) {
654 /* FIXME: is this really fatal? Hm... */
655 gsm_util_init_error (TRUE,
656 "Could not update ICEauthority file %s",
657 IceAuthFileName ());
658 }
659
660 network_id_list = IceComposeNetworkIdList (server->priv->num_local_xsmp_sockets,
661 server->priv->xsmp_sockets);
662
663 gsm_util_setenv ("SESSION_MANAGER", network_id_list);
664 g_debug ("GsmXsmpServer: SESSION_MANAGER=%s\n", network_id_list);
665 free (network_id_list);
666 }
667
668 static GObject *
gsm_xsmp_server_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)669 gsm_xsmp_server_constructor (GType type,
670 guint n_construct_properties,
671 GObjectConstructParam *construct_properties)
672 {
673 GsmXsmpServer *xsmp_server;
674
675 xsmp_server = GSM_XSMP_SERVER (G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->constructor (type,
676 n_construct_properties,
677 construct_properties));
678 setup_listener (xsmp_server);
679
680 return G_OBJECT (xsmp_server);
681 }
682
683 static void
gsm_xsmp_server_class_init(GsmXsmpServerClass * klass)684 gsm_xsmp_server_class_init (GsmXsmpServerClass *klass)
685 {
686 GObjectClass *object_class = G_OBJECT_CLASS (klass);
687
688 object_class->get_property = gsm_xsmp_server_get_property;
689 object_class->set_property = gsm_xsmp_server_set_property;
690 object_class->constructor = gsm_xsmp_server_constructor;
691 object_class->finalize = gsm_xsmp_server_finalize;
692
693 g_object_class_install_property (object_class,
694 PROP_CLIENT_STORE,
695 g_param_spec_object ("client-store",
696 NULL,
697 NULL,
698 GSM_TYPE_STORE,
699 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
700
701 g_type_class_add_private (klass, sizeof (GsmXsmpServerPrivate));
702 }
703
704 static void
gsm_xsmp_server_init(GsmXsmpServer * xsmp_server)705 gsm_xsmp_server_init (GsmXsmpServer *xsmp_server)
706 {
707 xsmp_server->priv = GSM_XSMP_SERVER_GET_PRIVATE (xsmp_server);
708
709 }
710
711 static void
gsm_xsmp_server_finalize(GObject * object)712 gsm_xsmp_server_finalize (GObject *object)
713 {
714 GsmXsmpServer *xsmp_server;
715
716 g_return_if_fail (object != NULL);
717 g_return_if_fail (GSM_IS_XSMP_SERVER (object));
718
719 xsmp_server = GSM_XSMP_SERVER (object);
720
721 g_return_if_fail (xsmp_server->priv != NULL);
722
723 IceFreeListenObjs (xsmp_server->priv->num_xsmp_sockets,
724 xsmp_server->priv->xsmp_sockets);
725
726 if (xsmp_server->priv->client_store != NULL) {
727 g_object_unref (xsmp_server->priv->client_store);
728 }
729
730 G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->finalize (object);
731 }
732
733 GsmXsmpServer *
gsm_xsmp_server_new(GsmStore * client_store)734 gsm_xsmp_server_new (GsmStore *client_store)
735 {
736 if (xsmp_server_object != NULL) {
737 g_object_ref (xsmp_server_object);
738 } else {
739 xsmp_server_object = g_object_new (GSM_TYPE_XSMP_SERVER,
740 "client-store", client_store,
741 NULL);
742
743 g_object_add_weak_pointer (xsmp_server_object,
744 (gpointer *) &xsmp_server_object);
745 }
746
747 return GSM_XSMP_SERVER (xsmp_server_object);
748 }
749