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 "gsocketinputstream.h" |
26 | #include "glibintl.h" |
27 | |
28 | #include "gcancellable.h" |
29 | #include "gpollableinputstream.h" |
30 | #include "gioerror.h" |
31 | #include "gfiledescriptorbased.h" |
32 | |
33 | struct _GSocketInputStreamPrivate |
34 | { |
35 | GSocket *socket; |
36 | |
37 | /* pending operation metadata */ |
38 | gpointer buffer; |
39 | gsize count; |
40 | }; |
41 | |
42 | static void g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); |
43 | #ifdef G_OS_UNIX |
44 | static void g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); |
45 | #endif |
46 | |
47 | #define g_socket_input_stream_get_type _g_socket_input_stream_get_type |
48 | |
49 | #ifdef G_OS_UNIX |
50 | G_DEFINE_TYPE_WITH_CODE (GSocketInputStream, g_socket_input_stream, G_TYPE_INPUT_STREAM, |
51 | G_ADD_PRIVATE (GSocketInputStream) |
52 | G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, g_socket_input_stream_pollable_iface_init) |
53 | G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED, g_socket_input_stream_file_descriptor_based_iface_init) |
54 | ) |
55 | #else |
56 | G_DEFINE_TYPE_WITH_CODE (GSocketInputStream, g_socket_input_stream, G_TYPE_INPUT_STREAM, |
57 | G_ADD_PRIVATE (GSocketInputStream) |
58 | G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, g_socket_input_stream_pollable_iface_init) |
59 | ) |
60 | #endif |
61 | |
62 | enum |
63 | { |
64 | PROP_0, |
65 | PROP_SOCKET |
66 | }; |
67 | |
68 | static void |
69 | g_socket_input_stream_get_property (GObject *object, |
70 | guint prop_id, |
71 | GValue *value, |
72 | GParamSpec *pspec) |
73 | { |
74 | GSocketInputStream *stream = G_SOCKET_INPUT_STREAM (object); |
75 | |
76 | switch (prop_id) |
77 | { |
78 | case PROP_SOCKET: |
79 | g_value_set_object (value, v_object: stream->priv->socket); |
80 | break; |
81 | |
82 | default: |
83 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
84 | } |
85 | } |
86 | |
87 | static void |
88 | g_socket_input_stream_set_property (GObject *object, |
89 | guint prop_id, |
90 | const GValue *value, |
91 | GParamSpec *pspec) |
92 | { |
93 | GSocketInputStream *stream = G_SOCKET_INPUT_STREAM (object); |
94 | |
95 | switch (prop_id) |
96 | { |
97 | case PROP_SOCKET: |
98 | stream->priv->socket = g_value_dup_object (value); |
99 | break; |
100 | |
101 | default: |
102 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
103 | } |
104 | } |
105 | |
106 | static void |
107 | g_socket_input_stream_finalize (GObject *object) |
108 | { |
109 | GSocketInputStream *stream = G_SOCKET_INPUT_STREAM (object); |
110 | |
111 | if (stream->priv->socket) |
112 | g_object_unref (object: stream->priv->socket); |
113 | |
114 | G_OBJECT_CLASS (g_socket_input_stream_parent_class)->finalize (object); |
115 | } |
116 | |
117 | static gssize |
118 | g_socket_input_stream_read (GInputStream *stream, |
119 | void *buffer, |
120 | gsize count, |
121 | GCancellable *cancellable, |
122 | GError **error) |
123 | { |
124 | GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (stream); |
125 | |
126 | return g_socket_receive_with_blocking (socket: input_stream->priv->socket, |
127 | buffer, size: count, TRUE, |
128 | cancellable, error); |
129 | } |
130 | |
131 | static gboolean |
132 | g_socket_input_stream_pollable_is_readable (GPollableInputStream *pollable) |
133 | { |
134 | GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (pollable); |
135 | |
136 | return g_socket_condition_check (socket: input_stream->priv->socket, condition: G_IO_IN); |
137 | } |
138 | |
139 | static GSource * |
140 | g_socket_input_stream_pollable_create_source (GPollableInputStream *pollable, |
141 | GCancellable *cancellable) |
142 | { |
143 | GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (pollable); |
144 | GSource *socket_source, *pollable_source; |
145 | |
146 | pollable_source = g_pollable_source_new (G_OBJECT (input_stream)); |
147 | socket_source = g_socket_create_source (socket: input_stream->priv->socket, |
148 | condition: G_IO_IN, cancellable); |
149 | g_source_set_dummy_callback (source: socket_source); |
150 | g_source_add_child_source (source: pollable_source, child_source: socket_source); |
151 | g_source_unref (source: socket_source); |
152 | |
153 | return pollable_source; |
154 | } |
155 | |
156 | static gssize |
157 | g_socket_input_stream_pollable_read_nonblocking (GPollableInputStream *pollable, |
158 | void *buffer, |
159 | gsize size, |
160 | GError **error) |
161 | { |
162 | GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (pollable); |
163 | |
164 | return g_socket_receive_with_blocking (socket: input_stream->priv->socket, |
165 | buffer, size, FALSE, |
166 | NULL, error); |
167 | } |
168 | |
169 | #ifdef G_OS_UNIX |
170 | static int |
171 | g_socket_input_stream_get_fd (GFileDescriptorBased *fd_based) |
172 | { |
173 | GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (fd_based); |
174 | |
175 | return g_socket_get_fd (socket: input_stream->priv->socket); |
176 | } |
177 | #endif |
178 | |
179 | static void |
180 | g_socket_input_stream_class_init (GSocketInputStreamClass *klass) |
181 | { |
182 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
183 | GInputStreamClass *ginputstream_class = G_INPUT_STREAM_CLASS (klass); |
184 | |
185 | gobject_class->finalize = g_socket_input_stream_finalize; |
186 | gobject_class->get_property = g_socket_input_stream_get_property; |
187 | gobject_class->set_property = g_socket_input_stream_set_property; |
188 | |
189 | ginputstream_class->read_fn = g_socket_input_stream_read; |
190 | |
191 | g_object_class_install_property (oclass: gobject_class, property_id: PROP_SOCKET, |
192 | pspec: g_param_spec_object (name: "socket" , |
193 | P_("socket" ), |
194 | P_("The socket that this stream wraps" ), |
195 | G_TYPE_SOCKET, flags: G_PARAM_CONSTRUCT_ONLY | |
196 | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
197 | } |
198 | |
199 | #ifdef G_OS_UNIX |
200 | static void |
201 | g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) |
202 | { |
203 | iface->get_fd = g_socket_input_stream_get_fd; |
204 | } |
205 | #endif |
206 | |
207 | static void |
208 | g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) |
209 | { |
210 | iface->is_readable = g_socket_input_stream_pollable_is_readable; |
211 | iface->create_source = g_socket_input_stream_pollable_create_source; |
212 | iface->read_nonblocking = g_socket_input_stream_pollable_read_nonblocking; |
213 | } |
214 | |
215 | static void |
216 | g_socket_input_stream_init (GSocketInputStream *stream) |
217 | { |
218 | stream->priv = g_socket_input_stream_get_instance_private (self: stream); |
219 | } |
220 | |
221 | GSocketInputStream * |
222 | _g_socket_input_stream_new (GSocket *socket) |
223 | { |
224 | return g_object_new (G_TYPE_SOCKET_INPUT_STREAM, first_property_name: "socket" , socket, NULL); |
225 | } |
226 | |