Coverage Report

Created: 2025-06-13 06:55

/src/glib/gio/gsocketconnection.c
Line
Count
Source (jump to first uncovered line)
1
/* GIO - GLib Input, Output and Streaming Library
2
 *
3
 * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
4
 *           © 2008 codethink
5
 * Copyright © 2009 Red Hat, Inc
6
 *
7
 * SPDX-License-Identifier: LGPL-2.1-or-later
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General
20
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
21
 *
22
 * Authors: Christian Kellner <gicmo@gnome.org>
23
 *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
24
 *          Ryan Lortie <desrt@desrt.ca>
25
 *          Alexander Larsson <alexl@redhat.com>
26
 */
27
28
#include "config.h"
29
30
#include "gsocketconnection.h"
31
32
#include "gsocketoutputstream.h"
33
#include "gsocketinputstream.h"
34
#include "gioprivate.h"
35
#include <gio/giostream.h>
36
#include <gio/gtask.h>
37
#include "gunixconnection.h"
38
#include "gtcpconnection.h"
39
#include "glibintl.h"
40
41
42
/**
43
 * SECTION:gsocketconnection
44
 * @short_description: A socket connection
45
 * @include: gio/gio.h
46
 * @see_also: #GIOStream, #GSocketClient, #GSocketListener
47
 *
48
 * #GSocketConnection is a #GIOStream for a connected socket. They
49
 * can be created either by #GSocketClient when connecting to a host,
50
 * or by #GSocketListener when accepting a new client.
51
 *
52
 * The type of the #GSocketConnection object returned from these calls
53
 * depends on the type of the underlying socket that is in use. For
54
 * instance, for a TCP/IP connection it will be a #GTcpConnection.
55
 *
56
 * Choosing what type of object to construct is done with the socket
57
 * connection factory, and it is possible for 3rd parties to register
58
 * custom socket connection types for specific combination of socket
59
 * family/type/protocol using g_socket_connection_factory_register_type().
60
 *
61
 * To close a #GSocketConnection, use g_io_stream_close(). Closing both
62
 * substreams of the #GIOStream separately will not close the underlying
63
 * #GSocket.
64
 *
65
 * Since: 2.22
66
 */
67
68
enum
69
{
70
  PROP_NONE,
71
  PROP_SOCKET,
72
};
73
74
struct _GSocketConnectionPrivate
75
{
76
  GSocket       *socket;
77
  GInputStream  *input_stream;
78
  GOutputStream *output_stream;
79
80
  GSocketAddress *cached_remote_address;
81
82
  gboolean       in_dispose;
83
};
84
85
static gboolean g_socket_connection_close         (GIOStream            *stream,
86
               GCancellable         *cancellable,
87
               GError              **error);
88
static void     g_socket_connection_close_async   (GIOStream            *stream,
89
               int                   io_priority,
90
               GCancellable         *cancellable,
91
               GAsyncReadyCallback   callback,
92
               gpointer              user_data);
93
static gboolean g_socket_connection_close_finish  (GIOStream            *stream,
94
               GAsyncResult         *result,
95
               GError              **error);
96
97
G_DEFINE_TYPE_WITH_PRIVATE (GSocketConnection, g_socket_connection, G_TYPE_IO_STREAM)
98
99
static GInputStream *
100
g_socket_connection_get_input_stream (GIOStream *io_stream)
101
0
{
102
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
103
104
0
  if (connection->priv->input_stream == NULL)
105
0
    connection->priv->input_stream = (GInputStream *)
106
0
      _g_socket_input_stream_new (connection->priv->socket);
107
108
0
  return connection->priv->input_stream;
109
0
}
110
111
static GOutputStream *
112
g_socket_connection_get_output_stream (GIOStream *io_stream)
113
0
{
114
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
115
116
0
  if (connection->priv->output_stream == NULL)
117
0
    connection->priv->output_stream = (GOutputStream *)
118
0
      _g_socket_output_stream_new (connection->priv->socket);
119
120
0
  return connection->priv->output_stream;
121
0
}
122
123
/**
124
 * g_socket_connection_is_connected:
125
 * @connection: a #GSocketConnection
126
 *
127
 * Checks if @connection is connected. This is equivalent to calling
128
 * g_socket_is_connected() on @connection's underlying #GSocket.
129
 *
130
 * Returns: whether @connection is connected
131
 *
132
 * Since: 2.32
133
 */
