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