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-sync.h"
13 #include "soup-connection.h"
15 struct SoupSessionSyncPrivate {
20 void queue_message (SoupSession *session, SoupMessage *msg,
21 SoupMessageCallbackFn callback,
23 static guint send_message (SoupSession *session, SoupMessage *msg);
24 static void cancel_message (SoupSession *session, SoupMessage *msg);
26 #define PARENT_TYPE SOUP_TYPE_SESSION
27 static SoupSessionClass *parent_class;
30 init (GObject *object)
32 SoupSessionSync *ss = SOUP_SESSION_SYNC (object);
34 ss->priv = g_new0 (SoupSessionSyncPrivate, 1);
35 ss->priv->lock = g_mutex_new ();
36 ss->priv->cond = g_cond_new ();
40 finalize (GObject *object)
42 SoupSessionSync *ss = SOUP_SESSION_SYNC (object);
44 g_mutex_free (ss->priv->lock);
45 g_cond_free (ss->priv->cond);
48 G_OBJECT_CLASS (parent_class)->finalize (object);
52 class_init (GObjectClass *object_class)
54 SoupSessionClass *session_class = SOUP_SESSION_CLASS (object_class);
56 parent_class = g_type_class_ref (PARENT_TYPE);
58 /* virtual method override */
59 session_class->queue_message = queue_message;
60 session_class->send_message = send_message;
61 session_class->cancel_message = cancel_message;
62 object_class->finalize = finalize;
65 SOUP_MAKE_TYPE (soup_session_sync, SoupSessionSync, class_init, init, PARENT_TYPE)
68 soup_session_sync_new (void)
70 return g_object_new (SOUP_TYPE_SESSION_SYNC, NULL);
74 soup_session_sync_new_with_options (const char *optname1, ...)
79 va_start (ap, optname1);
80 session = (SoupSession *)g_object_new_valist (SOUP_TYPE_SESSION_SYNC,
89 queue_message (SoupSession *session, SoupMessage *msg,
90 SoupMessageCallbackFn callback, gpointer user_data)
93 g_warning ("soup_session_queue_message called on synchronous session");
96 static SoupConnection *
97 wait_for_connection (SoupSession *session, SoupMessage *msg)
99 SoupSessionSync *ss = SOUP_SESSION_SYNC (session);
100 SoupConnection *conn;
101 gboolean try_pruning = FALSE, is_new = FALSE;
104 g_mutex_lock (ss->priv->lock);
107 conn = soup_session_get_connection (session, msg,
108 &try_pruning, &is_new);
111 status = soup_connection_connect_sync (conn);
113 /* If the connection attempt fails, SoupSession
114 * will notice, unref conn, and set an error
115 * status on msg. So all we need to do is just
116 * not return the no-longer-valid connection.
119 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
121 else if (msg->status == SOUP_MESSAGE_STATUS_FINISHED) {
122 /* Message was cancelled while we were
125 soup_connection_disconnect (conn);
130 g_mutex_unlock (ss->priv->lock);
134 if (try_pruning && soup_session_try_prune_connection (session))
138 g_cond_wait (ss->priv->cond, ss->priv->lock);
140 /* See if something bad happened */
141 if (msg->status == SOUP_MESSAGE_STATUS_FINISHED) {
142 g_mutex_unlock (ss->priv->lock);
150 send_message (SoupSession *session, SoupMessage *msg)
152 SoupConnection *conn;
154 SOUP_SESSION_CLASS (parent_class)->queue_message (session, msg,
158 /* Get a connection */
159 conn = wait_for_connection (session, msg);
161 return msg->status_code;
163 /* Set up a weak pointer so that "conn" is zeroed out
164 * if the connection is destroyed.
166 g_object_add_weak_pointer (G_OBJECT (conn),
169 /* Now repeatedly send the message across the connection
170 * until either it's done, or the connection is closed.
172 while (msg->status != SOUP_MESSAGE_STATUS_FINISHED && conn)
173 soup_connection_send_request (conn, msg);
176 g_object_remove_weak_pointer (G_OBJECT (conn),
180 /* If the message isn't finished, that means we need to
181 * re-send it on a new connection, so loop back to the
184 } while (msg->status != SOUP_MESSAGE_STATUS_FINISHED);
186 return msg->status_code;
190 cancel_message (SoupSession *session, SoupMessage *msg)
192 SoupSessionSync *ss = SOUP_SESSION_SYNC (session);
194 SOUP_SESSION_CLASS (parent_class)->cancel_message (session, msg);
195 g_cond_broadcast (ss->priv->cond);