134
gboolean
135
g_socket_connection_is_connected (GSocketConnection  *connection)
136
0
{
137
0
  return g_socket_is_connected (connection->priv->socket);
138
0
}
139
140
/**
141
 * g_socket_connection_connect:
142
 * @connection: a #GSocketConnection
143
 * @address: a #GSocketAddress specifying the remote address.
144
 * @cancellable: (nullable): a %GCancellable or %NULL
145
 * @error: #GError for error reporting, or %NULL to ignore.
146
 *
147
 * Connect @connection to the specified remote address.
148
 *
149
 * Returns: %TRUE if the connection succeeded, %FALSE on error
150
 *
151
 * Since: 2.32
152
 */
153
gboolean
154
g_socket_connection_connect (GSocketConnection  *connection,
155
           GSocketAddress     *address,
156
           GCancellable       *cancellable,
157
           GError            **error)
158
0
{
159
0
  g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
160
0
  g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), FALSE);
161
162
0
  return g_socket_connect (connection->priv->socket, address,
163
0
         cancellable, error);
164
0
}
165
166
static gboolean g_socket_connection_connect_callback (GSocket      *socket,
167
                  GIOCondition  condition,
168
                  gpointer      user_data);
169
170
/**
171
 * g_socket_connection_connect_async:
172
 * @connection: a #GSocketConnection
173
 * @address: a #GSocketAddress specifying the remote address.
174
 * @cancellable: (nullable): a %GCancellable or %NULL
175
 * @callback: (scope async): a #GAsyncReadyCallback
176
 * @user_data: user data for the callback
177
 *
178
 * Asynchronously connect @connection to the specified remote address.
179
 *
180
 * This clears the #GSocket:blocking flag on @connection's underlying
181
 * socket if it is currently set.
182
 *
183
 * Use g_socket_connection_connect_finish() to retrieve the result.
184
 *
185
 * Since: 2.32
186
 */
187
void
188
g_socket_connection_connect_async (GSocketConnection   *connection,
189
           GSocketAddress      *address,
190
           GCancellable        *cancellable,
191
           GAsyncReadyCallback  callback,
192
           gpointer             user_data)
193
0
{
194
0
  GTask *task;
195
0
  GError *tmp_error = NULL;
196
197
0
  g_return_if_fail (G_IS_SOCKET_CONNECTION (connection));
198
0
  g_return_if_fail (G_IS_SOCKET_ADDRESS (address));
199
200
0
  task = g_task_new (connection, cancellable, callback, user_data);
201
0
  g_task_set_source_tag (task, g_socket_connection_connect_async);
202
203
0
  g_socket_set_blocking (connection->priv->socket, FALSE);
204
205
0
  if (g_socket_connect (connection->priv->socket, address,
206
0
      cancellable, &tmp_error))
207
0
    {
208
0
      g_task_return_boolean (task, TRUE);
209
0
      g_object_unref (task);
210
0
    }
211
0
  else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
212
0
    {
213
0
      GSource *source;
214
215
0
      g_error_free (tmp_error);
216
0
      source = g_socket_create_source (connection->priv->socket,
217
0
               G_IO_OUT, cancellable);
218
0
      g_task_attach_source (task, source,
219
0
          (GSourceFunc) g_socket_connection_connect_callback);
220
0
      g_source_unref (source);
221
0
    }
222
0
  else
223
0
    {
224
0
      g_task_return_error (task, tmp_error);
225
0
      g_object_unref (task);
226
0
    }
227
0
}
228
229
static gboolean
230
g_socket_connection_connect_callback (GSocket      *socket,
231
              GIOCondition  condition,
232
              gpointer      user_data)
