diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 9f59816..434e444 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -48,6 +48,8 @@ G_DEFINE_TYPE (SoupConnection, soup_connection, G_TYPE_OBJECT)
 
 enum {
 	DISCONNECTED,
+	CHANGED_MESSAGE,
+	DESTROYED,
 	LAST_SIGNAL
 };
 
@@ -63,6 +65,7 @@ enum {
 	PROP_ASYNC_CONTEXT,
 	PROP_TIMEOUT,
 	PROP_IDLE_TIMEOUT,
+	PROP_STATE,
 
 	LAST_PROP
 };
@@ -110,6 +113,8 @@ dispose (GObject *object)
 	SoupConnection *conn = SOUP_CONNECTION (object);
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
+	g_signal_emit (conn, signals[DESTROYED], 0);
+
 	stop_idle_timer (priv);
 	/* Make sure clear_current_request doesn't re-establish the timeout */
 	priv->idle_timeout = 0;
@@ -143,6 +148,25 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
 			      soup_marshal_NONE__NONE,
 			      G_TYPE_NONE, 0);
 
+	signals[DESTROYED] =
+		g_signal_new ("destroyed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__NONE,
+			      G_TYPE_NONE, 0);
+
+	signals[CHANGED_MESSAGE] =
+		g_signal_new ("changed-message",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_MESSAGE);
+
 	/* properties */
 	g_object_class_install_property (
 		object_class, PROP_REMOTE_ADDRESS,
@@ -191,6 +215,13 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
 				   "Connection lifetime when idle",
 				   0, G_MAXUINT, 0,
 				   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (
+		object_class, PROP_STATE,
+		g_param_spec_uint (SOUP_CONNECTION_STATE,
+				   "Connection state",
+				   "Current state of connection",
+				   0, G_MAXUINT, SOUP_CONNECTION_NEW,
+				   G_PARAM_READWRITE));
 }
 
 
@@ -240,6 +271,9 @@ set_property (GObject *object, guint prop_id,
 	case PROP_IDLE_TIMEOUT:
 		priv->idle_timeout = g_value_get_uint (value);
 		break;
+	case PROP_STATE:
+		priv->state = g_value_get_uint (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -274,6 +308,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_IDLE_TIMEOUT:
 		g_value_set_uint (value, priv->idle_timeout);
 		break;
+	case PROP_STATE:
+		g_value_set_uint (value, priv->state);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -330,8 +367,9 @@ clear_current_request (SoupConnection *conn)
 {
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
-	if (priv->state == SOUP_CONNECTION_IN_USE)
+	if (priv->state == SOUP_CONNECTION_IN_USE) {
 		priv->state = SOUP_CONNECTION_IDLE;
+	}
 	start_idle_timer (conn);
 	if (priv->cur_req) {
 		SoupMessage *cur_req = priv->cur_req;
@@ -379,6 +417,7 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
 			  G_CALLBACK (socket_disconnected), data->conn);
 
 	priv->state = SOUP_CONNECTION_IDLE;
+	g_object_notify (G_OBJECT(data->conn), "state");
 	priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
 	start_idle_timer (data->conn);
 
@@ -412,6 +451,7 @@ soup_connection_connect_async (SoupConnection *conn,
 	g_return_if_fail (priv->socket == NULL);
 
 	priv->state = SOUP_CONNECTION_CONNECTING;
+	g_object_notify (G_OBJECT(conn), "state");
 
 	data = g_slice_new (SoupConnectionAsyncConnectData);
 	data->conn = conn;
@@ -447,6 +487,7 @@ soup_connection_connect_sync (SoupConnection *conn)
 	g_return_val_if_fail (priv->socket == NULL, SOUP_STATUS_MALFORMED);
 
 	priv->state = SOUP_CONNECTION_CONNECTING;
+	g_object_notify (G_OBJECT(conn), "state");
 
 	priv->socket =
 		soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
@@ -472,6 +513,7 @@ soup_connection_connect_sync (SoupConnection *conn)
 
 	if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
 		priv->state = SOUP_CONNECTION_IDLE;
+		g_object_notify (G_OBJECT(conn), "state");
 		priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
 		start_idle_timer (conn);
 	} else {
@@ -542,6 +584,7 @@ soup_connection_disconnect (SoupConnection *conn)
 		return;
 
 	priv->state = SOUP_CONNECTION_DISCONNECTED;
+	g_object_notify (G_OBJECT(conn), "state");
 	/* NB: this might cause conn to be destroyed. */
 	g_signal_emit (conn, signals[DISCONNECTED], 0);
 }
@@ -578,13 +621,17 @@ soup_connection_get_state (SoupConnection *conn)
 		pfd.fd = soup_socket_get_fd (priv->socket);
 		pfd.events = G_IO_IN;
 		pfd.revents = 0;
-		if (g_poll (&pfd, 1, 0) == 1)
+		if (g_poll (&pfd, 1, 0) == 1) {
 			priv->state = SOUP_CONNECTION_REMOTE_DISCONNECTED;
+			g_object_notify (G_OBJECT(conn), "state");
+		}
 	}
 #endif
 	if (priv->state == SOUP_CONNECTION_IDLE &&
-	    priv->unused_timeout && priv->unused_timeout < time (NULL))
+	    priv->unused_timeout && priv->unused_timeout < time (NULL)) {
 		priv->state = SOUP_CONNECTION_REMOTE_DISCONNECTED;
+		g_object_notify (G_OBJECT(conn), "state");
+	}
 
 	return priv->state;
 }
