1 /*
2  * GNetwork Library: libgnetwork/gnetwork-connection.c
3  *
4  * Copyright (c) 2003 James M. Cape.
5  * All Rights Reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; version 2.1 of the
10  * License.
11  *
12  * This program 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
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20  * USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif /* HAVE_CONFIG_H */
26 
27 
28 #include "gnetwork-connection.h"
29 
30 #include "gnetwork-type-builtins.h"
31 #include "gnetwork-errors.h"
32 
33 #include "marshal.h"
34 
35 #include <glib/gi18n.h>
36 
37 #define G_UCHAR(ptr)	((guchar *) (ptr))
38 
39 
40 enum
41 {
42   RECEIVED,
43   SENT,
44   ERROR,
45   LAST_SIGNAL
46 };
47 
48 
49 typedef struct _EnumString
50 {
51   const guint value;
52   const gchar *const str;
53 }
54 EnumString;
55 
56 
57 static gint signals[LAST_SIGNAL] = { 0 };
58 
59 
60 /* ***************** *
61  *  GType Functions  *
62  * ***************** */
63 
64 static void
gnetwork_connection_base_init(gpointer g_iface)65 gnetwork_connection_base_init (gpointer g_iface)
66 {
67   static gboolean initialized = FALSE;
68 
69   if (!initialized)
70     {
71       signals[RECEIVED] =
72 	g_signal_new ("received",
73 		      GNETWORK_TYPE_CONNECTION,
74 		      G_SIGNAL_RUN_FIRST,
75 		      G_STRUCT_OFFSET (GNetworkConnectionIface, received),
76 		      NULL, NULL, _gnetwork_marshal_VOID__POINTER_ULONG,
77 		      G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_ULONG);
78       signals[SENT] =
79 	g_signal_new ("sent",
80 		      GNETWORK_TYPE_CONNECTION,
81 		      G_SIGNAL_RUN_FIRST,
82 		      G_STRUCT_OFFSET (GNetworkConnectionIface, sent),
83 		      NULL, NULL, _gnetwork_marshal_VOID__POINTER_ULONG,
84 		      G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_ULONG);
85       signals[ERROR] =
86 	g_signal_new ("error",
87 		      GNETWORK_TYPE_CONNECTION,
88 		      (G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED),
89 		      G_STRUCT_OFFSET (GNetworkConnectionIface, error),
90 		      NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ERROR);
91 
92       g_object_interface_install_property (g_iface,
93 					   g_param_spec_enum ("connection-type",
94 							      _("Connection Type"),
95 							      _("The type of connection "
96 								"represented by the implementing "
97 								"object."),
98 							      GNETWORK_TYPE_CONNECTION_TYPE,
99 							      GNETWORK_CONNECTION_CLIENT,
100 							      (G_PARAM_READWRITE
101 							       | G_PARAM_CONSTRUCT)));
102 
103       g_object_interface_install_property (g_iface,
104 					   g_param_spec_enum ("status", _("Connection Status"),
105 							      _("The status of this connection."),
106 							      GNETWORK_TYPE_CONNECTION_STATUS,
107 							      GNETWORK_CONNECTION_CLOSED,
108 							      G_PARAM_READABLE));
109       g_object_interface_install_property (g_iface,
110 					   g_param_spec_ulong ("bytes-received",
111 							       _("Bytes Received"),
112 							       _("The number of bytes received "
113 								 "through this connection."),
114 							       0, G_MAXULONG, 0, G_PARAM_READABLE));
115       g_object_interface_install_property (g_iface,
116 					   g_param_spec_ulong ("bytes-sent", _("Bytes Sent"),
117 							       _("The number of bytes sent through "
118 								 "this connection."),
119 							       0, G_MAXULONG, 0, G_PARAM_READABLE));
120       g_object_interface_install_property (g_iface,
121 					   g_param_spec_uint ("buffer-size", _("Buffer Size"),
122 							      _("The maximum size in bytes of "
123 								"outgoing and incoming data "
124 								"packets."), 0, G_MAXUINT, 2048,
125 							      (G_PARAM_READWRITE |
126 							       G_PARAM_CONSTRUCT)));
127 
128       initialized = TRUE;
129     }
130 }
131 
132 
133 /* ************************************************************************** *
134  *  Public API                                                                *
135  * ************************************************************************** */
136 
137 GType
gnetwork_connection_get_type(void)138 gnetwork_connection_get_type (void)
139 {
140   static GType type = G_TYPE_INVALID;
141 
142   if (type == G_TYPE_INVALID)
143     {
144       static const GTypeInfo info = {
145 	sizeof (GNetworkConnectionIface),	/* class_size */
146 	gnetwork_connection_base_init,	/* base_init */
147 	NULL,			/* base_finalize */
148 	NULL,
149 	NULL,			/* class_finalize */
150 	NULL,			/* class_data */
151 	0,
152 	0,			/* n_preallocs */
153 	NULL
154       };
155 
156       type = g_type_register_static (G_TYPE_INTERFACE, "GNetworkConnection", &info, 0);
157 
158       g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
159     }
160 
161   return type;
162 }
163 
164 
165 /**
166  * gnetwork_connection_open:
167  * @connection: the connection to open.
168  *
169  * Starts the connection process for @connection.
170  *
171  * Since: 1.0
172  **/
173 void
gnetwork_connection_open(GNetworkConnection * connection)174 gnetwork_connection_open (GNetworkConnection * connection)
175 {
176   GNetworkConnectionIface *iface;
177 
178   g_return_if_fail (GNETWORK_IS_CONNECTION (connection));
179 
180   iface = GNETWORK_CONNECTION_GET_IFACE (connection);
181 
182   g_return_if_fail (iface->open != NULL);
183 
184   g_object_ref (connection);
185   (*iface->open) (connection);
186   g_object_unref (connection);
187 }
188 
189 
190 /**
191  * gnetwork_connection_close:
192  * @connection: the connection to close.
193  *
194  * Closes the @connection in question.
195  *
196  * Since: 1.0
197  **/
198 void
gnetwork_connection_close(GNetworkConnection * connection)199 gnetwork_connection_close (GNetworkConnection * connection)
200 {
201   GNetworkConnectionIface *iface;
202 
203   g_return_if_fail (GNETWORK_IS_CONNECTION (connection));
204 
205   iface = GNETWORK_CONNECTION_GET_IFACE (connection);
206 
207   g_return_if_fail (iface->close != NULL);
208 
209   g_object_ref (connection);
210   (*iface->close) (connection);
211   g_object_unref (connection);
212 }
213 
214 
215 /**
216  * gnetwork_connection_send:
217  * @connection: the connection to send through.
218  * @data: the data to send.
219  * @length: the length in bytes of @data.
220  *
221  * Sends the data in @data through @connection. If @length is less than one,
222  * @data is assumed to be terminated by %0. This function will perform the
223  * necessary calculations for @length. After calling the implementation's
224  * send function, the "send" signal will be emitted.
225  *
226  * Since: 1.0
227  **/
228 void
gnetwork_connection_send(GNetworkConnection * connection,gconstpointer data,glong length)229 gnetwork_connection_send (GNetworkConnection * connection, gconstpointer data, glong length)
230 {
231   GNetworkConnectionIface *iface;
232 
233   g_return_if_fail (GNETWORK_IS_CONNECTION (connection));
234   g_return_if_fail (data != NULL);
235   g_return_if_fail (data != 0);
236 
237   iface = GNETWORK_CONNECTION_GET_IFACE (connection);
238 
239   g_return_if_fail (iface->send != NULL);
240 
241   if (length < 0)
242     {
243       for (length = 0; *(G_UCHAR (data) + length) != 0; length++);
244     }
245 
246   g_object_ref (connection);
247   (*iface->send) (connection, data, (gulong) length);
248   g_object_unref (connection);
249 }
250 
251 
252 /**
253  * gnetwork_connection_received:
254  * @connection: the connection to use.
255  * @data: the data being recieved.
256  * @length: the length of @data in bytes.
257  *
258  * Emits the "received" signal for @connection, using the values in @data and @length.
259  * Implementations of the #GNetworkConnectionIface interface should use this function
260  * when data has been received.
261  *
262  * Since: 1.0
263  **/
264 void
gnetwork_connection_received(GNetworkConnection * connection,gconstpointer data,gulong length)265 gnetwork_connection_received (GNetworkConnection * connection, gconstpointer data, gulong length)
266 {
267   g_return_if_fail (GNETWORK_IS_CONNECTION (connection));
268   g_return_if_fail (data != NULL);
269   g_return_if_fail (length > 0);
270 
271   g_object_ref (connection);
272   g_signal_emit (connection, signals[RECEIVED], 0, data, length);
273   g_object_unref (connection);
274 }
275 
276 
277 /**
278  * gnetwork_connection_sent:
279  * @connection: the connection to use.
280  * @data: the data which was sent.
281  * @length: the length of @data in bytes.
282  *
283  * Emits the "sent" signal for @connection, using the values in @data and
284  * @length. Implementations of the #GNetworkConnectionIface interface should
285  * call this function when data has been sent.
286  *
287  * Since: 1.0
288  **/
289 void
gnetwork_connection_sent(GNetworkConnection * connection,gconstpointer data,gulong length)290 gnetwork_connection_sent (GNetworkConnection * connection, gconstpointer data, gulong length)
291 {
292   g_return_if_fail (GNETWORK_IS_CONNECTION (connection));
293   g_return_if_fail (data != NULL);
294   g_return_if_fail (length > 0);
295 
296   g_object_ref (connection);
297   g_signal_emit (connection, signals[SENT], 0, data, length);
298   g_object_unref (connection);
299 }
300 
301 
302 /**
303  * gnetwork_connection_error:
304  * @connection: the connection to use.
305  * @error: the error structure.
306  *
307  * Emits the "error" signal for @connection, using @error. Callers to this function
308  * should use their own error domains.
309  *
310  * Since: 1.0
311  **/
312 void
gnetwork_connection_error(GNetworkConnection * connection,const GError * error)313 gnetwork_connection_error (GNetworkConnection * connection, const GError * error)
314 {
315   g_return_if_fail (GNETWORK_IS_CONNECTION (connection));
316   g_return_if_fail (error != NULL);
317 
318   g_object_ref (connection);
319   g_signal_emit (connection, signals[ERROR], error->domain, error);
320   g_object_unref (connection);
321 }
322 
323 
324 /**
325  * gnetwork_connection_strerror:
326  * @error: the connection error code to use.
327  *
328  * Retrieves a string message describing @error. The returned data should not
329  * be modified or freed.
330  *
331  * Returns: the string message describing @error.
332  *
333  * Since: 1.0
334  **/
335 G_CONST_RETURN gchar *
gnetwork_connection_strerror(GNetworkConnectionError error)336 gnetwork_connection_strerror (GNetworkConnectionError error)
337 {
338   const gchar *str;
339 
340   g_return_val_if_fail (error >= GNETWORK_CONNECTION_ERROR_INTERNAL &&
341 		        error <= GNETWORK_CONNECTION_ERROR_PERMISSIONS, NULL);
342 
343   switch (error)
344     {
345     case GNETWORK_CONNECTION_ERROR_INTERNAL:
346       str = _("There was an error inside of the networking library.");
347       break;
348     case GNETWORK_CONNECTION_ERROR_REFUSED:
349       str = _("The service will not let you connect.");
350       break;
351     case GNETWORK_CONNECTION_ERROR_TIMEOUT:
352       str = _("The service may be down, or you may have been disconnected from the network.");
353       break;
354     case GNETWORK_CONNECTION_ERROR_UNREACHABLE:
355       str = _("The service could not be contacted.");
356       break;
357     case GNETWORK_CONNECTION_ERROR_PERMISSIONS:
358       str = _("Your computer or firewall is configured to prevent access to the service.");
359       break;
360     default:
361       g_assert_not_reached ();
362       str = NULL;
363   };
364 
365   return str;
366 }
367 
368 
369 G_LOCK_DEFINE_STATIC (quark);
370 
371 GQuark
gnetwork_connection_error_get_quark(void)372 gnetwork_connection_error_get_quark (void)
373 {
374   static volatile GQuark quark = 0;
375 
376   G_LOCK (quark);
377 
378   if (quark == 0)
379     {
380       quark = g_quark_from_static_string ("gnetwork-connection-error");
381     }
382 
383   G_UNLOCK (quark);
384 
385   return quark;
386 }
387