233
0
{
234
0
  GTask *task = user_data;
235
0
  GSocketConnection *connection = g_task_get_source_object (task);
236
0
  GError *error = NULL;
237
238
0
  if (g_socket_check_connect_result (connection->priv->socket, &error))
239
0
    g_task_return_boolean (task, TRUE);
240
0
  else
241
0
    g_task_return_error (task, error);
242
243
0
  g_object_unref (task);
244
0
  return FALSE;
245
0
}
246
247
/**
248
 * g_socket_connection_connect_finish:
249
 * @connection: a #GSocketConnection
250
 * @result: the #GAsyncResult
251
 * @error: #GError for error reporting, or %NULL to ignore.
252
 *
253
 * Gets the result of a g_socket_connection_connect_async() call.
254
 *
255
 * Returns: %TRUE if the connection succeeded, %FALSE on error
256
 *
257
 * Since: 2.32
258
 */
259
gboolean
260
g_socket_connection_connect_finish (GSocketConnection  *connection,
261
            GAsyncResult       *result,
262
            GError            **error)
263
0
{
264
0
  g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
265
0
  g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
266
267
0
  return g_task_propagate_boolean (G_TASK (result), error);
268
0
}
269
270
/**
271
 * g_socket_connection_get_socket:
272
 * @connection: a #GSocketConnection
273
 *
274
 * Gets the underlying #GSocket object of the connection.
275
 * This can be useful if you want to do something unusual on it
276
 * not supported by the #GSocketConnection APIs.
277
 *
278
 * Returns: (transfer none): a #GSocket or %NULL on error.
279
 *
280
 * Since: 2.22
281
 */
282
GSocket *
283
g_socket_connection_get_socket (GSocketConnection *connection)
284
0
{
285
0
  g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), NULL);
286
287
0
  return connection->priv->socket;
288
0
}
289
290
/**
291
 * g_socket_connection_get_local_address:
292
 * @connection: a #GSocketConnection
293
 * @error: #GError for error reporting, or %NULL to ignore.
294
 *
295
 * Try to get the local address of a socket connection.
296
 *
297
 * Returns: (transfer full): a #GSocketAddress or %NULL on error.
298
 *     Free the returned object with g_object_unref().
299
 *
300
 * Since: 2.22
301
 */
302
GSocketAddress *
303
g_socket_connection_get_local_address (GSocketConnection  *connection,
304
               GError            **error)
305
0
{
306
0
  return g_socket_get_local_address (connection->priv->socket, error);
307
0
}
308
309
/**
310
 * g_socket_connection_get_remote_address:
311
 * @connection: a #GSocketConnection
312
 * @error: #GError for error reporting, or %NULL to ignore.
313
 *
314
 * Try to get the remote address of a socket connection.
315
 *
316
 * Since GLib 2.40, when used with g_socket_client_connect() or
317
 * g_socket_client_connect_async(), during emission of
318
 * %G_SOCKET_CLIENT_CONNECTING, this function will return the remote
319
 * address that will be used for the connection.  This allows
320
 * applications to print e.g. "Connecting to example.com
321
 * (10.42.77.3)...".
322
 *
323
 * Returns: (transfer full): a #GSocketAddress or %NULL on error.
324
 *     Free the returned object with g_object_unref().
325
 *
326
 * Since: 2.22
327
 */
328
GSocketAddress *
329
g_socket_connection_get_remote_address (GSocketConnection  *connection,
330
          GError            **error)
331
0
{
332
0
  if (!g_socket_is_connected (connection->priv->socket))
333
0
    {
334
0
      return connection->priv->cached_remote_address ?
335
0
        g_object_ref (connection->priv->cached_remote_address) : NULL;
336
0
    }
337
0
  return g_socket_get_remote_address (connection->priv->socket, error);
338
0
}
339
340
/* Private API allowing applications to retrieve the resolved address
341
 * now, before we start connecting.
342
 *
343
 * https://bugzilla.gnome.org/show_bug.cgi?id=712547
344
 */
