/** * soup_connection_disconnect: * @conn: a connection * * Disconnects @conn's socket and emits a %disconnected signal. * After calling this, @conn will be essentially useless. **/ void soup_connection_disconnect (SoupConnection *conn) { SoupConnectionPrivate *priv; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); if (!priv->socket) return; g_signal_handlers_disconnect_by_func (priv->socket, socket_disconnected, conn); soup_socket_disconnect (priv->socket); g_object_unref (priv->socket); priv->socket = NULL; /* Don't emit "disconnected" if we aren't yet connected */ if (priv->state < SOUP_CONNECTION_IDLE) return; soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED); /* NB: this might cause conn to be destroyed. */ g_signal_emit (conn, signals[DISCONNECTED], 0); }
SoupSocket * soup_connection_get_socket (SoupConnection *conn) { g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL); return SOUP_CONNECTION_GET_PRIVATE (conn)->socket; }
SoupURI * soup_connection_get_proxy_uri (SoupConnection *conn) { g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL); return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri; }
void soup_connection_set_state (SoupConnection *conn, SoupConnectionState state) { SoupConnectionPrivate *priv; g_return_if_fail (SOUP_IS_CONNECTION (conn)); g_return_if_fail (state >= SOUP_CONNECTION_NEW && state <= SOUP_CONNECTION_DISCONNECTED); g_object_freeze_notify (G_OBJECT (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); if (priv->current_msg) { g_warn_if_fail (state == SOUP_CONNECTION_IDLE || state == SOUP_CONNECTION_DISCONNECTED); clear_current_msg (conn); } if (state == SOUP_CONNECTION_IDLE && !priv->reusable) { /* This will recursively call set_state() */ soup_connection_disconnect (conn); } else { priv->state = state; if (priv->state == SOUP_CONNECTION_IDLE) start_idle_timer (conn); g_object_notify (G_OBJECT (conn), "state"); } g_object_thaw_notify (G_OBJECT (conn)); }
gboolean soup_connection_get_ever_used (SoupConnection *conn) { g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); return SOUP_CONNECTION_GET_PRIVATE (conn)->unused_timeout == 0; }
SoupConnectionState soup_connection_get_state (SoupConnection *conn) { SoupConnectionPrivate *priv; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_CONNECTION_DISCONNECTED); priv = SOUP_CONNECTION_GET_PRIVATE (conn); #ifdef G_OS_UNIX if (priv->state == SOUP_CONNECTION_IDLE) { GPollFD pfd; pfd.fd = soup_socket_get_fd (priv->socket); pfd.events = G_IO_IN; pfd.revents = 0; if (g_poll (&pfd, 1, 0) == 1) soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED); } #endif if (priv->state == SOUP_CONNECTION_IDLE && priv->unused_timeout && priv->unused_timeout < time (NULL)) soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED); return priv->state; }
gboolean soup_connection_is_via_proxy (SoupConnection *conn) { g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri != NULL; }
/** * soup_connection_connect_async: * @conn: the connection * @callback: callback to call when the connection succeeds or fails * @user_data: data for @callback * * Asynchronously connects @conn. **/ void soup_connection_connect_async (SoupConnection *conn, SoupConnectionCallback callback, gpointer user_data) { SoupConnectionAsyncConnectData *data; SoupConnectionPrivate *priv; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); g_return_if_fail (priv->socket == NULL); soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING); data = g_slice_new (SoupConnectionAsyncConnectData); data->conn = conn; data->callback = callback; data->callback_data = user_data; priv->socket = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr, SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds, SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context, SOUP_SOCKET_TIMEOUT, priv->io_timeout, NULL); soup_socket_connect_async (priv->socket, NULL, socket_connect_result, data); }
/** * soup_connection_disconnect: * @conn: a connection * * Disconnects @conn's socket and emits a %disconnected signal. * After calling this, @conn will be essentially useless. **/ void soup_connection_disconnect (SoupConnection *conn) { SoupConnectionPrivate *priv; SoupConnectionState old_state; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); old_state = priv->state; if (old_state != SOUP_CONNECTION_DISCONNECTED) soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED); if (priv->socket) { SoupSocket *socket = priv->socket; g_signal_handlers_disconnect_by_func (socket, G_CALLBACK (re_emit_socket_event), conn); priv->socket = NULL; soup_socket_disconnect (socket); g_object_unref (socket); } if (old_state != SOUP_CONNECTION_DISCONNECTED) g_signal_emit (conn, signals[DISCONNECTED], 0); }
/** * soup_connection_last_used: * @conn: a #SoupConnection. * * Returns the last time a response was received on @conn. * * Return value: the last time a response was received on @conn, or 0 * if @conn has not been used yet. */ time_t soup_connection_last_used (SoupConnection *conn) { g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); return SOUP_CONNECTION_GET_PRIVATE (conn)->last_used; }
SoupConnectionState soup_connection_get_state (SoupConnection *conn) { g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_CONNECTION_DISCONNECTED); return SOUP_CONNECTION_GET_PRIVATE (conn)->state; }
gboolean soup_connection_is_tunnelled (SoupConnection *conn) { SoupConnectionPrivate *priv; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); priv = SOUP_CONNECTION_GET_PRIVATE (conn); return priv->ssl && priv->proxy_uri != NULL; }
SoupAddress * soup_connection_get_tunnel_addr (SoupConnection *conn) { SoupConnectionPrivate *priv; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL); priv = SOUP_CONNECTION_GET_PRIVATE (conn); return priv->tunnel_addr; }
gboolean soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable, GError **error) { SoupConnectionPrivate *priv; SoupAddress *remote_addr; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); priv = SOUP_CONNECTION_GET_PRIVATE (conn); g_return_val_if_fail (priv->socket == NULL, FALSE); soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING); /* Set the protocol to ensure correct proxy resolution. */ remote_addr = g_object_new (SOUP_TYPE_ADDRESS, SOUP_ADDRESS_NAME, priv->remote_uri->host, SOUP_ADDRESS_PORT, priv->remote_uri->port, SOUP_ADDRESS_PROTOCOL, priv->remote_uri->scheme, NULL); priv->socket = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr, SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback, SOUP_SOCKET_SOCKET_PROPERTIES, priv->socket_props, SOUP_SOCKET_FLAG_NONBLOCKING, FALSE, NULL); g_object_unref (remote_addr); g_signal_connect (priv->socket, "event", G_CALLBACK (re_emit_socket_event), conn); if (!soup_socket_connect_sync_internal (priv->socket, cancellable, error)) return FALSE; priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket); if (priv->ssl && !priv->proxy_uri) { if (!soup_socket_handshake_sync (priv->socket, priv->remote_uri->host, cancellable, error)) return FALSE; } if (!priv->ssl || !priv->proxy_uri) { soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL); } soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE); priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT; start_idle_timer (conn); return TRUE; }
void soup_connection_set_state (SoupConnection *conn, SoupConnectionState state) { g_return_if_fail (SOUP_IS_CONNECTION (conn)); g_return_if_fail (state > SOUP_CONNECTION_NEW && state < SOUP_CONNECTION_DISCONNECTED); SOUP_CONNECTION_GET_PRIVATE (conn)->state = state; if (state == SOUP_CONNECTION_IDLE) clear_current_request (conn); }
gboolean soup_connection_start_ssl (SoupConnection *conn) { SoupConnectionPrivate *priv; const char *server_name; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); priv = SOUP_CONNECTION_GET_PRIVATE (conn); server_name = soup_address_get_name (priv->tunnel_addr ? priv->tunnel_addr : priv->remote_addr); return soup_socket_start_proxy_ssl (priv->socket, server_name, NULL); }
/** * soup_connection_connect_sync: * @conn: the connection * * Synchronously connects @conn. * * Return value: the soup status **/ guint soup_connection_connect_sync (SoupConnection *conn) { SoupConnectionPrivate *priv; guint status; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED); priv = SOUP_CONNECTION_GET_PRIVATE (conn); g_return_val_if_fail (priv->socket == NULL, SOUP_STATUS_MALFORMED); soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING); priv->socket = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr, SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds, SOUP_SOCKET_FLAG_NONBLOCKING, FALSE, SOUP_SOCKET_TIMEOUT, priv->io_timeout, NULL); status = soup_socket_connect_sync (priv->socket, NULL); if (!SOUP_STATUS_IS_SUCCESSFUL (status)) goto fail; g_signal_connect (priv->socket, "disconnected", G_CALLBACK (socket_disconnected), conn); if (priv->ssl_creds && !priv->tunnel_addr) { if (!soup_socket_start_ssl (priv->socket, NULL)) { status = SOUP_STATUS_SSL_FAILED; goto fail; } } if (SOUP_STATUS_IS_SUCCESSFUL (status)) { soup_connection_set_state (conn, SOUP_CONNECTION_IDLE); priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT; start_idle_timer (conn); } else { fail: if (priv->socket) { g_object_unref (priv->socket); priv->socket = NULL; } } if (priv->proxy_uri != NULL) status = soup_status_proxify (status); return status; }
/** * soup_connection_send_request: * @conn: a #SoupConnection * @req: a #SoupMessage * * Sends @req on @conn. This is a low-level function, intended for use * by #SoupSession. **/ void soup_connection_send_request (SoupConnection *conn, SoupMessage *req) { SoupConnectionPrivate *priv; g_return_if_fail (SOUP_IS_CONNECTION (conn)); g_return_if_fail (SOUP_IS_MESSAGE (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) set_current_request (conn, req); soup_message_send_request (req, priv->socket, conn, priv->proxy_uri != NULL); }
gboolean soup_connection_start_ssl_sync (SoupConnection *conn, GCancellable *cancellable, GError **error) { SoupConnectionPrivate *priv; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); priv = SOUP_CONNECTION_GET_PRIVATE (conn); if (soup_socket_handshake_sync (priv->socket, priv->remote_uri->host, cancellable, error)) { soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL); return TRUE; } else return FALSE; }
void soup_connection_set_state (SoupConnection *conn, SoupConnectionState state) { SoupConnectionPrivate *priv; SoupConnectionState old_state; g_return_if_fail (SOUP_IS_CONNECTION (conn)); g_return_if_fail (state >= SOUP_CONNECTION_NEW && state <= SOUP_CONNECTION_DISCONNECTED); priv = SOUP_CONNECTION_GET_PRIVATE (conn); old_state = priv->state; priv->state = state; if (state == SOUP_CONNECTION_IDLE && old_state == SOUP_CONNECTION_IN_USE) clear_current_request (conn); g_object_notify (G_OBJECT (conn), "state"); }
SoupConnectionState soup_connection_get_state (SoupConnection *conn) { SoupConnectionPrivate *priv; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_CONNECTION_DISCONNECTED); priv = SOUP_CONNECTION_GET_PRIVATE (conn); if (priv->state == SOUP_CONNECTION_IDLE && (!soup_socket_is_connected (priv->socket) || soup_socket_is_readable (priv->socket))) soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED); if (priv->state == SOUP_CONNECTION_IDLE && priv->unused_timeout && priv->unused_timeout < time (NULL)) soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED); return priv->state; }
void soup_connection_start_ssl_async (SoupConnection *conn, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SoupConnectionPrivate *priv; GTask *task; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); soup_socket_properties_push_async_context (priv->socket_props); task = g_task_new (conn, cancellable, callback, user_data); soup_socket_handshake_async (priv->socket, priv->remote_uri->host, cancellable, start_ssl_completed, task); soup_socket_properties_pop_async_context (priv->socket_props); }
void soup_connection_connect_async (SoupConnection *conn, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SoupConnectionPrivate *priv; SoupAddress *remote_addr; GTask *task; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); g_return_if_fail (priv->socket == NULL); soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING); /* Set the protocol to ensure correct proxy resolution. */ remote_addr = g_object_new (SOUP_TYPE_ADDRESS, SOUP_ADDRESS_NAME, priv->remote_uri->host, SOUP_ADDRESS_PORT, priv->remote_uri->port, SOUP_ADDRESS_PROTOCOL, priv->remote_uri->scheme, NULL); priv->socket = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr, SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback, SOUP_SOCKET_SOCKET_PROPERTIES, priv->socket_props, NULL); g_object_unref (remote_addr); g_signal_connect (priv->socket, "event", G_CALLBACK (re_emit_socket_event), conn); soup_socket_properties_push_async_context (priv->socket_props); task = g_task_new (conn, cancellable, callback, user_data); soup_socket_connect_async_internal (priv->socket, cancellable, socket_connect_complete, task); soup_socket_properties_pop_async_context (priv->socket_props); }
void soup_connection_send_request (SoupConnection *conn, SoupMessageQueueItem *item, SoupMessageCompletionFn completion_cb, gpointer user_data) { SoupConnectionPrivate *priv; g_return_if_fail (SOUP_IS_CONNECTION (conn)); g_return_if_fail (item != NULL); priv = SOUP_CONNECTION_GET_PRIVATE (conn); g_return_if_fail (priv->state != SOUP_CONNECTION_NEW && priv->state != SOUP_CONNECTION_DISCONNECTED); if (item->msg != priv->current_msg) set_current_msg (conn, item->msg); else priv->reusable = FALSE; soup_message_send_request (item, completion_cb, user_data); }
/** * soup_connection_disconnect: * @conn: a connection * * Disconnects @conn's socket and emits a %disconnected signal. * After calling this, @conn will be essentially useless. **/ void soup_connection_disconnect (SoupConnection *conn) { SoupConnectionPrivate *priv; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); if (!priv->socket) return; g_signal_handlers_disconnect_by_func (priv->socket, socket_disconnected, conn); soup_socket_disconnect (priv->socket); g_object_unref (priv->socket); priv->socket = NULL; /* Don't emit "disconnected" if we aren't yet connected */ if (priv->state < SOUP_CONNECTION_IDLE) return; priv->state = SOUP_CONNECTION_DISCONNECTED; if (priv->cur_req && priv->cur_req->status_code == SOUP_STATUS_IO_ERROR && priv->last_used != 0) { /* There was a message queued on this connection, but * the socket was closed while it was being sent. * Since last_used is not 0, then that means at least * one message was successfully sent on this * connection before, and so the most likely cause of * the IO_ERROR is that the connection was idle for * too long and the server timed out and closed it * (and we didn't notice until after we started * sending the message). So we want the message to get * tried again on a new connection. The only code path * that could have gotten us to this point is through * the call to io_cleanup() in * soup_message_io_finished(), and so all we need to * do to get the message requeued in this case is to * change its status. */ soup_message_cleanup_response (priv->cur_req); soup_message_set_io_status (priv->cur_req, SOUP_MESSAGE_IO_STATUS_QUEUED); } /* If cur_req is non-NULL but priv->last_used is 0, then that * means this was the first message to be sent on this * connection, and it failed, so the error probably means that * there's some network or server problem, so we let the * IO_ERROR be returned to the caller. * * (Of course, it's also possible that the error in the * last_used != 0 case was because of a network/server problem * too. It's even possible that the message crashed the * server. In this case, requeuing it was the wrong thing to * do, but presumably, the next attempt will also get an * error, and eventually the message will be requeued onto a * fresh connection and get an error, at which point the error * will finally be returned to the caller.) */ /* NB: this might cause conn to be destroyed. */ g_signal_emit (conn, signals[DISCONNECTED], 0); }