Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/gsocketoutputstream.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
 *           © 2009 codethink
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General
17
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * Authors: Christian Kellner <gicmo@gnome.org>
20
 *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
21
 *          Ryan Lortie <desrt@desrt.ca>
22
 */
23
24
#include "config.h"
25
#include "goutputstream.h"
26
#include "gsocketoutputstream.h"
27
#include "gsocket.h"
28
#include "glibintl.h"
29
30
#include "gcancellable.h"
31
#include "gpollableinputstream.h"
32
#include "gpollableoutputstream.h"
33
#include "gioerror.h"
34
#include "glibintl.h"
35
#include "gfiledescriptorbased.h"
36
#include "gioprivate.h"
37
38
struct _GSocketOutputStreamPrivate
39
{
40
  GSocket *socket;
41
42
  /* pending operation metadata */
43
  gconstpointer buffer;
44
  gsize count;
45
};
46
47
static void g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
48
#ifdef G_OS_UNIX
49
static void g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
50
#endif
51
52
#define g_socket_output_stream_get_type _g_socket_output_stream_get_type
53
54
#ifdef G_OS_UNIX
55
G_DEFINE_TYPE_WITH_CODE (GSocketOutputStream, g_socket_output_stream, G_TYPE_OUTPUT_STREAM,
56
                         G_ADD_PRIVATE (GSocketOutputStream)
57
       G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, g_socket_output_stream_pollable_iface_init)
58
       G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED, g_socket_output_stream_file_descriptor_based_iface_init)
59
       )
60
#else
61
G_DEFINE_TYPE_WITH_CODE (GSocketOutputStream, g_socket_output_stream, G_TYPE_OUTPUT_STREAM,
62
                         G_ADD_PRIVATE (GSocketOutputStream)
63
       G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, g_socket_output_stream_pollable_iface_init)
64
       )
65
#endif
66
67
enum
68
{
69
  PROP_0,
70
  PROP_SOCKET
71
};
72
73
static void
74
g_socket_output_stream_get_property (GObject    *object,
75
                                     guint       prop_id,
76
                                     GValue     *value,
77
                                     GParamSpec *pspec)
78
0
{
79
0
  GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object);
80
81
0
  switch (prop_id)
82
0
    {
83
0
      case PROP_SOCKET:
84
0
        g_value_set_object (value, stream->priv->socket);
85
0
        break;
86
87
0
      default:
88
0
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
89
0
    }
90
0
}
91
92
static void
93
g_socket_output_stream_set_property (GObject      *object,
94
                                     guint         prop_id,
95
                                     const GValue *value,
96
                                     GParamSpec   *pspec)
97
0
{
98
0
  GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object);
99
100
0
  switch (prop_id)
101
0
    {
102
0
      case PROP_SOCKET:
103
0
        stream->priv->socket = g_value_dup_object (value);
104
0
        break;
105
106
0
      default:
107
0
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
108
0
    }
109
0
}
110
111
static void
112
g_socket_output_stream_finalize (GObject *object)
113
0
{
114
0
  GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object);
115
116
0
  if (stream->priv->socket)
117
0
    g_object_unref (stream->priv->socket);
118
119
0
  G_OBJECT_CLASS (g_socket_output_stream_parent_class)->finalize (object);
120
0
}
121
122
static gssize
123
g_socket_output_stream_write (GOutputStream  *stream,
124
                              const void     *buffer,
125
                              gsize           count,
126
                              GCancellable   *cancellable,
127
                              GError        **error)
128
0
{
129
0
  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (stream);
130
131
0
  return g_socket_send_with_blocking (output_stream->priv->socket,
132
0
              buffer, count, TRUE,
133
0
              cancellable, error);
134
0
}
135
136
static gboolean
137
g_socket_output_stream_writev (GOutputStream        *stream,
138
                               const GOutputVector  *vectors,
139
                               gsize                 n_vectors,
140
                               gsize                *bytes_written,
141
                               GCancellable         *cancellable,
142
                               GError              **error)
143
0
{
144
0
  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (stream);
145
0
  GPollableReturn res;
146
147
  /* Clamp the number of vectors if more given than we can write in one go.
148
   * The caller has to handle short writes anyway.
149
   */
150
0
  if (n_vectors > G_IOV_MAX)
151
0
    n_vectors = G_IOV_MAX;
152
153
0
  res = g_socket_send_message_with_timeout (output_stream->priv->socket, NULL,
154
0
                                            vectors, n_vectors,
155
0
                                            NULL, 0, G_SOCKET_MSG_NONE,
156
0
                                            -1, bytes_written,
157
0
                                            cancellable, error);
158
159
  /* we have a non-zero timeout so this can't happen */
160
0
  g_assert (res != G_POLLABLE_RETURN_WOULD_BLOCK);
161
162
0
  return res == G_POLLABLE_RETURN_OK;
163
0
}
164
165
static gboolean
166
g_socket_output_stream_pollable_is_writable (GPollableOutputStream *pollable)
167
0
{
168
0
  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable);