345
void
346
g_socket_connection_set_cached_remote_address (GSocketConnection *connection,
347
                                               GSocketAddress    *address)
348
0
{
349
0
  g_clear_object (&connection->priv->cached_remote_address);
350
0
  connection->priv->cached_remote_address = address ? g_object_ref (address) : NULL;
351
0
}
352
353
static void
354
g_socket_connection_get_property (GObject    *object,
355
                                  guint       prop_id,
356
                                  GValue     *value,
357
                                  GParamSpec *pspec)
358
0
{
359
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
360
361
0
  switch (prop_id)
362
0
    {
363
0
     case PROP_SOCKET:
364
0
      g_value_set_object (value, connection->priv->socket);
365
0
      break;
366
367
0
     default:
368
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
369
0
    }
370
0
}
371
372
static void
373
g_socket_connection_set_property (GObject      *object,
374
                                  guint         prop_id,
375
                                  const GValue *value,
376
                                  GParamSpec   *pspec)
377
0
{
378
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
379
380
0
  switch (prop_id)
381
0
    {
382
0
     case PROP_SOCKET:
383
0
      connection->priv->socket = G_SOCKET (g_value_dup_object (value));
384
0
      break;
385
386
0
     default:
387
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
388
0
    }
389
0
}
390
391
static void
392
g_socket_connection_constructed (GObject *object)
393
0
{
394
0
#ifndef G_DISABLE_ASSERT
395
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
396
0
#endif
397
398
0
  g_assert (connection->priv->socket != NULL);
399
0
}
400
401
static void
402
g_socket_connection_dispose (GObject *object)
403
0
{
404
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
405
406
0
  connection->priv->in_dispose = TRUE;
407
408
0
  g_clear_object (&connection->priv->cached_remote_address);
409
410
0
  G_OBJECT_CLASS (g_socket_connection_parent_class)
411
0
    ->dispose (object);
412
413
0
  connection->priv->in_dispose = FALSE;
414
0
}
415
416
static void
417
g_socket_connection_finalize (GObject *object)
418
0
{
419
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
420
421
0
  if (connection->priv->input_stream)
422
0
    g_object_unref (connection->priv->input_stream);
423
424
0
  if (connection->priv->output_stream)
425
0
    g_object_unref (connection->priv->output_stream);
426
427
0
  g_object_unref (connection->priv->socket);
428
429
0
  G_OBJECT_CLASS (g_socket_connection_parent_class)
430
0
    ->finalize (object);
431
0
}
432
433
static void
434
g_socket_connection_class_init (GSocketConnectionClass *klass)
435
0
{
436
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
437
0
  GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
438
439
0
  gobject_class->set_property = g_socket_connection_set_property;
440
0
  gobject_class->get_property = g_socket_connection_get_property;
441
0
  gobject_class->constructed = g_socket_connection_constructed;
442
0
  gobject_class->finalize = g_socket_connection_finalize;
443
0
  gobject_class->dispose = g_socket_connection_dispose;
444
445
0
  stream_class->get_input_stream = g_socket_connection_get_input_stream;
446
0
  stream_class->get_output_stream = g_socket_connection_get_output_stream;
447
0
  stream_class->close_fn = g_socket_connection_close;
448
0
  stream_class->close_async = g_socket_connection_close_async;
449
0
  stream_class->close_finish = g_socket_connection_close_finish;
450
451
0
  g_object_class_install_property (gobject_class,
452
0
                                   PROP_SOCKET,
453
0
                                   g_param_spec_object ("socket",
454
0
                                      P_("Socket"),
455
0
                                      P_("The underlying GSocket"),
456
0
                                                        G_TYPE_SOCKET,
457
0
                                                        G_PARAM_CONSTRUCT_ONLY |
458
0
                                                        G_PARAM_READWRITE |
459
0
                                                        G_PARAM_STATIC_STRINGS));
460
0
}
461
462
static void
463
g_socket_connection_init (GSocketConnection *connection)
464
0
{
465
0
  connection->priv = g_socket_connection_get_instance_private (connection);
466
0
}
467
468
static gboolean
469
g_socket_connection_close (GIOStream     *stream,
470
         GCancellable  *cancellable,
471
         GError       **error)