@@ -599,6 +646,7 @@ soup_connection_set_state (SoupConnection *conn, SoupConnectionState state)
 	SOUP_CONNECTION_GET_PRIVATE (conn)->state = state;
 	if (state == SOUP_CONNECTION_IDLE)
 		clear_current_request (conn);
+	g_object_notify (G_OBJECT(conn), "state");
 }
 
 /**
@@ -619,8 +667,11 @@ soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 	g_return_if_fail (priv->state != SOUP_CONNECTION_NEW && priv->state != SOUP_CONNECTION_DISCONNECTED);
 
-	if (req != priv->cur_req)
+	if (req != priv->cur_req) {
 		set_current_request (priv, req);
+		g_signal_emit (conn, signals[CHANGED_MESSAGE], 0, req);
+		g_object_notify (G_OBJECT(conn), "state");
+	}
 	soup_message_send_request (req, priv->socket, conn,
 				   priv->proxy_uri != NULL);
 }
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index aa261d2..279dc7e 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -55,6 +55,7 @@ typedef enum {
 #define SOUP_CONNECTION_ASYNC_CONTEXT   "async-context"
 #define SOUP_CONNECTION_TIMEOUT         "timeout"
 #define SOUP_CONNECTION_IDLE_TIMEOUT    "idle-timeout"
+#define SOUP_CONNECTION_STATE           "state"
 
 SoupConnection *soup_connection_new            (const char       *propname1,
 						...) G_GNUC_NULL_TERMINATED;
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index 731138c..7790e25 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -258,12 +258,14 @@ got_connection (SoupConnection *conn, guint status, gpointer session)
 	if (status == SOUP_STATUS_OK) {
 		tunnel_addr = soup_connection_get_tunnel_addr (conn);
 		if (tunnel_addr) {
+			
 			SoupSessionAsyncTunnelData *data;
 
 			data = g_slice_new (SoupSessionAsyncTunnelData);
 			data->session = session;
 			data->conn = conn;
 			data->item = soup_session_make_connect_message (session, tunnel_addr);
+			g_signal_emit_by_name (session, "tunneling", conn);
 			g_signal_connect (data->item->msg, "finished",
 					  G_CALLBACK (tunnel_connected), data);
 			g_signal_connect (data->item->msg, "restarted",
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index eba77e4..4e58400 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -209,6 +209,7 @@ wait_for_connection (SoupMessageQueueItem *item)
 	conn = soup_session_get_connection (session, item, &try_pruning);
 	if (conn) {
 		if (soup_connection_get_state (conn) == SOUP_CONNECTION_NEW) {
+			g_signal_emit_by_name (session, "connecting", msg);
 			status = soup_connection_connect_sync (conn);
 
 			if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
old mode 100644
new mode 100755
index 8fb28ec..ee6de4c
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -123,6 +123,14 @@ enum {
 	REQUEST_STARTED,
 	REQUEST_UNQUEUED,
 	AUTHENTICATE,
+	CONNECTION_CREATED,
+	CONNECTION_IDLE,
+	CONNECTION_CONNECTING,
+	CONNECTION_IN_USE,
+	CONNECTION_DISCONNECTED,
+	CONNECTION_CHANGED_MESSAGE,
+	CONNECTION_DESTROYED,
+	TUNNELING,
 	LAST_SIGNAL
 };
 
@@ -143,6 +151,7 @@ enum {
 	PROP_ADD_FEATURE,
 	PROP_ADD_FEATURE_BY_TYPE,
 	PROP_REMOVE_FEATURE_BY_TYPE,
+	PROP_STATUS,
 
 	LAST_PROP
 };
@@ -380,6 +389,98 @@ soup_session_class_init (SoupSessionClass *session_class)
 			      SOUP_TYPE_AUTH,
 			      G_TYPE_BOOLEAN);
 
+	/**
+	 * SoupSession::connecting:
+	 * @session: the session
+	 * @msg: the #SoupMessage being sent
+	 *
+	 * Emitted when the @session is trying to connect to the server
+	 * before it begins to transmit @msg.
+	 *
+	 * Since: 2.30
+	 **/
+	signals[CONNECTION_CREATED] =
+		g_signal_new ("connection-created",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_CONNECTION);
+
+	signals[CONNECTION_IDLE] =
+		g_signal_new ("connection-idle",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_CONNECTION);
+
+	signals[CONNECTION_CONNECTING] =
+		g_signal_new ("connection-connecting",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_CONNECTION);
+
+	signals[CONNECTION_IN_USE] =
+		g_signal_new ("connection-in-use",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_CONNECTION);
+
+	signals[CONNECTION_DISCONNECTED] =
+		g_signal_new ("connection-disconnected",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_CONNECTION);
+
+	signals[CONNECTION_CHANGED_MESSAGE] =
+		g_signal_new ("connection-changed-message",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+            soup_marshal_NONE__OBJECT_OBJECT,
+			      G_TYPE_NONE, 2,
+			      SOUP_TYPE_CONNECTION,
+			      SOUP_TYPE_MESSAGE);
+
+	signals[CONNECTION_DESTROYED] =
+		g_signal_new ("connection-destroyed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_CONNECTION);
+
+	signals[TUNNELING] =
+		g_signal_new ("tunneling",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      soup_marshal_NONE__OBJECT,
+			      G_TYPE_NONE, 1,
+			      SOUP_TYPE_CONNECTION);
+
+
 	/* properties */
 	/**
 	 * SOUP_SESSION_PROXY_URI:
@@ -611,6 +712,58 @@ soup_session_class_init (SoupSessionClass *session_class)
 				    G_PARAM_READWRITE));
 }
 
+static void
+notify_connection_state_cb (SoupConnection* conn, GParamSpec* pspec, gpointer data)
+{
+	SoupConnectionState st = soup_connection_get_state(conn);
+	SoupSession *session = (SoupSession *)data;;
+
+	g_return_if_fail( SOUP_IS_CONNECTION(conn) );
+	g_return_if_fail( SOUP_IS_SESSION(session) );
+
+	switch (st) {
+		case SOUP_CONNECTION_NEW:
+			/* CONNECTION_CREATED signal should have already been sent */
+			break;
+		case SOUP_CONNECTION_IDLE:
+			g_signal_emit (session, signals[CONNECTION_IDLE], 0, conn);
+			break;
+		case SOUP_CONNECTION_CONNECTING:
+			g_signal_emit (session, signals[CONNECTION_CONNECTING], 0, conn);
+			break;
+		case SOUP_CONNECTION_IN_USE:
+			g_signal_emit (session, signals[CONNECTION_IN_USE], 0, conn);
+			break;
+		case SOUP_CONNECTION_REMOTE_DISCONNECTED:
+		case SOUP_CONNECTION_DISCONNECTED:
+			g_signal_emit (session, signals[CONNECTION_DISCONNECTED], 0, conn);
+			break;
+	}
+}
+
+static void
+connection_changed_message_cb (SoupConnection* conn, SoupMessage* msg, gpointer data)
+{
+		SoupSession *session = (SoupSession *)data;
+
+		g_return_if_fail( SOUP_IS_CONNECTION(conn) );
+		g_return_if_fail( SOUP_IS_SESSION(session) );
+		g_return_if_fail( SOUP_IS_MESSAGE(msg) );
+
+		g_signal_emit (session, signals[CONNECTION_CHANGED_MESSAGE], 0, conn, msg);
+}
+
+static void
+connection_destroyed_cb (SoupConnection* conn, gpointer data)
+{
+	SoupSession *session = (SoupSession *)data;
+
+	g_return_if_fail( SOUP_IS_CONNECTION(conn) );
+	g_return_if_fail( SOUP_IS_SESSION(session) );
+
+	g_signal_emit (session, signals[CONNECTION_DESTROYED], 0, conn);
+}
+
 static gboolean
 safe_str_equal (const char *a, const char *b)
 {
@@ -1204,6 +1357,16 @@ soup_session_get_connection (SoupSession *session,
 			  G_CALLBACK (connection_disconnected),
 			  session);
 
+	g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
+	g_signal_connect (conn, "notify::state",
+			  G_CALLBACK(notify_connection_state_cb), session);
+
+	g_signal_connect (conn, "changed-message",
+			  G_CALLBACK(connection_changed_message_cb), session);
+
+	g_signal_connect (conn, "destroyed",
+			  G_CALLBACK(connection_destroyed_cb), session);
+
 	g_hash_table_insert (priv->conns, conn, host);
 
 	priv->num_conns++;
