Coverage Report

Created: 2025-07-01 07:09

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