Esempio n. 1
0
/**
 * soup_session_get_connection:
 * @session: a #SoupSession
 * @item: a #SoupMessageQueueItem
 * @try_pruning: on return, whether or not to try pruning a connection
 * 
 * Tries to find or create a connection for @item; this is an internal
 * method for #SoupSession subclasses.
 *
 * If there is an idle connection to the relevant host available, then
 * that connection will be returned. The connection will be set to
 * %SOUP_CONNECTION_IN_USE, so the caller must call
 * soup_connection_set_state() to set it to %SOUP_CONNECTION_IDLE if
 * it ends up not using the connection right away.
 *
 * If there is no idle connection available, but it is possible to
 * create a new connection, then one will be created and returned
 * (with state %SOUP_CONNECTION_NEW). The caller MUST then call
 * soup_connection_connect_sync() or soup_connection_connect_async()
 * to connect it. If the connection attempt fails, the caller must
 * call soup_session_connection_failed() to tell the session to free
 * the connection.
 *
 * If no connection is available and a new connection cannot be made,
 * soup_session_get_connection() will return %NULL. If @session has
 * the maximum number of open connections open, but does not have the
 * maximum number of per-host connections open to the relevant host,
 * then *@try_pruning will be set to %TRUE. In this case, the caller
 * can call soup_session_try_prune_connection() to close an idle
 * connection, and then try soup_session_get_connection() again. (If
 * calling soup_session_try_prune_connection() wouldn't help, then
 * *@try_pruning is left untouched; it is NOT set to %FALSE.)
 *
 * Return value: a #SoupConnection, or %NULL
 **/
