1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5 * Copyright (C) 2000-2003, Ximian, Inc.
12 #include "soup-session-async.h"
13 #include "soup-connection.h"
15 struct SoupSessionAsyncPrivate {
19 static gboolean run_queue (SoupSessionAsync *sa, gboolean try_pruning);
21 static void queue_message (SoupSession *session, SoupMessage *req,
22 SoupMessageCallbackFn callback,
24 static guint send_message (SoupSession *session, SoupMessage *req);
26 #define PARENT_TYPE SOUP_TYPE_SESSION
27 static SoupSessionClass *parent_class;
30 init (GObject *object)
32 SoupSessionAsync *sa = SOUP_SESSION_ASYNC (object);
34 sa->priv = g_new0 (SoupSessionAsyncPrivate, 1);
38 finalize (GObject *object)
40 SoupSessionAsync *sa = SOUP_SESSION_ASYNC (object);
44 G_OBJECT_CLASS (parent_class)->finalize (object);
48 class_init (GObjectClass *object_class)
50 SoupSessionClass *session_class = SOUP_SESSION_CLASS (object_class);
52 parent_class = g_type_class_ref (PARENT_TYPE);
54 /* virtual method override */
55 session_class->queue_message = queue_message;
56 session_class->send_message = send_message;
57 object_class->finalize = finalize;
60 SOUP_MAKE_TYPE (soup_session_async, SoupSessionAsync, class_init, init, PARENT_TYPE)
63 soup_session_async_new (void)
65 return g_object_new (SOUP_TYPE_SESSION_ASYNC, NULL);
69 soup_session_async_new_with_options (const char *optname1, ...)
74 va_start (ap, optname1);
75 session = (SoupSession *)g_object_new_valist (SOUP_TYPE_SESSION_ASYNC,
84 connection_closed (SoupConnection *conn, SoupSessionAsync *sa)
86 /* Run the queue in case anyone was waiting for a connection
89 run_queue (sa, FALSE);
93 got_connection (SoupConnection *conn, guint status, gpointer user_data)
95 SoupSessionAsync *sa = user_data;
97 if (status == SOUP_STATUS_OK) {
98 g_signal_connect (conn, "disconnected",
99 G_CALLBACK (connection_closed),
103 /* Either we just got a connection, or we just failed to
104 * open a connection and so decremented the open connection
105 * count by one. Either way, we need to run the queue now.
107 run_queue (sa, FALSE);
111 run_queue (SoupSessionAsync *sa, gboolean try_pruning)
113 SoupSession *session = SOUP_SESSION (sa);
114 SoupMessageQueueIter iter;
116 SoupConnection *conn;
117 gboolean should_prune = FALSE, started_any = FALSE, is_new;
119 /* FIXME: prefer CONNECTING messages */
122 for (msg = soup_message_queue_first (session->queue, &iter); msg; msg = soup_message_queue_next (session->queue, &iter)) {
124 if (!SOUP_MESSAGE_IS_STARTING (msg))
127 conn = soup_session_get_connection (session, msg,
128 &should_prune, &is_new);
133 soup_connection_connect_async (conn, got_connection,
136 soup_connection_send_request (conn, msg);
141 if (try_pruning && should_prune && !started_any) {
142 /* We didn't manage to start any message, but there is
143 * at least one message in the queue that could be
144 * sent if we pruned an idle connection from some
147 if (soup_session_try_prune_connection (session)) {
157 request_restarted (SoupMessage *req, gpointer sa)
159 run_queue (sa, FALSE);
163 final_finished (SoupMessage *req, gpointer user_data)
165 SoupSessionAsync *sa = user_data;
167 if (!SOUP_MESSAGE_IS_STARTING (req)) {
168 g_signal_handlers_disconnect_by_func (req, final_finished, sa);
169 g_object_unref (req);
172 run_queue (sa, FALSE);
176 queue_message (SoupSession *session, SoupMessage *req,
177 SoupMessageCallbackFn callback, gpointer user_data)
179 SoupSessionAsync *sa = SOUP_SESSION_ASYNC (session);
181 g_signal_connect (req, "restarted",
182 G_CALLBACK (request_restarted), sa);
185 g_signal_connect (req, "finished",
186 G_CALLBACK (callback), user_data);
188 g_signal_connect_after (req, "finished",
189 G_CALLBACK (final_finished), sa);
191 SOUP_SESSION_CLASS (parent_class)->queue_message (session, req,
192 callback, user_data);
194 run_queue (sa, TRUE);
198 send_message (SoupSession *session, SoupMessage *req)
200 /* Balance out the unref that final_finished will do */
203 queue_message (session, req, NULL, NULL);
205 while (req->status != SOUP_MESSAGE_STATUS_FINISHED &&
206 !SOUP_STATUS_IS_TRANSPORT_ERROR (req->status_code))
207 g_main_iteration (TRUE);
209 return req->status_code;