472
0
{
473
0
  GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
474
475
0
  if (connection->priv->output_stream)
476
0
    g_output_stream_close (connection->priv->output_stream,
477
0
         cancellable, NULL);
478
0
  if (connection->priv->input_stream)
479
0
    g_input_stream_close (connection->priv->input_stream,
480
0
        cancellable, NULL);
481
482
  /* Don't close the underlying socket if this is being called
483
   * as part of dispose(); when destroying the GSocketConnection,
484
   * we only want to close the socket if we're holding the last
485
   * reference on it, and in that case it will close itself when
486
   * we unref it in finalize().
487
   */
488
0
  if (connection->priv->in_dispose)
489
0
    return TRUE;
490
491
0
  return g_socket_close (connection->priv->socket, error);
492
0
}
493
494
495
static void
496
g_socket_connection_close_async (GIOStream           *stream,
497
         int                  io_priority,
498
         GCancellable        *cancellable,
499
         GAsyncReadyCallback  callback,
500
         gpointer             user_data)
501
0
{
502
0
  GTask *task;
503
0
  GIOStreamClass *class;
504
0
  GError *error;
505
506
0
  class = G_IO_STREAM_GET_CLASS (stream);
507
508
0
  task = g_task_new (stream, cancellable, callback, user_data);
509
0
  g_task_set_source_tag (task, g_socket_connection_close_async);
510
511
  /* socket close is not blocked, just do it! */
512
0
  error = NULL;
513
0
  if (class->close_fn &&
514
0
      !class->close_fn (stream, cancellable, &error))
515
0
    g_task_return_error (task, error);
516
0
  else
517
0
    g_task_return_boolean (task, TRUE);
518
519
0
  g_object_unref (task);
520
0
}
521
522
static gboolean
523
g_socket_connection_close_finish (GIOStream     *stream,
524
          GAsyncResult  *result,
525
          GError       **error)
526
0
{
527
0
  return g_task_propagate_boolean (G_TASK (result), error);
528
0
}
529
530
typedef struct {
531
  GSocketFamily socket_family;
532
  GSocketType socket_type;
533
  int protocol;
534
  GType implementation;
535
} ConnectionFactory;
536
537
static guint
538
connection_factory_hash (gconstpointer key)
539
0
{
540
0
  const ConnectionFactory *factory = key;
541
0
  guint h;
542
543
0
  h = factory->socket_family ^ (factory->socket_type << 4) ^ (factory->protocol << 8);
544
  /* This is likely to be small, so spread over whole
545
     hash space to get some distribution */
546
0
  h = h ^ (h << 8) ^ (h << 16) ^ (h << 24);
547
548
0
  return h;
549
0
}
550
551
static gboolean
552
connection_factory_equal (gconstpointer _a,
553
        gconstpointer _b)
554
0
{
555
0
  const ConnectionFactory *a = _a;
556
0
  const ConnectionFactory *b = _b;
557
558
0
  if (a->socket_family != b->socket_family)
559
0
    return FALSE;
560
561
0
  if (a->socket_type != b->socket_type)
562
0
    return FALSE;
563
564
0
  if (a->protocol != b->protocol)
565
0
    return FALSE;
566
567
0
  return TRUE;
568
0
}
569
570
static GHashTable *connection_factories = NULL;
571
G_LOCK_DEFINE_STATIC(connection_factories);
572
573
/**
574
 * g_socket_connection_factory_register_type:
575
 * @g_type: a #GType, inheriting from %G_TYPE_SOCKET_CONNECTION
576
 * @family: a #GSocketFamily
577
 * @type: a #GSocketType
578
 * @protocol: a protocol id
579
 *
580
 * Looks up the #GType to be used when creating socket connections on
581
 * sockets with the specified @family, @type and @protocol.
582
 *
583
 * If no type is registered, the #GSocketConnection base type is returned.
584
 *
585
 * Since: 2.22
586
 */
