Example #1
0
static void
setup_timeout_persistent (SoupServer *server, SoupSocket *sock)
{
	char buf[1];
	gsize nread;

	/* In order for the test to work correctly, we have to
	 * close the connection *after* the client side writes
	 * the request. To ensure that this happens reliably,
	 * regardless of thread scheduling, we:
	 *
	 *   1. Try to read off the socket now, knowing it will
	 *      fail (since the client is waiting for us to
	 *      return a response). This will cause it to
	 *      emit "readable" later.
	 *   2. Connect to the server's request-started signal.
	 *   3. Run an inner main loop from that signal handler
	 *      until the socket emits "readable". (If we don't
	 *      do this then it's possible the client's next
	 *      request would be ready before we returned to
	 *      the main loop, and so the signal would never be
	 *      emitted.)
	 *   4. Close the socket.
	 */

	soup_socket_read (sock, buf, 1, &nread, NULL, NULL);
	g_signal_connect (server, "request-started",
			  G_CALLBACK (timeout_request_started), NULL);
}
Example #2
0
static void
async_read (SoupSocket *sock, gpointer user_data)
{
	AsyncData *data = user_data;
	SoupSocketIOStatus status;
	gsize n;
	GError *error = NULL;

	do {
		status = soup_socket_read (sock, data->readbuf + data->total,
					   BUFSIZE - data->total, &n,
					   NULL, &error);
		if (status == SOUP_SOCKET_OK)
			data->total += n;
	} while (status == SOUP_SOCKET_OK && data->total < BUFSIZE);

	if (status == SOUP_SOCKET_ERROR || status == SOUP_SOCKET_EOF) {
		g_error ("Async read got status %d: %s", status,
			 error ? error->message : "(unknown)");
	} else if (status == SOUP_SOCKET_WOULD_BLOCK)
		return;

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

	g_free (data);
	g_main_loop_quit (loop);
}
Example #3
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;
}
Example #4
0
/* Reads as much message body data as is available on io->sock (but no
 * further than the end of the current message body or chunk). On a
 * successful read, emits "got_chunk" (possibly multiple times), and
 * (unless told not to) appends the chunk to io->read_body.
 *
 * See the note at read_metadata() for an explanation of the return
 * value.
 */
static gboolean
read_body_chunk (SoupMessage *msg)
{
	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
	SoupMessageIOData *io = priv->io_data;
	SoupSocketIOStatus status;
	guchar *stack_buf = NULL;
	gsize len;
	gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
	gsize nread;
	GError *error = NULL;
	SoupBuffer *buffer;

	if (!io_handle_sniffing (msg, FALSE))
		return FALSE;

	while (read_to_eof || io->read_length > 0) {
		if (priv->chunk_allocator) {
			buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
			if (!buffer) {
				soup_message_io_pause (msg);
				return FALSE;
			}
		} else {
			if (!stack_buf)
				stack_buf = alloca (RESPONSE_BLOCK_SIZE);
			buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
						  stack_buf,
						  RESPONSE_BLOCK_SIZE);
		}

		if (read_to_eof)
			len = buffer->length;
		else
			len = MIN (buffer->length, io->read_length);

		status = soup_socket_read (io->sock,
					   (guchar *)buffer->data, len,
					   &nread, NULL, &error);

		if (status == SOUP_SOCKET_OK && nread) {
			buffer->length = nread;
			io->read_length -= nread;

			buffer = content_decode (msg, buffer);
			if (!buffer)
				continue;

			soup_message_body_got_chunk (io->read_body, buffer);

			if (io->need_content_sniffed) {
				soup_message_body_append_buffer (io->sniff_data, buffer);
				soup_buffer_free (buffer);
				io->need_got_chunk = TRUE;
				if (!io_handle_sniffing (msg, FALSE))
					return FALSE;
				continue;
			}

			SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
			soup_message_got_chunk (msg, buffer);
			soup_buffer_free (buffer);
			SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
			continue;
		}

		soup_buffer_free (buffer);
		switch (status) {
		case SOUP_SOCKET_OK:
			break;

		case SOUP_SOCKET_EOF:
			if (read_to_eof)
				return TRUE;
			/* else fall through */

		case SOUP_SOCKET_ERROR:
			io_error (io->sock, msg, error);
			return FALSE;

		case SOUP_SOCKET_WOULD_BLOCK:
			return FALSE;
		}
	}

	return TRUE;
}