169
170
0
  return g_socket_condition_check (output_stream->priv->socket, G_IO_OUT);
171
0
}
172
173
static gssize
174
g_socket_output_stream_pollable_write_nonblocking (GPollableOutputStream  *pollable,
175
               const void             *buffer,
176
               gsize                   size,
177
               GError                **error)
178
0
{
179
0
  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable);
180
181
0
  return g_socket_send_with_blocking (output_stream->priv->socket,
182
0
              buffer, size, FALSE,
183
0
              NULL, error);
184
0
}
185
186
static GPollableReturn
187
g_socket_output_stream_pollable_writev_nonblocking (GPollableOutputStream  *pollable,
188
                                                    const GOutputVector    *vectors,
189
                                                    gsize                   n_vectors,
190
                                                    gsize                  *bytes_written,
191
                                                    GError                **error)
192
0
{
193
0
  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable);
194
195
  /* Clamp the number of vectors if more given than we can write in one go.
196
   * The caller has to handle short writes anyway.
197
   */
198
0
  if (n_vectors > G_IOV_MAX)
199
0
    n_vectors = G_IOV_MAX;
200
201
0
  return g_socket_send_message_with_timeout (output_stream->priv->socket,
202
0
                                             NULL, vectors, n_vectors,
203
0
                                             NULL, 0, G_SOCKET_MSG_NONE, 0,
204
0
                                             bytes_written, NULL, error);
205
0
}
206
207
static GSource *
208
g_socket_output_stream_pollable_create_source (GPollableOutputStream *pollable,
209
                 GCancellable          *cancellable)
210
0
{
211
0
  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable);
212
0
  GSource *socket_source, *pollable_source;
213
214
0
  pollable_source = g_pollable_source_new (G_OBJECT (output_stream));
215
0
  socket_source = g_socket_create_source (output_stream->priv->socket,
216
0
            G_IO_OUT, cancellable);
217
0
  g_source_set_dummy_callback (socket_source);
218
0
  g_source_add_child_source (pollable_source, socket_source);
219
0
  g_source_unref (socket_source);
220
221
0
  return pollable_source;
222
0
}
223
224
#ifdef G_OS_UNIX
225
static int
226
g_socket_output_stream_get_fd (GFileDescriptorBased *fd_based)
227
0
{
228
0
  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (fd_based);
229
230
0
  return g_socket_get_fd (output_stream->priv->socket);
231
0
}
232
#endif
233
234
static void
235
g_socket_output_stream_class_init (GSocketOutputStreamClass *klass)
236
0
{
237
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
238
0
  GOutputStreamClass *goutputstream_class = G_OUTPUT_STREAM_CLASS (klass);
239
240
0
  gobject_class->finalize = g_socket_output_stream_finalize;
241
0
  gobject_class->get_property = g_socket_output_stream_get_property;
242
0
  gobject_class->set_property = g_socket_output_stream_set_property;
243
244
0
  goutputstream_class->write_fn = g_socket_output_stream_write;
245
0
  goutputstream_class->writev_fn = g_socket_output_stream_writev;
246
247
0
  g_object_class_install_property (gobject_class, PROP_SOCKET,
248
0
           g_param_spec_object ("socket",
249
0
              P_("socket"),
250
0
              P_("The socket that this stream wraps"),
251
0
              G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY |
252
0
              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
253
0
}
254
255
#ifdef G_OS_UNIX
256
static void
257
g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
258
0
{
259
0
  iface->get_fd = g_socket_output_stream_get_fd;
260
0
}
261
#endif
262
263
static void
264
g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
265
0
{
266
0
  iface->is_writable = g_socket_output_stream_pollable_is_writable;
267
0
  iface->create_source = g_socket_output_stream_pollable_create_source;
268
0
  iface->write_nonblocking = g_socket_output_stream_pollable_write_nonblocking;
269
0
  iface->writev_nonblocking = g_socket_output_stream_pollable_writev_nonblocking;
270
0
}
271
272
static void
273
g_socket_output_stream_init (GSocketOutputStream *stream)
274
0
{
275
0
  stream->priv = g_socket_output_stream_get_instance_private (stream);
276
0
}
277
278
GSocketOutputStream *
279
_g_socket_output_stream_new (GSocket *socket)
280
0
{
281
0
  return g_object_new (G_TYPE_SOCKET_OUTPUT_STREAM, "socket", socket, NULL);
282
0
}