1 #include <stdlib.h>
2 #include "gskio.h"
3 #include "gskmacros.h"
4 #include "debug.h"
5
6 /* always use 'notify_connected' from the outside */
7 #define gsk_io_clear_is_connecting(io) _GSK_IO_CLEAR_FIELD (io, is_connecting)
8
9 static GObjectClass *parent_class = NULL;
10
11 /* signals */
12 static guint on_connect_signal = 0;
13 static guint on_error_signal = 0;
14
15 /* ugh... */
16 #define DEBUG_PRINT_HEADER(flags, fctname) \
17 _GSK_DEBUG_PRINTF((flags), ("running %s on %s[%p]", \
18 fctname, g_type_name(G_OBJECT_TYPE(io)), io))
19
20
21 /**
22 * gsk_io_error_cause_to_string:
23 * @cause: the cause code.
24 *
25 * Convert the GskIOErrorCause code into a human-readable lowercase string.
26 *
27 * returns: the error as a string.
28 */
29 const char *
gsk_io_error_cause_to_string(GskIOErrorCause cause)30 gsk_io_error_cause_to_string (GskIOErrorCause cause)
31 {
32 switch (cause)
33 {
34 case GSK_IO_ERROR_NONE: return "none";
35 case GSK_IO_ERROR_OPEN: return "open";
36 case GSK_IO_ERROR_READ: return "read";
37 case GSK_IO_ERROR_WRITE: return "write";
38 case GSK_IO_ERROR_POLL_READ: return "poll-read";
39 case GSK_IO_ERROR_POLL_WRITE: return "poll-write";
40 case GSK_IO_ERROR_SHUTDOWN_READ: return "shutdown-read";
41 case GSK_IO_ERROR_SHUTDOWN_WRITE: return "shutdown-write";
42 case GSK_IO_ERROR_CLOSE: return "close";
43 case GSK_IO_ERROR_SYNC: return "sync";
44 case GSK_IO_ERROR_POLL: return "poll";
45 default: return "*unknown*";
46 }
47 }
48
49 static gboolean default_print_errors = FALSE;
50 static gboolean has_default_print_errors = FALSE;
51
52 void
gsk_io_set_default_print_errors(gboolean print_errors)53 gsk_io_set_default_print_errors (gboolean print_errors)
54 {
55 has_default_print_errors = TRUE;
56 default_print_errors = print_errors;
57 }
58
59 static void
gsk_io_set_error_literal(GskIO * io,GskIOErrorCause cause,GError * error)60 gsk_io_set_error_literal (GskIO *io,
61 GskIOErrorCause cause,
62 GError *error)
63 {
64 g_assert (error != NULL);
65 if (io->error != NULL)
66 g_error_free (io->error);
67 io->error = error;
68 io->error_cause = cause;
69 if (GSK_IS_DEBUGGING (IO) || io->print_errors)
70 g_message ("I/O Error [%s,%p]: cause=%s: %s",
71 G_OBJECT_TYPE_NAME (io), io,
72 gsk_io_error_cause_to_string (cause),
73 error->message);
74
75 g_signal_emit (io, on_error_signal, 0);
76
77 if (io->error != NULL
78 && gsk_io_get_shutdown_on_error (io))
79 {
80 gsk_io_shutdown (io, NULL);
81 }
82 }
83
84 /**
85 * gsk_io_set_error:
86 * @io: the object whose GError member should be set.
87 * @cause: what kind of situation triggered the error
88 * @error_code: an error code.
89 * @format: a printf-like format string.
90 * @Varargs: values to be embedded in the format string.
91 *
92 * Set the error member of the #GskIO.
93 */
94 void
gsk_io_set_error(GskIO * io,GskIOErrorCause cause,GskErrorCode error_code,const char * format,...)95 gsk_io_set_error (GskIO *io,
96 GskIOErrorCause cause,
97 GskErrorCode error_code,
98 const char *format,
99 ...)
100 {
101 va_list args;
102 guint len;
103 char *buf;
104 GError *error;
105
106 va_start (args, format);
107 len = g_printf_string_upper_bound (format, args);
108 buf = alloca (len + 1);
109 g_vsnprintf (buf, len + 1, format, args);
110 va_end (args);
111
112 error = g_error_new_literal (GSK_G_ERROR_DOMAIN, error_code, buf);
113 gsk_io_set_error_literal (io, cause, error);
114 }
115
116 /**
117 * gsk_io_set_gerror:
118 * @io: the IO whose error member should be set.
119 * @cause: the operation which caused the error.
120 * @error: gerror which will be freed by the IO automatically now.
121 *
122 * Set the IO's error member, taking ownership of
123 * the @error parameter.
124 */
125 void
gsk_io_set_gerror(GskIO * io,GskIOErrorCause cause,GError * error)126 gsk_io_set_gerror (GskIO *io,
127 GskIOErrorCause cause,
128 GError *error)
129 {
130 gsk_io_set_error_literal (io, cause, error);
131 }
132
133 /**
134 * gsk_io_shutdown:
135 * @io: the object which should be shut down.
136 * @error: optional error to set upon failure.
137 *
138 * Shutdown the read and write ends of a #GskIO.
139 */
140 void
gsk_io_shutdown(GskIO * io,GError ** error)141 gsk_io_shutdown (GskIO *io, GError **error)
142 {
143 g_object_ref (io);
144 gsk_io_read_shutdown (io, error);
145 gsk_io_write_shutdown (io, error);
146 g_object_unref (io);
147 }
148
149 /* --- implement poll-read/write for nonblocking ios --- */
150
151 /**
152 * gsk_io_notify_shutdown:
153 * @io: the object which is shut-down.
154 *
155 * This function is called by an implementation
156 * when the read- and write- ends of the i/o object
157 * have both shut-down.
158 */
159 void
gsk_io_notify_shutdown(GskIO * io)160 gsk_io_notify_shutdown (GskIO *io)
161 {
162 g_object_ref (io);
163 gsk_io_notify_read_shutdown (io);
164 gsk_io_notify_write_shutdown (io);
165 g_object_unref (io);
166 }
167
168 /**
169 * gsk_io_notify_connected:
170 * @io: the #GskIO that finished connecting to the remote side.
171 *
172 * Trigger an is-connected event. This should only be
173 * called by derived implementations.
174 * Called to indicate that the connection has been made.
175 */
176 void
gsk_io_notify_connected(GskIO * io)177 gsk_io_notify_connected (GskIO *io)
178 {
179 g_return_if_fail (gsk_io_get_is_connecting (io));
180 DEBUG_PRINT_HEADER (GSK_DEBUG_IO, "gsk_io_notify_connected");
181 gsk_io_clear_is_connecting (io);
182 g_signal_emit (io, on_connect_signal, 0);
183 }
184
185 /**
186 * gsk_io_close:
187 * @io: the #GskIO to close.
188 *
189 * Close an open #GskIO.
190 */
191 void
gsk_io_close(GskIO * io)192 gsk_io_close (GskIO *io)
193 {
194 GskIOClass *class = GSK_IO_GET_CLASS (io);
195 g_return_if_fail (io->is_open);
196 if (class->close != NULL)
197 (*class->close) (io);
198 io->is_open = FALSE;
199 }
200
201 static GObject *
gsk_io_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)202 gsk_io_constructor (GType type,
203 guint n_construct_properties,
204 GObjectConstructParam *construct_properties)
205 {
206 GObject *rv = parent_class->constructor (type, n_construct_properties,
207 construct_properties);
208 GskIO *io = GSK_IO (rv);
209 GskIOClass *class = GSK_IO_GET_CLASS (io);
210 _GSK_DEBUG_PRINTF(GSK_DEBUG_LIFETIME,
211 ("constructing %s [%p] [num_construct_properties=%d]",
212 g_type_name (type), rv, n_construct_properties));
213 if (class->open != NULL)
214 {
215 GError *error = NULL;
216 if (class->open (io, &error))
217 {
218 io->is_open = 1;
219 }
220 else
221 {
222 if (error == NULL)
223 gsk_io_set_error (io, GSK_IO_ERROR_OPEN,
224 GSK_ERROR_OPEN_FAILED,
225 _("open failed for %s (no explanation given)"),
226 g_type_name (G_OBJECT_CLASS_TYPE (class)));
227 else
228 gsk_io_set_error_literal (io, GSK_IO_ERROR_OPEN, error);
229 io->open_failed = 1;
230 }
231 }
232 else
233 {
234 io->is_open = 1;
235 }
236 return rv;
237 }
238
239 static void
gsk_io_finalize(GObject * object)240 gsk_io_finalize (GObject *object)
241 {
242 GskIO *io = GSK_IO (object);
243 DEBUG_PRINT_HEADER(GSK_DEBUG_IO | GSK_DEBUG_LIFETIME, "gsk_io_finalize");
244
245 /* TO CONSIDER: should we close then destruct the hooks, instead? */
246 gsk_hook_destruct (&io->read_hook);
247 gsk_hook_destruct (&io->write_hook);
248 if (io->error)
249 g_error_free (io->error);
250 gsk_io_close (io);
251 (*parent_class->finalize) (object);
252 }
253
254
255 /* --- functions --- */
256 static void
gsk_io_init(GskIO * io)257 gsk_io_init (GskIO *io)
258 {
259 gsk_io_mark_shutdown_on_error (io);
260 io->print_errors = default_print_errors;
261 GSK_HOOK_INIT (io, GskIO, read_hook,
262 GSK_HOOK_CAN_HAVE_SHUTDOWN_ERROR,
263 set_poll_read, shutdown_read);
264 GSK_HOOK_INIT (io, GskIO, write_hook,
265 GSK_HOOK_CAN_HAVE_SHUTDOWN_ERROR,
266 set_poll_write, shutdown_write);
267 }
268
269 static void
gsk_io_class_init(GskIOClass * class)270 gsk_io_class_init (GskIOClass *class)
271 {
272 GObjectClass *object_class = G_OBJECT_CLASS (class);
273 GType type = G_OBJECT_CLASS_TYPE (object_class);
274 parent_class = g_type_class_peek_parent (class);
275 object_class->constructor = gsk_io_constructor;
276 object_class->finalize = gsk_io_finalize;
277 GSK_HOOK_CLASS_INIT (object_class, "read", GskIO, read_hook);
278 GSK_HOOK_CLASS_INIT (object_class, "write", GskIO, write_hook);
279 on_connect_signal
280 = g_signal_new ("on-connect",
281 type,
282 G_SIGNAL_NO_RECURSE,
283 G_STRUCT_OFFSET (GskIOClass, on_connect),
284 NULL, /* accumulator */
285 NULL, /* accu_data */
286 g_cclosure_marshal_VOID__VOID,
287 G_TYPE_NONE,
288 0);
289 on_error_signal
290 = g_signal_new ("on-error",
291 type,
292 G_SIGNAL_NO_RECURSE,
293 G_STRUCT_OFFSET (GskIOClass, on_error),
294 NULL, /* accumulator */
295 NULL, /* accu_data */
296 g_cclosure_marshal_VOID__VOID,
297 G_TYPE_NONE,
298 0);
299
300 if (!has_default_print_errors)
301 {
302 const char *env = getenv ("GSK_PRINT_ERRORS");
303 if (env)
304 gsk_io_set_default_print_errors (atoi (env) ? 1 : 0);
305 }
306 }
307
gsk_io_get_type()308 GType gsk_io_get_type()
309 {
310 static GType io_type = 0;
311 if (!io_type)
312 {
313 static const GTypeInfo io_info =
314 {
315 sizeof(GskIOClass),
316 (GBaseInitFunc) NULL,
317 (GBaseFinalizeFunc) NULL,
318 (GClassInitFunc) gsk_io_class_init,
319 NULL, /* class_finalize */
320 NULL, /* class_data */
321 sizeof (GskIO),
322 0, /* n_preallocs */
323 (GInstanceInitFunc) gsk_io_init,
324 NULL /* value_table */
325 };
326 io_type = g_type_register_static (G_TYPE_OBJECT, "GskIO",
327 &io_info, G_TYPE_FLAG_ABSTRACT);
328 }
329 return io_type;
330 }
331