source: trunk/third/linc/src/linc-server.c @ 18552

Revision 18552, 10.2 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18551, which included commits to RCS files with non-trunk default branches.
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 <netdb.h>
15#include <unistd.h>
16#include <string.h>
17#include <fcntl.h>
18#include <errno.h>
19
20#include <linc/linc.h>
21#include <linc/linc-server.h>
22#include <linc/linc-connection.h>
23
24#include "linc-debug.h"
25#include "linc-private.h"
26#include "linc-compat.h"
27
28enum {
29        NEW_CONNECTION,
30        LAST_SIGNAL
31};
32static guint server_signals [LAST_SIGNAL] = { 0 };
33
34static GObjectClass *parent_class = NULL;
35
36static void
37my_cclosure_marshal_VOID__OBJECT (GClosure     *closure,
38                                  GValue       *return_value,
39                                  guint         n_param_values,
40                                  const GValue *param_values,
41                                  gpointer      invocation_hint,
42                                  gpointer      marshal_data)
43{
44        typedef void (*GSignalFunc_VOID__OBJECT) (gpointer     data1,
45                                                  GObject     *arg_1,
46                                                  gpointer     data2);
47        register GSignalFunc_VOID__OBJECT callback;
48        register GCClosure *cc = (GCClosure*) closure;
49        register gpointer data1, data2;
50
51        g_return_if_fail (n_param_values >= 2);
52
53        if (G_CCLOSURE_SWAP_DATA (closure)) {
54                data1 = closure->data;
55                data2 = g_value_peek_pointer (param_values + 0);
56        } else {
57                data1 = g_value_peek_pointer (param_values + 0);
58                data2 = closure->data;
59        }
60        callback = (GSignalFunc_VOID__OBJECT) (
61                marshal_data ? marshal_data : cc->callback);
62
63        callback (data1,
64                  g_value_peek_pointer (param_values + 1),
65                  data2);
66}
67
68static void
69linc_server_init (LINCServer *cnx)
70{
71        cnx->priv = g_new0 (LINCServerPrivate, 1);
72
73        cnx->priv->mutex = linc_mutex_new ();
74        cnx->priv->fd = -1;
75}
76
77static void
78linc_server_dispose (GObject *obj)
79{
80        GSList     *l;
81        LINCServer *cnx = (LINCServer *) obj;
82
83        d_printf ("Dispose / close server fd %d\n", cnx->priv->fd);
84
85#ifdef G_THREADS_ENABLED
86        if (cnx->priv->mutex) {
87                g_mutex_free (cnx->priv->mutex);
88                cnx->priv->mutex = NULL;
89        }
90#endif
91        if (cnx->priv->tag) {
92                LincWatch *thewatch = cnx->priv->tag;
93                cnx->priv->tag = NULL;
94                linc_io_remove_watch (thewatch);
95        }
96
97        linc_protocol_destroy_cnx (cnx->proto,
98                                   cnx->priv->fd,
99                                   cnx->local_host_info,
100                                   cnx->local_serv_info);
101        cnx->priv->fd = -1;
102
103        while ((l = cnx->priv->connections)) {
104                GObject *o = l->data;
105
106                cnx->priv->connections = l->next;
107                g_slist_free_1 (l);
108                g_object_unref (o);
109        }
110
111        parent_class->dispose (obj);
112}
113
114static void
115linc_server_finalize (GObject *obj)
116{
117        LINCServer *cnx = (LINCServer *)obj;
118
119        g_free (cnx->local_host_info);
120        g_free (cnx->local_serv_info);
121
122        g_free (cnx->priv);
123
124        parent_class->finalize (obj);
125}
126
127static LINCConnection *
128linc_server_create_connection (LINCServer *cnx)
129{
130        return g_object_new (linc_connection_get_type (), NULL);
131}
132
133static gboolean
134linc_server_accept_connection (LINCServer      *server,
135                               LINCConnection **connection)
136{
137        LINCServerClass *klass;
138        struct sockaddr *saddr;
139        int              addrlen, fd;
140       
141        g_return_val_if_fail (connection != NULL, FALSE);
142
143        *connection = NULL;
144
145        addrlen = server->proto->addr_len;
146        saddr = g_alloca (addrlen);
147
148        fd = accept (server->priv->fd, saddr, &addrlen);
149        if (fd < 0) {
150                d_printf ("accept on %d failed %d", server->priv->fd, errno);
151                return FALSE; /* error */
152        }
153
154        if (server->create_options & LINC_CONNECTION_LOCAL_ONLY &&
155            !linc_protocol_is_local (server->proto, saddr, addrlen)) {
156                LINC_CLOSE (fd);
157                return FALSE;
158        }
159
160        if (server->create_options & LINC_CONNECTION_NONBLOCKING)
161                if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) {
162                        d_printf ("failed to set O_NONBLOCK on %d", fd);
163                        LINC_CLOSE (fd);
164                        return FALSE;
165                }
166
167        if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) {
168                d_printf ("failed to set cloexec on %d", fd);
169                LINC_CLOSE (fd);
170                return FALSE;
171        }
172
173        klass = (LINCServerClass *) G_OBJECT_GET_CLASS (server);
174
175        g_assert (klass->create_connection);
176        *connection = klass->create_connection (server);
177
178        g_return_val_if_fail (*connection != NULL, FALSE);
179
180        d_printf ("accepted a new connection (%d) on server %d\n",
181                 fd, server->priv->fd);
182
183        if (!linc_connection_from_fd (
184                *connection, fd, server->proto, NULL, NULL,
185                FALSE, LINC_CONNECTED, server->create_options)) {
186               
187                g_object_unref (G_OBJECT (*connection));
188                *connection = NULL;
189                LINC_CLOSE (fd);
190                return FALSE;
191        }
192
193        server->priv->connections = g_slist_prepend (
194                server->priv->connections, *connection);
195
196        return TRUE;
197}
198
199static gboolean
200linc_server_handle_io (GIOChannel  *gioc,
201                       GIOCondition condition,
202                       gpointer     data)
203{
204        gboolean        accepted;
205        LINCServer     *server = data;
206        LINCConnection *connection = NULL;
207
208        if (!(condition & LINC_IN_CONDS))
209                g_error ("error condition on server fd is %#x", condition);
210
211        LINC_MUTEX_LOCK (server->priv->mutex);
212
213        accepted = linc_server_accept_connection (server, &connection);
214
215        LINC_MUTEX_UNLOCK (server->priv->mutex);
216
217        if (!accepted) {
218                GValue parms[2];
219
220                memset (parms, 0, sizeof (parms));
221                g_value_init (parms, G_OBJECT_TYPE (server));
222                g_value_set_object (parms, G_OBJECT (server));
223                g_value_init (parms + 1, G_TYPE_OBJECT);
224
225                /* FIXME: this connection is always NULL */
226                g_value_set_object (parms + 1, (GObject *) connection);
227
228                d_printf ("p %d, Non-accepted input on fd %d",
229                          getpid (), server->priv->fd);
230               
231                g_signal_emitv (parms, server_signals [NEW_CONNECTION], 0, NULL);
232               
233                g_value_unset (parms);
234                g_value_unset (parms + 1);
235        }
236
237        return TRUE;
238}
239
240/**
241 * linc_server_setup:
242 * @cnx: the connection to setup
243 * @proto_name: the protocol to use
244 * @local_host_info: the local hsot
245 * @local_serv_info: remote server info
246 * @create_options: various create options
247 *
248 *   Setup the server object. You should create a server object
249 * via g_object_new and then set it up, using this method.
250 *
251 * Return value: the initialized server
252 **/
253gboolean
254linc_server_setup (LINCServer            *cnx,
255                   const char            *proto_name,
256                   const char            *local_host_info,
257                   const char            *local_serv_info,
258                   LINCConnectionOptions  create_options)
259{
260        const LINCProtocolInfo *proto;
261        int                     fd, n;
262        struct sockaddr        *saddr;
263        LincSockLen             saddr_len;
264        const char             *local_host;
265        char                   *service, *hostname;
266
267#if !LINC_SSL_SUPPORT
268        if (create_options & LINC_CONNECTION_SSL)
269                return FALSE;
270#endif
271
272        proto = linc_protocol_find (proto_name);
273        if (!proto) {
274                d_printf ("Can't find proto '%s'\n", proto_name);
275                return FALSE;
276        }
277
278        if (local_host_info)
279                local_host = local_host_info;
280        else
281                local_host = linc_get_local_hostname ();
282
283 address_in_use:
284
285        saddr = linc_protocol_get_sockaddr (
286                proto, local_host, local_serv_info, &saddr_len);
287
288        if (!saddr) {
289                d_printf ("Can't get_sockaddr proto '%s' '%s'\n",
290                          local_host, local_serv_info ? local_serv_info : "(null)");
291                return FALSE;
292        }
293
294        fd = socket (proto->family, SOCK_STREAM,
295                     proto->stream_proto_num);
296        if (fd < 0) {
297                g_free (saddr);
298                d_printf ("socket (%d, %d, %d) failed\n",
299                         proto->family, SOCK_STREAM,
300                         proto->stream_proto_num);
301                return FALSE;
302        }
303
304        {
305                static const int oneval = 1;
306
307                setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &oneval, sizeof (oneval));
308        }
309   
310        n = 0;
311        errno = 0;
312
313        if ((proto->flags & LINC_PROTOCOL_NEEDS_BIND) || local_serv_info)
314                n = bind (fd, saddr, saddr_len);
315
316        if (n && errno == EADDRINUSE) {
317                d_printf ("bind failed; retrying");
318                goto address_in_use;
319        }
320
321        if (!n)
322                n = listen (fd, 10);
323        else
324                d_printf ("bind really failed errno: %d\n", errno);
325
326
327        if (!n &&
328            create_options & LINC_CONNECTION_NONBLOCKING)
329                n = fcntl (fd, F_SETFL, O_NONBLOCK);
330        else
331                d_printf ("listen failed errno: %d\n", errno);
332
333        if (!n)
334                n = fcntl (fd, F_SETFD, FD_CLOEXEC);
335        else
336                d_printf ("failed to set nonblock on %d", fd);
337
338        if (!n)
339                n = getsockname (fd, saddr, &saddr_len);
340        else
341                d_printf ("failed to set cloexec on %d", fd);
342
343        if (n) {
344                linc_protocol_destroy_addr (proto, fd, saddr);
345                d_printf ("get_sockname failed errno: %d\n", errno);
346                return FALSE;
347        }
348
349        if (!linc_protocol_get_sockinfo (proto, saddr, &hostname, &service)) {
350                linc_protocol_destroy_addr (proto, fd, saddr);
351                d_printf ("linc_getsockinfo failed.\n");
352                return FALSE;
353        }
354
355        g_free (saddr);
356
357        cnx->proto = proto;
358        cnx->priv->fd = fd;
359
360        if (create_options & LINC_CONNECTION_NONBLOCKING) {
361                g_assert (cnx->priv->tag == NULL);
362
363                cnx->priv->tag = linc_io_add_watch_fd (
364                        fd, LINC_IN_CONDS | LINC_ERR_CONDS,
365                        linc_server_handle_io, cnx);
366        }
367
368        cnx->create_options = create_options;
369
370        if (local_host_info) {
371                g_free (hostname);
372                cnx->local_host_info = g_strdup (local_host_info);
373        } else
374                cnx->local_host_info = hostname;
375
376        cnx->local_serv_info = service;
377
378        d_printf ("Created a new server fd (%d) '%s', '%s', '%s'\n",
379                 fd, proto->name,
380                 hostname ? hostname : "<Null>",
381                 service ? service : "<Null>");
382
383        return TRUE;
384}
385
386static void
387linc_server_class_init (LINCServerClass *klass)
388{
389        GType         ptype;
390        GClosure     *closure;
391        GObjectClass *object_class = (GObjectClass *) klass;
392
393        object_class->dispose    = linc_server_dispose;
394        object_class->finalize   = linc_server_finalize;
395        klass->create_connection = linc_server_create_connection;
396
397        parent_class = g_type_class_peek_parent (klass);
398        closure = g_signal_type_cclosure_new (
399                G_OBJECT_CLASS_TYPE (klass),
400                G_STRUCT_OFFSET (LINCServerClass, new_connection));
401
402        ptype = G_TYPE_OBJECT;
403        server_signals [NEW_CONNECTION] = g_signal_newv (
404                "new_connection",
405                G_OBJECT_CLASS_TYPE (klass),
406                G_SIGNAL_RUN_LAST, closure,
407                NULL, NULL,
408                my_cclosure_marshal_VOID__OBJECT,
409                G_TYPE_NONE,
410                1, &ptype);
411}
412
413GType
414linc_server_get_type (void)
415{
416        static GType object_type = 0;
417
418        if (!object_type) {
419                static const GTypeInfo object_info = {
420                        sizeof (LINCServerClass),
421                        (GBaseInitFunc) NULL,
422                        (GBaseFinalizeFunc) NULL,
423                        (GClassInitFunc) linc_server_class_init,
424                        NULL,           /* class_finalize */
425                        NULL,           /* class_data */
426                        sizeof (LINCServer),
427                        0,              /* n_preallocs */
428                        (GInstanceInitFunc) linc_server_init,
429                };
430     
431                object_type = g_type_register_static (
432                        G_TYPE_OBJECT, "LINCServer",
433                        &object_info, 0);
434        } 
435
436        return object_type;
437}
Note: See TracBrowser for help on using the repository browser.