587
void
588
g_socket_connection_factory_register_type (GType         g_type,
589
             GSocketFamily family,
590
             GSocketType   type,
591
             gint          protocol)
592
0
{
593
0
  ConnectionFactory *factory;
594
595
0
  g_return_if_fail (g_type_is_a (g_type, G_TYPE_SOCKET_CONNECTION));
596
597
0
  G_LOCK (connection_factories);
598
599
0
  if (connection_factories == NULL)
600
0
    connection_factories = g_hash_table_new_full (connection_factory_hash,
601
0
              connection_factory_equal,
602
0
              (GDestroyNotify)g_free,
603
0
              NULL);
604
605
0
  factory = g_new0 (ConnectionFactory, 1);
606
0
  factory->socket_family = family;
607
0
  factory->socket_type = type;
608
0
  factory->protocol = protocol;
609
0
  factory->implementation = g_type;
610
611
0
  g_hash_table_insert (connection_factories,
612
0
           factory, factory);
613
614
0
  G_UNLOCK (connection_factories);
615
0
}
616
617
static void
618
init_builtin_types (void)
619
0
{
620
0
  g_type_ensure (G_TYPE_UNIX_CONNECTION);
621
0
  g_type_ensure (G_TYPE_TCP_CONNECTION);
622
0
}
623
624
/**
625
 * g_socket_connection_factory_lookup_type:
626
 * @family: a #GSocketFamily
627
 * @type: a #GSocketType
628
 * @protocol_id: a protocol id
629
 *
630
 * Looks up the #GType to be used when creating socket connections on
631
 * sockets with the specified @family, @type and @protocol_id.
632
 *
633
 * If no type is registered, the #GSocketConnection base type is returned.
634
 *
635
 * Returns: a #GType
636
 *
637
 * Since: 2.22
638
 */
639
GType
640
g_socket_connection_factory_lookup_type (GSocketFamily family,
641
           GSocketType   type,
642
           gint          protocol_id)
643
0
{
644
0
  ConnectionFactory *factory, key;
645
0
  GType g_type;
646
647
0
  init_builtin_types ();
648
649
0
  G_LOCK (connection_factories);
650
651
0
  g_type = G_TYPE_SOCKET_CONNECTION;
652
653
0
  if (connection_factories)
654
0
    {
655
0
      key.socket_family = family;
656
0
      key.socket_type = type;
657
0
      key.protocol = protocol_id;
658
659
0
      factory = g_hash_table_lookup (connection_factories, &key);
660
0
      if (factory)
661
0
  g_type = factory->implementation;
662
0
    }
663
664
0
  G_UNLOCK (connection_factories);
665
666
0
  return g_type;
667
0
}
668
669
/**
670
 * g_socket_connection_factory_create_connection:
671
 * @socket: a #GSocket
672
 *
673
 * Creates a #GSocketConnection subclass of the right type for
674
 * @socket.
675
 *
676
 * Returns: (transfer full): a #GSocketConnection
677
 *
678
 * Since: 2.22
679
 */
680
GSocketConnection *
681
g_socket_connection_factory_create_connection (GSocket *socket)
682
0
{
683
0
  GType type;
684
685
0
  type = g_socket_connection_factory_lookup_type (g_socket_get_family (socket),
686
0
              g_socket_get_socket_type (socket),
687
0
              g_socket_get_protocol (socket));
688
0
  return g_object_new (type, "socket", socket, NULL);
689
0
}