SoupConnection *
soup_session_get_connection (SoupSession *session,
			     SoupMessageQueueItem *item,
			     gboolean *try_pruning)
{
	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
	SoupConnection *conn;
	SoupSessionHost *host;
	SoupAddress *remote_addr, *tunnel_addr;
	SoupSSLCredentials *ssl_creds;
	GSList *conns;
	gboolean has_pending = FALSE;
	SoupURI *uri;

	g_mutex_lock (priv->host_lock);

	host = get_host_for_message (session, item->msg);
	for (conns = host->connections; conns; conns = conns->next) {
		if (soup_connection_get_state (conns->data) == SOUP_CONNECTION_IDLE) {
			soup_connection_set_state (conns->data, SOUP_CONNECTION_IN_USE);
			g_mutex_unlock (priv->host_lock);
			return conns->data;
		} else if (soup_connection_get_state (conns->data) == SOUP_CONNECTION_CONNECTING)
			has_pending = TRUE;
	}

	if (has_pending) {
		/* We've already started one connection to this
		 * address, so don't start another one until it's
		 * done.
		 */
		g_mutex_unlock (priv->host_lock);
		return NULL;
	}

	if (host->num_conns >= priv->max_conns_per_host) {
		g_mutex_unlock (priv->host_lock);
		return NULL;
	}

	if (priv->num_conns >= priv->max_conns) {
		*try_pruning = TRUE;
		g_mutex_unlock (priv->host_lock);
		return NULL;
	}

	if (item->proxy_addr) {
		remote_addr = item->proxy_addr;
		tunnel_addr = NULL;
	} else {
		remote_addr = host->addr;
		tunnel_addr = NULL;
	}

	uri = soup_message_get_uri (item->msg);
	if (uri->scheme == SOUP_URI_SCHEME_HTTPS) {
		if (!priv->ssl_creds)
			priv->ssl_creds = soup_ssl_get_client_credentials (priv->ssl_ca_file);
		ssl_creds = priv->ssl_creds;

		if (item->proxy_addr)
			tunnel_addr = host->addr;
	} else
		ssl_creds = NULL;

	conn = soup_connection_new (
		SOUP_CONNECTION_REMOTE_ADDRESS, remote_addr,
		SOUP_CONNECTION_TUNNEL_ADDRESS, tunnel_addr,
		SOUP_CONNECTION_PROXY_URI, item->proxy_uri,
		SOUP_CONNECTION_SSL_CREDENTIALS, ssl_creds,
		SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
		SOUP_CONNECTION_TIMEOUT, priv->io_timeout,
		SOUP_CONNECTION_IDLE_TIMEOUT, priv->idle_timeout,
		NULL);
	g_signal_connect (conn, "disconnected",
			  G_CALLBACK (connection_disconnected),
			  session);

	g_hash_table_insert (priv->conns, conn, host);

	priv->num_conns++;
	host->num_conns++;
	host->connections = g_slist_prepend (host->connections, conn);

	g_mutex_unlock (priv->host_lock);
	return conn;
}
Esempio n. 2
0
int
main (int argc, char **argv)
{
	int opt, debug = 0, listener, sin_len, port, i;
	struct sockaddr_in sin;
	GThread *server;
	char writebuf[BUFSIZE], readbuf[BUFSIZE];
	SoupAddress *addr;
	SoupSSLCredentials *creds;
	SoupSocket *sock;
	gsize n, total;
	SoupSocketIOStatus status;
	int connect_status;
	GError *error = NULL;

	g_thread_init (NULL);
	g_type_init ();

	/* On Windows, this will call WSAStartup() */
	soup_socket_get_type ();

	while ((opt = getopt (argc, argv, "c:d:k:")) != -1) {
		switch (opt) {
		case 'c':
			ssl_cert_file = optarg;
			break;
		case 'd':
			debug = atoi (optarg);
			break;
		case 'k':
			ssl_key_file = optarg;
			break;

		case '?':
			fprintf (stderr, "Usage: %s [-d debuglevel] [-c ssl-cert-file] [-k ssl-key-file]\n",
				 argv[0]);
			break;
		}
	}

	if (debug) {
		gnutls_global_set_log_function (debug_log);
		gnutls_global_set_log_level (debug);
	}

	/* Create server socket */
	listener = socket (AF_INET, SOCK_STREAM, 0);
	if (listener == -1) {
		SOCKET_PRINT_ERROR ("creating listening socket");
		exit (1);
	}

	memset (&sin, 0, sizeof (sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = ntohl (INADDR_LOOPBACK);

	if (bind (listener, (struct sockaddr *) &sin, sizeof (sin))  == -1) {
		SOCKET_PRINT_ERROR ("binding listening socket");
		exit (1);
	}

	if (listen (listener, 1) == -1) {
		SOCKET_PRINT_ERROR ("listening on socket");
		exit (1);
	}

	sin_len = sizeof (sin);
	getsockname (listener, (struct sockaddr *)&sin, (void *)&sin_len);
	port = ntohs (sin.sin_port);

	/* Create the client */
	addr = soup_address_new ("127.0.0.1", port);
	creds = soup_ssl_get_client_credentials (NULL);
	sock = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, addr,
				SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
				SOUP_SOCKET_SSL_CREDENTIALS, creds,
				NULL);
	g_object_unref (addr);
	connect_status = soup_socket_connect_sync (sock, NULL);
	if (connect_status != SOUP_STATUS_OK) {
		g_error ("Could not create client socket: %s",
			 soup_status_get_phrase (connect_status));
	}

	soup_socket_start_ssl (sock, NULL);

	/* Now spawn server thread */
	server = g_thread_create (server_thread, GINT_TO_POINTER (listener),
				  TRUE, NULL);

	/* Synchronous client test */
	for (i = 0; i < BUFSIZE; i++)
		writebuf[i] = i & 0xFF;

	total = 0;
	while (total < BUFSIZE) {
		status = soup_socket_write (sock, writebuf + total,
					    BUFSIZE - total, &n,
					    NULL, &error);
		if (status != SOUP_SOCKET_OK)
			g_error ("Sync write got status %d: %s", status,
				 error ? error->message : "(unknown)");
		total += n;
	}

	total = 0;
	while (total < BUFSIZE) {
		status = soup_socket_read (sock, readbuf + total,
					   BUFSIZE - total, &n,
					   NULL, &error);
		if (status != SOUP_SOCKET_OK)
			g_error ("Sync read got status %d: %s", status,
				 error ? error->message : "(unknown)");
		total += n;
	}

	if (memcmp (writebuf, readbuf, BUFSIZE) != 0)
		g_error ("Sync read didn't match write");

	printf ("SYNCHRONOUS SSL TEST PASSED\n");

	/* Switch socket to async and do it again */

	g_object_set (sock,
		      SOUP_SOCKET_FLAG_NONBLOCKING, TRUE,
		      NULL);

	g_idle_add (start_writing, sock);
	loop = g_main_loop_new (NULL, TRUE);
	g_main_loop_run (loop);
	g_main_loop_unref (loop);
	g_main_context_unref (g_main_context_default ());

	printf ("ASYNCHRONOUS SSL TEST PASSED\n");

	g_object_unref (sock);
	soup_ssl_free_client_credentials (creds);
	g_thread_join (server);

	/* Success */
	return 0;
}