source: trunk/ORBit2-2.14.0/linc2/src/linc-server.c

Last change on this file was 92, checked in by cinc, 19 years ago

Orbit2 modified for use with NOM

File size: 12.4 KB
Line 
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
25enum {
26 NEW_CONNECTION,
27 LAST_SIGNAL
28};
29static guint server_signals [LAST_SIGNAL] = { 0 };
30
31static GList *server_list = NULL;
32static GObjectClass *parent_class = NULL;
33
34static void
35my_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
66static void
67link_server_init (LinkServer *srv)
68{
69 srv->priv = g_new0 (LinkServerPrivate, 1);
70
71 srv->priv->fd = -1;
72}
73
74
75static void
76link_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
87static void
88link_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
124static void
125link_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
137static LinkConnection *
138link_server_create_connection (LinkServer *srv)
139{
140 return g_object_new (link_connection_get_type (), NULL);
141}
142
143static gboolean
144link_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
234static gboolean
235link_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 **/
290gboolean
291link_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
469static void
470link_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
496GType
497link_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
522void
523link_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}
Note: See TracBrowser for help on using the repository browser.