4 * Copyright (C) 2005 Novell, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
34 #include <sys/types.h>
35 #include <sys/socket.h>
38 #include "beagle-error-response.h"
39 #include "beagle-marshal.h"
40 #include "beagle-parser.h"
41 #include "beagle-request.h"
42 #include "beagle-private.h"
43 #include "beagle-util.h"
49 BeagleParserContext
*ctx
;
50 } BeagleRequestPrivate
;
52 #define BEAGLE_REQUEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BEAGLE_TYPE_REQUEST, BeagleRequestPrivate))
61 static GObjectClass
*parent_class
= NULL
;
62 static guint signals
[LAST_SIGNAL
] = { 0 };
64 G_DEFINE_TYPE (BeagleRequest
, beagle_request
, G_TYPE_OBJECT
)
67 beagle_request_finalize (GObject
*obj
)
69 BeagleRequestPrivate
*priv
= BEAGLE_REQUEST_GET_PRIVATE (obj
);
73 if (priv
->io_watch
!= 0) {
74 g_source_remove (priv
->io_watch
);
79 g_io_channel_unref (priv
->channel
);
83 if (G_OBJECT_CLASS (parent_class
)->finalize
)
84 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
88 beagle_request_class_init (BeagleRequestClass
*klass
)
90 GObjectClass
*obj_class
= G_OBJECT_CLASS (klass
);
92 parent_class
= g_type_class_peek_parent (klass
);
94 obj_class
->finalize
= beagle_request_finalize
;
96 signals
[CLOSED
] = g_signal_new ("closed",
97 G_TYPE_FROM_CLASS (klass
),
99 G_STRUCT_OFFSET (BeagleRequestClass
, closed
),
101 beagle_marshal_VOID__VOID
,
103 signals
[RESPONSE
] = g_signal_new ("response",
104 G_TYPE_FROM_CLASS (klass
),
106 G_STRUCT_OFFSET (BeagleRequestClass
, response
),
108 g_cclosure_marshal_VOID__OBJECT
,
110 BEAGLE_TYPE_RESPONSE
);
111 signals
[ERROR
] = g_signal_new ("error",
112 G_TYPE_FROM_CLASS (klass
),
114 G_STRUCT_OFFSET (BeagleRequestClass
, error
),
116 g_cclosure_marshal_VOID__POINTER
,
120 g_type_class_add_private (klass
, sizeof (BeagleRequestPrivate
));
122 klass
->response_types
= g_hash_table_new_full (g_str_hash
,
127 g_hash_table_insert (klass
->response_types
,
128 g_strdup ("ErrorResponse"),
129 (gpointer
) BEAGLE_TYPE_ERROR_RESPONSE
);
133 beagle_request_init (BeagleRequest
*request
)
138 _beagle_request_class_set_response_types (BeagleRequestClass
*klass
,
139 const char *beagle_type
,
146 g_hash_table_replace (klass
->response_types
,
147 g_strdup (beagle_type
),
148 (gpointer
) gobject_type
);
150 va_start (args
, gobject_type
);
151 arg
= va_arg (args
, const char *);
153 while (arg
!= NULL
) {
154 GType gtype
= va_arg (args
, GType
);
156 g_hash_table_replace (klass
->response_types
,
160 arg
= va_arg (args
, const char *);
167 request_connect (BeagleRequest
*request
, const char *path
, GError
**err
)
169 BeagleRequestPrivate
*priv
;
171 struct sockaddr_un sun
;
173 priv
= BEAGLE_REQUEST_GET_PRIVATE (request
);
175 sockfd
= socket (AF_UNIX
, SOCK_STREAM
, 0);
177 g_set_error (err
, BEAGLE_ERROR
, BEAGLE_ERROR
,
178 "Unable to create connection");
182 bzero (&sun
, sizeof (sun
));
183 sun
.sun_family
= AF_UNIX
;
184 snprintf (sun
.sun_path
, sizeof (sun
.sun_path
), path
);
186 if (connect (sockfd
, (struct sockaddr
*) &sun
, sizeof (sun
)) < 0) {
187 g_set_error (err
, BEAGLE_ERROR
, BEAGLE_ERROR
,
188 "Unable to connect to Beagle daemon");
193 priv
->path
= g_strdup (path
);
195 priv
->channel
= g_io_channel_unix_new (sockfd
);
197 g_io_channel_set_encoding (priv
->channel
, NULL
, NULL
);
198 g_io_channel_set_buffered (priv
->channel
, FALSE
);
199 g_io_channel_set_close_on_unref (priv
->channel
, TRUE
);
205 request_close (BeagleRequest
*request
)
207 BeagleRequestPrivate
*priv
;
209 priv
= BEAGLE_REQUEST_GET_PRIVATE (request
);
211 g_return_if_fail (priv
->channel
!= NULL
);
216 g_io_channel_unref (priv
->channel
);
217 priv
->channel
= NULL
;
219 g_source_remove (priv
->io_watch
);
222 g_signal_emit (request
, signals
[CLOSED
], 0);
226 request_send (BeagleRequest
*request
, const char *socket_path
, GError
**err
)
228 BeagleRequestPrivate
*priv
;
230 gsize bytes_written
, total_written
;
231 char eom_marker
= 0xff;
234 if (!request_connect (request
, socket_path
, err
))
237 priv
= BEAGLE_REQUEST_GET_PRIVATE (request
);
239 buffer
= BEAGLE_REQUEST_GET_CLASS (request
)->to_xml (request
, err
);
243 #ifdef ENABLE_XML_DUMP
244 printf ("Sending request:\n");
245 printf ("%*s\n\n", buffer
->len
, buffer
->str
);
248 /* Send the data over the wire */
251 status
= g_io_channel_write_chars (priv
->channel
,
252 buffer
->str
+ total_written
,
253 buffer
->len
- total_written
,
256 total_written
+= bytes_written
;
257 } while ((status
== G_IO_STATUS_NORMAL
|| status
== G_IO_STATUS_AGAIN
)
258 && total_written
< buffer
->len
);
260 if (status
== G_IO_STATUS_ERROR
)
263 /* And send the end-of-message marker */
265 status
= g_io_channel_write_chars (priv
->channel
,
269 } while ((status
== G_IO_STATUS_NORMAL
|| status
== G_IO_STATUS_AGAIN
)
270 && total_written
== 0);
272 if (status
== G_IO_STATUS_ERROR
)
279 request_io_cb (GIOChannel
*channel
, GIOCondition condition
, gpointer user_data
)
281 BeagleRequestPrivate
*priv
= BEAGLE_REQUEST_GET_PRIVATE (user_data
);
287 BeagleResponse
*response
;
289 if (condition
& G_IO_IN
) {
291 GError
*error
= NULL
;
293 status
= g_io_channel_read_chars (priv
->channel
,
298 if (status
== G_IO_STATUS_ERROR
) {
299 g_signal_emit (user_data
, signals
[ERROR
], 0, error
);
300 g_error_free (error
);
304 if (bytes_read
> 0) {
307 while (start
< bytes_read
) {
308 marker
= memchr (buf
+ start
, 0xff, bytes_read
- start
);
311 priv
->ctx
= _beagle_parser_context_new ();
314 if (marker
!= NULL
) {
315 to_parse
= (marker
- buf
) - start
;
318 _beagle_parser_context_parse_chunk (priv
->ctx
, buf
+ start
, to_parse
);
321 /* Finish the context */
322 response
= _beagle_parser_context_finished (priv
->ctx
);
323 g_assert (response
!= NULL
);
325 if (BEAGLE_IS_ERROR_RESPONSE (response
)) {
326 _beagle_error_response_to_g_error (BEAGLE_ERROR_RESPONSE (response
), &error
);
327 g_signal_emit (BEAGLE_REQUEST (user_data
),
328 signals
[ERROR
], 0, error
);
329 g_error_free (error
);
332 g_signal_emit (BEAGLE_REQUEST (user_data
),
333 signals
[RESPONSE
], 0, response
);
335 g_object_unref (response
);
337 /* Move past the 0xff marker */
338 start
+= to_parse
+ 1;
343 _beagle_parser_context_parse_chunk (priv
->ctx
, buf
+ start
, bytes_read
- start
);
348 } while (bytes_read
== 4096 || status
== G_IO_STATUS_AGAIN
);
351 if (condition
& G_IO_HUP
||
352 condition
& G_IO_ERR
) {
353 request_close (BEAGLE_REQUEST (user_data
));
360 _beagle_request_send_async (BeagleRequest
*request
,
361 const char *socket_path
,
364 BeagleRequestPrivate
*priv
= BEAGLE_REQUEST_GET_PRIVATE (request
);
366 if (!request_send (request
, socket_path
, err
))
369 priv
->io_watch
= g_io_add_watch (priv
->channel
,
370 G_IO_IN
| G_IO_HUP
| G_IO_ERR
,
378 _beagle_request_send (BeagleRequest
*request
, const char *socket_path
, GError
**err
)
380 BeagleRequestPrivate
*priv
;
381 BeagleParserContext
*ctx
;
386 BeagleResponse
*response
;
388 if (!request_send (request
, socket_path
, err
))
391 priv
= BEAGLE_REQUEST_GET_PRIVATE (request
);
393 ctx
= _beagle_parser_context_new ();
398 status
= g_io_channel_read_chars (priv
->channel
,
403 if (bytes_read
> 0) {
404 marker
= memchr (buf
, 0xff, bytes_read
);
407 to_parse
= marker
- buf
;
409 to_parse
= bytes_read
;
411 _beagle_parser_context_parse_chunk (ctx
, buf
, to_parse
);
413 } while ((status
== G_IO_STATUS_NORMAL
|| G_IO_STATUS_AGAIN
) &&
416 response
= _beagle_parser_context_finished (ctx
);
418 g_io_channel_unref (priv
->channel
);
419 priv
->channel
= NULL
;
421 if (BEAGLE_IS_ERROR_RESPONSE (response
)) {
422 _beagle_error_response_to_g_error (BEAGLE_ERROR_RESPONSE (response
), err
);
423 g_object_unref (response
);
431 _beagle_request_append_standard_header (GString
*data
, const char *xsi_type
)
433 const char header
[] =
434 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
435 "<RequestWrapper xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
436 "<Message xsi:type=\"";
438 g_string_append_len (data
, header
, sizeof (header
) - 1);
439 g_string_append (data
, xsi_type
);
440 g_string_append_len (data
, "\">", 2);
444 _beagle_request_append_standard_footer (GString
*data
)
446 const char footer
[] = "</Message></RequestWrapper>";
448 g_string_append_len (data
, footer
, sizeof (footer
) - 1);