| 1 | /*
|
|---|
| 2 | * linc-server.c: This file is part of the linc library.
|
|---|
| 3 | *
|
|---|
| 4 | * Authors:
|
|---|
| 5 | * Elliot Lee (sopwith@redhat.com)
|
|---|
| 6 | * Michael Meeks (michael@ximian.com)
|
|---|
| 7 | * Mark McLouglin (mark@skynet.ie) & others
|
|---|
| 8 | *
|
|---|
| 9 | * Copyright 2001, Red Hat, Inc., Ximian, Inc.,
|
|---|
| 10 | * Sun Microsystems, Inc.
|
|---|
| 11 | */
|
|---|
| 12 | #include <config.h>
|
|---|
| 13 | #include <stdio.h>
|
|---|
| 14 | #include <string.h>
|
|---|
| 15 | #include <fcntl.h>
|
|---|
| 16 | #include <errno.h>
|
|---|
| 17 |
|
|---|
| 18 | #include <linc/linc.h>
|
|---|
| 19 | #include <linc/linc-server.h>
|
|---|
| 20 | #include <linc/linc-connection.h>
|
|---|
| 21 |
|
|---|
| 22 | #include "linc-private.h"
|
|---|
| 23 | #include "linc-compat.h"
|
|---|
| 24 |
|
|---|
| 25 | enum {
|
|---|
| 26 | NEW_CONNECTION,
|
|---|
| 27 | LAST_SIGNAL
|
|---|
| 28 | };
|
|---|
| 29 | static guint server_signals [LAST_SIGNAL] = { 0 };
|
|---|
| 30 |
|
|---|
| 31 | static GList *server_list = NULL;
|
|---|
| 32 | static GObjectClass *parent_class = NULL;
|
|---|
| 33 |
|
|---|
| 34 | static void
|
|---|
| 35 | my_cclosure_marshal_VOID__OBJECT (GClosure *closure,
|
|---|
| 36 | GValue *return_value,
|
|---|
| 37 | guint n_param_values,
|
|---|
| 38 | const GValue *param_values,
|
|---|
| 39 | gpointer invocation_hint,
|
|---|
| 40 | gpointer marshal_data)
|
|---|
| 41 | {
|
|---|
| 42 | typedef void (*GSignalFunc_VOID__OBJECT) (gpointer data1,
|
|---|
| 43 | GObject *arg_1,
|
|---|
| 44 | gpointer data2);
|
|---|
| 45 | register GSignalFunc_VOID__OBJECT callback;
|
|---|
| 46 | register GCClosure *cc = (GCClosure*) closure;
|
|---|
| 47 | register gpointer data1, data2;
|
|---|
| 48 |
|
|---|
| 49 | g_return_if_fail (n_param_values >= 2);
|
|---|
| 50 |
|
|---|
| 51 | if (G_CCLOSURE_SWAP_DATA (closure)) {
|
|---|
| 52 | data1 = closure->data;
|
|---|
| 53 | data2 = g_value_peek_pointer (param_values + 0);
|
|---|
| 54 | } else {
|
|---|
| 55 | data1 = g_value_peek_pointer (param_values + 0);
|
|---|
| 56 | data2 = closure->data;
|
|---|
| 57 | }
|
|---|
| 58 | callback = (GSignalFunc_VOID__OBJECT) (
|
|---|
| 59 | marshal_data ? marshal_data : cc->callback);
|
|---|
| 60 |
|
|---|
| 61 | callback (data1,
|
|---|
| 62 | g_value_peek_pointer (param_values + 1),
|
|---|
| 63 | data2);
|
|---|
| 64 | }
|
|---|
| 65 |
|
|---|
| 66 | static void
|
|---|
| 67 | link_server_init (LinkServer *srv)
|
|---|
| 68 | {
|
|---|
| 69 | srv->priv = g_new0 (LinkServerPrivate, 1);
|
|---|
| 70 |
|
|---|
| 71 | srv->priv->fd = -1;
|
|---|
| 72 | }
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 | static void
|
|---|
| 76 | link_server_client_connection_broken (LinkConnection *connection,
|
|---|
| 77 | gpointer user_data)
|
|---|
| 78 | {
|
|---|
| 79 | LinkServer *server = user_data;
|
|---|
| 80 |
|
|---|
| 81 | server->priv->connections =
|
|---|
| 82 | g_slist_remove (server->priv->connections, connection);
|
|---|
| 83 |
|
|---|
| 84 | link_connection_unref (connection);
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | static void
|
|---|
| 88 | link_server_dispose (GObject *obj)
|
|---|
| 89 | {
|
|---|
| 90 | GSList *l;
|
|---|
| 91 | LinkServer *srv = (LinkServer *) obj;
|
|---|
| 92 |
|
|---|
| 93 | server_list = g_list_remove (server_list, srv);
|
|---|
| 94 |
|
|---|
| 95 | d_printf ("Dispose / close server fd %d\n", srv->priv->fd);
|
|---|
| 96 |
|
|---|
| 97 | if (srv->priv->tag) {
|
|---|
| 98 | LinkWatch *thewatch = srv->priv->tag;
|
|---|
| 99 | srv->priv->tag = NULL;
|
|---|
| 100 | link_io_remove_watch (thewatch);
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 | link_protocol_destroy_cnx (srv->proto,
|
|---|
| 104 | srv->priv->fd,
|
|---|
| 105 | srv->local_host_info,
|
|---|
| 106 | srv->local_serv_info);
|
|---|
| 107 | srv->priv->fd = -1;
|
|---|
| 108 |
|
|---|
| 109 | while ((l = srv->priv->connections)) {
|
|---|
| 110 | GObject *o = l->data;
|
|---|
| 111 |
|
|---|
| 112 | g_signal_handlers_disconnect_by_func (o,
|
|---|
| 113 | link_server_client_connection_broken,
|
|---|
| 114 | srv);
|
|---|
| 115 |
|
|---|
| 116 | srv->priv->connections = l->next;
|
|---|
| 117 | g_slist_free_1 (l);
|
|---|
| 118 | link_connection_unref (o);
|
|---|
| 119 | }
|
|---|
| 120 |
|
|---|
| 121 | parent_class->dispose (obj);
|
|---|
| 122 | }
|
|---|
| 123 |
|
|---|
| 124 | static void
|
|---|
| 125 | link_server_finalize (GObject *obj)
|
|---|
| 126 | {
|
|---|
| 127 | LinkServer *srv = (LinkServer *)obj;
|
|---|
| 128 |
|
|---|
| 129 | g_free (srv->local_host_info);
|
|---|
| 130 | g_free (srv->local_serv_info);
|
|---|
| 131 |
|
|---|
| 132 | g_free (srv->priv);
|
|---|
| 133 |
|
|---|
| 134 | parent_class->finalize (obj);
|
|---|
| 135 | }
|
|---|
| 136 |
|
|---|
| 137 | static LinkConnection *
|
|---|
| 138 | link_server_create_connection (LinkServer *srv)
|
|---|
| 139 | {
|
|---|
| 140 | return g_object_new (link_connection_get_type (), NULL);
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | static gboolean
|
|---|
| 144 | link_server_accept_connection (LinkServer *server,
|
|---|
| 145 | LinkConnection **connection)
|
|---|
| 146 | {
|
|---|
| 147 | LinkServerClass *klass;
|
|---|
| 148 | struct sockaddr *saddr;
|
|---|
| 149 | int addrlen, fd;
|
|---|
| 150 |
|
|---|
| 151 | g_return_val_if_fail (connection != NULL, FALSE);
|
|---|
| 152 |
|
|---|
| 153 | *connection = NULL;
|
|---|
| 154 |
|
|---|
| 155 | addrlen = server->proto->addr_len;
|
|---|
| 156 | saddr = g_alloca (addrlen);
|
|---|
| 157 |
|
|---|
| 158 | LINK_TEMP_FAILURE_RETRY_SOCKET (accept (server->priv->fd,
|
|---|
| 159 | saddr,
|
|---|
| 160 | &addrlen), fd);
|
|---|
| 161 | #ifdef HAVE_WINSOCK2_H
|
|---|
| 162 | if (fd == INVALID_SOCKET) {
|
|---|
| 163 | fd = -1;
|
|---|
| 164 | link_map_winsock_error_to_errno ();
|
|---|
| 165 | }
|
|---|
| 166 | #endif
|
|---|
| 167 | if (fd < 0) {
|
|---|
| 168 | d_printf ("accept on %d failed: %s\n",
|
|---|
| 169 | server->priv->fd, link_strerror (errno));
|
|---|
| 170 | return FALSE;
|
|---|
| 171 | }
|
|---|
| 172 |
|
|---|
| 173 | if (server->create_options & LINK_CONNECTION_LOCAL_ONLY &&
|
|---|
| 174 | !link_protocol_is_local (server->proto, saddr, addrlen)) {
|
|---|
| 175 | d_printf ("link_server_accept_connection: not local, closing %d\n", fd);
|
|---|
| 176 | LINK_CLOSE_SOCKET (fd);
|
|---|
| 177 | return FALSE;
|
|---|
| 178 | }
|
|---|
| 179 |
|
|---|
| 180 | if (server->create_options & LINK_CONNECTION_NONBLOCKING) {
|
|---|
| 181 | #ifdef HAVE_WINSOCK2_H
|
|---|
| 182 | u_long yes = 1;
|
|---|
| 183 | if (ioctlsocket (fd, FIONBIO, &yes) == SOCKET_ERROR) {
|
|---|
| 184 | link_map_winsock_error_to_errno ();
|
|---|
| 185 | d_printf ("failed to set FIONBIO on %d: %s\n",
|
|---|
| 186 | fd, link_strerror (errno));
|
|---|
| 187 | d_printf ("closing %d\n", fd);
|
|---|
| 188 | LINK_CLOSE_SOCKET (fd);
|
|---|
| 189 | return FALSE;
|
|---|
| 190 | }
|
|---|
| 191 | #else
|
|---|
| 192 | if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) {
|
|---|
| 193 | d_printf ("failed to set O_NONBLOCK on %d: %s\n",
|
|---|
| 194 | fd, link_strerror (errno));
|
|---|
| 195 | d_printf ("closing %d\n", fd);
|
|---|
| 196 | LINK_CLOSE_SOCKET (fd);
|
|---|
| 197 | return FALSE;
|
|---|
| 198 | }
|
|---|
| 199 | #endif
|
|---|
| 200 | }
|
|---|
| 201 | #if defined (F_SETFD) && defined (FD_CLOEXEC)
|
|---|
| 202 | if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) {
|
|---|
| 203 | d_printf ("failed to set cloexec on %d: %s\n",
|
|---|
| 204 | fd, link_strerror (errno));
|
|---|
| 205 | d_printf ("closing %d\n", fd);
|
|---|
| 206 | LINK_CLOSE_SOCKET (fd);
|
|---|
| 207 | return FALSE;
|
|---|
| 208 | }
|
|---|
| 209 | #endif
|
|---|
| 210 |
|
|---|
| 211 | klass = (LinkServerClass *) G_OBJECT_GET_CLASS (server);
|
|---|
| 212 |
|
|---|
| 213 | g_assert (klass->create_connection);
|
|---|
| 214 | *connection = klass->create_connection (server);
|
|---|
| 215 |
|
|---|
| 216 | g_return_val_if_fail (*connection != NULL, FALSE);
|
|---|
| 217 |
|
|---|
| 218 | d_printf ("accepted a new connection (%d) on server %d\n",
|
|---|
| 219 | fd, server->priv->fd);
|
|---|
| 220 |
|
|---|
| 221 | link_connection_from_fd
|
|---|
| 222 | (*connection, fd, server->proto, NULL, NULL,
|
|---|
| 223 | FALSE, LINK_CONNECTED, server->create_options);
|
|---|
| 224 |
|
|---|
| 225 | g_signal_connect (*connection, "broken",
|
|---|
| 226 | G_CALLBACK (link_server_client_connection_broken), server);
|
|---|
| 227 |
|
|---|
| 228 | server->priv->connections = g_slist_prepend (
|
|---|
| 229 | server->priv->connections, *connection);
|
|---|
| 230 |
|
|---|
| 231 | return TRUE;
|
|---|
| 232 | }
|
|---|
| 233 |
|
|---|
| 234 | static gboolean
|
|---|
| 235 | link_server_handle_io (GIOChannel *gioc,
|
|---|
| 236 | GIOCondition condition,
|
|---|
| 237 | gpointer data)
|
|---|
| 238 | {
|
|---|
| 239 | gboolean accepted;
|
|---|
| 240 | LinkServer *server = data;
|
|---|
| 241 | LinkConnection *connection = NULL;
|
|---|
| 242 |
|
|---|
| 243 | if (!(condition & LINK_IN_CONDS)) {
|
|---|
| 244 | /*
|
|---|
| 245 | * This call to g_warning was changed from g_error to avoid
|
|---|
| 246 | * a program crash. See bug #126209.
|
|---|
| 247 | */
|
|---|
| 248 | d_printf ("error condition on server fd is %#x\n", condition);
|
|---|
| 249 | return TRUE;
|
|---|
| 250 | }
|
|---|
| 251 |
|
|---|
| 252 | accepted = link_server_accept_connection (server, &connection);
|
|---|
| 253 |
|
|---|
| 254 | if (!accepted) {
|
|---|
| 255 | GValue parms[2];
|
|---|
| 256 |
|
|---|
| 257 | memset (parms, 0, sizeof (parms));
|
|---|
| 258 | g_value_init (parms, G_OBJECT_TYPE (server));
|
|---|
| 259 | g_value_set_object (parms, G_OBJECT (server));
|
|---|
| 260 | g_value_init (parms + 1, G_TYPE_OBJECT);
|
|---|
| 261 |
|
|---|
| 262 | /* FIXME: this connection is always NULL */
|
|---|
| 263 | g_value_set_object (parms + 1, (GObject *) connection);
|
|---|
| 264 |
|
|---|
| 265 | d_printf ("p %d, Non-accepted input on fd %d\n",
|
|---|
| 266 | getpid (), server->priv->fd);
|
|---|
| 267 |
|
|---|
| 268 | g_signal_emitv (parms, server_signals [NEW_CONNECTION], 0, NULL);
|
|---|
| 269 |
|
|---|
| 270 | g_value_unset (parms);
|
|---|
| 271 | g_value_unset (parms + 1);
|
|---|
| 272 | }
|
|---|
| 273 |
|
|---|
| 274 | return TRUE;
|
|---|
| 275 | }
|
|---|
| 276 |
|
|---|
| 277 | /**
|
|---|
| 278 | * link_server_setup:
|
|---|
| 279 | * @srv: the connection to setup
|
|---|
| 280 | * @proto_name: the protocol to use
|
|---|
| 281 | * @local_host_info: the local hsot
|
|---|
| 282 | * @local_serv_info: remote server info
|
|---|
| 283 | * @create_options: various create options
|
|---|
| 284 | *
|
|---|
| 285 | * Setup the server object. You should create a server object
|
|---|
| 286 | * via g_object_new and then set it up, using this method.
|
|---|
| 287 | *
|
|---|
| 288 | * Return value: the initialized server
|
|---|
| 289 | **/
|
|---|
| 290 | gboolean
|
|---|
| 291 | link_server_setup (LinkServer *srv,
|
|---|
| 292 | const char *proto_name,
|
|---|
| 293 | const char *local_host_info,
|
|---|
| 294 | const char *local_serv_info,
|
|---|
| 295 | LinkConnectionOptions create_options)
|
|---|
| 296 | {
|
|---|
| 297 | const LinkProtocolInfo *proto;
|
|---|
| 298 | int fd, n;
|
|---|
| 299 | struct sockaddr *saddr;
|
|---|
| 300 | LinkSockLen saddr_len;
|
|---|
| 301 | const char *local_host;
|
|---|
| 302 | char *service, *hostname;
|
|---|
| 303 |
|
|---|
| 304 | #if !LINK_SSL_SUPPORT
|
|---|
| 305 | if (create_options & LINK_CONNECTION_SSL)
|
|---|
| 306 | return FALSE;
|
|---|
| 307 | #endif
|
|---|
| 308 |
|
|---|
| 309 | proto = link_protocol_find (proto_name);
|
|---|
| 310 | if (!proto) {
|
|---|
| 311 | d_printf ("Can't find proto '%s'\n", proto_name);
|
|---|
| 312 | return FALSE;
|
|---|
| 313 | }
|
|---|
| 314 |
|
|---|
| 315 | srv->proto = proto;
|
|---|
| 316 |
|
|---|
| 317 | if (local_host_info)
|
|---|
| 318 | local_host = local_host_info;
|
|---|
| 319 | else
|
|---|
| 320 | local_host = link_get_local_hostname ();
|
|---|
| 321 |
|
|---|
| 322 | address_in_use:
|
|---|
| 323 |
|
|---|
| 324 | saddr = link_protocol_get_sockaddr (
|
|---|
| 325 | proto, local_host, local_serv_info, &saddr_len);
|
|---|
| 326 |
|
|---|
| 327 | if (!saddr) {
|
|---|
| 328 | d_printf ("Can't get_sockaddr proto '%s' '%s'\n",
|
|---|
| 329 | local_host, local_serv_info ? local_serv_info : "(null)");
|
|---|
| 330 | return FALSE;
|
|---|
| 331 | }
|
|---|
| 332 |
|
|---|
| 333 | fd = socket (proto->family, SOCK_STREAM,
|
|---|
| 334 | proto->stream_proto_num);
|
|---|
| 335 | #ifdef HAVE_WINSOCK2_H
|
|---|
| 336 | if (fd == INVALID_SOCKET) {
|
|---|
| 337 | fd = -1;
|
|---|
| 338 | link_map_winsock_error_to_errno ();
|
|---|
| 339 | }
|
|---|
| 340 | #endif
|
|---|
| 341 | if (fd < 0) {
|
|---|
| 342 | g_free (saddr);
|
|---|
| 343 | d_printf ("socket (%d, SOCK_STREAM, %d) failed: %s\n",
|
|---|
| 344 | proto->family, proto->stream_proto_num,
|
|---|
| 345 | link_strerror (errno));
|
|---|
| 346 | return FALSE;
|
|---|
| 347 | }
|
|---|
| 348 |
|
|---|
| 349 | {
|
|---|
| 350 | static const int oneval = 1;
|
|---|
| 351 |
|
|---|
| 352 | setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &oneval, sizeof (oneval));
|
|---|
| 353 | }
|
|---|
| 354 |
|
|---|
| 355 | n = 0;
|
|---|
| 356 | errno = 0;
|
|---|
| 357 |
|
|---|
| 358 | if ((proto->flags & LINK_PROTOCOL_NEEDS_BIND) || local_serv_info)
|
|---|
| 359 | n = bind (fd, saddr, saddr_len);
|
|---|
| 360 |
|
|---|
| 361 | #ifdef HAVE_WINSOCK2_H
|
|---|
| 362 | if (n == SOCKET_ERROR) {
|
|---|
| 363 | n = -1;
|
|---|
| 364 | link_map_winsock_error_to_errno ();
|
|---|
| 365 | }
|
|---|
| 366 | #endif
|
|---|
| 367 | if (n && errno == EADDRINUSE) {
|
|---|
| 368 | close(fd);
|
|---|
| 369 | if (!local_serv_info) {
|
|---|
| 370 | d_printf ("bind failed; retrying\n");
|
|---|
| 371 | goto address_in_use;
|
|---|
| 372 | }
|
|---|
| 373 | }
|
|---|
| 374 |
|
|---|
| 375 | if (n)
|
|---|
| 376 | d_printf ("bind failed: %s\n", link_strerror (errno));
|
|---|
| 377 |
|
|---|
| 378 | if (!n) {
|
|---|
| 379 | n = listen (fd, 10);
|
|---|
| 380 | #ifdef HAVE_WINSOCK2_H
|
|---|
| 381 | if (n == SOCKET_ERROR) {
|
|---|
| 382 | n = -1;
|
|---|
| 383 | link_map_winsock_error_to_errno ();
|
|---|
| 384 | }
|
|---|
| 385 | #endif
|
|---|
| 386 | if (n)
|
|---|
| 387 | d_printf ("listen failed: %s\n", link_strerror (errno));
|
|---|
| 388 | }
|
|---|
| 389 |
|
|---|
| 390 | if (!n &&
|
|---|
| 391 | create_options & LINK_CONNECTION_NONBLOCKING) {
|
|---|
| 392 | #ifdef HAVE_WINSOCK2_H
|
|---|
| 393 | u_long yes = 1;
|
|---|
| 394 | if (ioctlsocket (fd, FIONBIO, &yes) == SOCKET_ERROR) {
|
|---|
| 395 | n = -1;
|
|---|
| 396 | link_map_winsock_error_to_errno ();
|
|---|
| 397 | }
|
|---|
| 398 | #else
|
|---|
| 399 | n = fcntl (fd, F_SETFL, O_NONBLOCK);
|
|---|
| 400 | #endif
|
|---|
| 401 | if (n)
|
|---|
| 402 | d_printf ("failed to set nonblock on %d: %s\n",
|
|---|
| 403 | fd, link_strerror (errno));
|
|---|
| 404 | }
|
|---|
| 405 |
|
|---|
| 406 | #if defined (F_SETFD) && defined (FD_CLOEXEC)
|
|---|
| 407 | if (!n) {
|
|---|
| 408 | n = fcntl (fd, F_SETFD, FD_CLOEXEC);
|
|---|
| 409 | if (n)
|
|---|
| 410 | d_printf ("failed to set cloexec on %d: %s",
|
|---|
| 411 | fd, link_strerror (errno));
|
|---|
| 412 | }
|
|---|
| 413 | #endif
|
|---|
| 414 |
|
|---|
| 415 | if (!n) {
|
|---|
| 416 | n = getsockname (fd, saddr, &saddr_len);
|
|---|
| 417 | #ifdef HAVE_WINSOCK2_H
|
|---|
| 418 | if (n == SOCKET_ERROR) {
|
|---|
| 419 | n = -1;
|
|---|
| 420 | link_map_winsock_error_to_errno ();
|
|---|
| 421 | }
|
|---|
| 422 | #endif
|
|---|
| 423 | if (n) {
|
|---|
| 424 | link_protocol_destroy_addr (proto, fd, saddr);
|
|---|
| 425 | d_printf ("getsockname failed: %s\n",
|
|---|
| 426 | link_strerror (errno));
|
|---|
| 427 | return FALSE;
|
|---|
| 428 | }
|
|---|
| 429 | }
|
|---|
| 430 |
|
|---|
| 431 | if (!link_protocol_get_sockinfo (proto, saddr, &hostname, &service)) {
|
|---|
| 432 | link_protocol_destroy_addr (proto, fd, saddr);
|
|---|
| 433 | d_printf ("link_getsockinfo failed.\n");
|
|---|
| 434 | return FALSE;
|
|---|
| 435 | }
|
|---|
| 436 |
|
|---|
| 437 | g_free (saddr);
|
|---|
| 438 |
|
|---|
| 439 | srv->priv->fd = fd;
|
|---|
| 440 |
|
|---|
| 441 | if (create_options & LINK_CONNECTION_NONBLOCKING) {
|
|---|
| 442 | g_assert (srv->priv->tag == NULL);
|
|---|
| 443 |
|
|---|
| 444 | srv->priv->tag = link_io_add_watch_fd (
|
|---|
| 445 | fd, LINK_IN_CONDS | LINK_ERR_CONDS,
|
|---|
| 446 | link_server_handle_io, srv);
|
|---|
| 447 | }
|
|---|
| 448 |
|
|---|
| 449 | srv->create_options = create_options;
|
|---|
| 450 |
|
|---|
| 451 | if (local_host_info) {
|
|---|
| 452 | g_free (hostname);
|
|---|
| 453 | srv->local_host_info = g_strdup (local_host_info);
|
|---|
| 454 | } else
|
|---|
| 455 | srv->local_host_info = hostname;
|
|---|
| 456 |
|
|---|
| 457 | srv->local_serv_info = service;
|
|---|
| 458 |
|
|---|
| 459 | server_list = g_list_prepend (server_list, srv);
|
|---|
| 460 |
|
|---|
| 461 | d_printf ("Created a new server fd (%d) '%s', '%s', '%s'\n",
|
|---|
| 462 | fd, proto->name,
|
|---|
| 463 | hostname ? hostname : "<Null>",
|
|---|
| 464 | service ? service : "<Null>");
|
|---|
| 465 |
|
|---|
| 466 | return TRUE;
|
|---|
| 467 | }
|
|---|
| 468 |
|
|---|
| 469 | static void
|
|---|
| 470 | link_server_class_init (LinkServerClass *klass)
|
|---|
| 471 | {
|
|---|
| 472 | GType ptype;
|
|---|
| 473 | GClosure *closure;
|
|---|
| 474 | GObjectClass *object_class = (GObjectClass *) klass;
|
|---|
| 475 |
|
|---|
| 476 | object_class->dispose = link_server_dispose;
|
|---|
| 477 | object_class->finalize = link_server_finalize;
|
|---|
| 478 | klass->create_connection = link_server_create_connection;
|
|---|
| 479 |
|
|---|
| 480 | parent_class = g_type_class_peek_parent (klass);
|
|---|
| 481 | closure = g_signal_type_cclosure_new (
|
|---|
| 482 | G_OBJECT_CLASS_TYPE (klass),
|
|---|
| 483 | G_STRUCT_OFFSET (LinkServerClass, new_connection));
|
|---|
| 484 |
|
|---|
| 485 | ptype = G_TYPE_OBJECT;
|
|---|
| 486 | server_signals [NEW_CONNECTION] = g_signal_newv (
|
|---|
| 487 | "new_connection",
|
|---|
| 488 | G_OBJECT_CLASS_TYPE (klass),
|
|---|
| 489 | G_SIGNAL_RUN_LAST, closure,
|
|---|
| 490 | NULL, NULL,
|
|---|
| 491 | my_cclosure_marshal_VOID__OBJECT,
|
|---|
| 492 | G_TYPE_NONE,
|
|---|
| 493 | 1, &ptype);
|
|---|
| 494 | }
|
|---|
| 495 |
|
|---|
| 496 | GType
|
|---|
| 497 | link_server_get_type (void)
|
|---|
| 498 | {
|
|---|
| 499 | static GType object_type = 0;
|
|---|
| 500 |
|
|---|
| 501 | if (!object_type) {
|
|---|
| 502 | static const GTypeInfo object_info = {
|
|---|
| 503 | sizeof (LinkServerClass),
|
|---|
| 504 | (GBaseInitFunc) NULL,
|
|---|
| 505 | (GBaseFinalizeFunc) NULL,
|
|---|
| 506 | (GClassInitFunc) link_server_class_init,
|
|---|
| 507 | NULL, /* class_finalize */
|
|---|
| 508 | NULL, /* class_data */
|
|---|
| 509 | sizeof (LinkServer),
|
|---|
| 510 | 0, /* n_preallocs */
|
|---|
| 511 | (GInstanceInitFunc) link_server_init,
|
|---|
| 512 | };
|
|---|
| 513 |
|
|---|
| 514 | object_type = g_type_register_static (
|
|---|
| 515 | G_TYPE_OBJECT, "LinkServer",
|
|---|
| 516 | &object_info, 0);
|
|---|
| 517 | }
|
|---|
| 518 |
|
|---|
| 519 | return object_type;
|
|---|
| 520 | }
|
|---|
| 521 |
|
|---|
| 522 | void
|
|---|
| 523 | link_servers_move_io_T (gboolean to_io_thread)
|
|---|
| 524 | {
|
|---|
| 525 | GList *l;
|
|---|
| 526 |
|
|---|
| 527 | for (l = server_list; l; l = l->next) {
|
|---|
| 528 | LinkServer *srv = l->data;
|
|---|
| 529 | link_watch_move_io (srv->priv->tag, to_io_thread);
|
|---|
| 530 | }
|
|---|
| 531 | }
|
|---|