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); }
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); }
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; }
/* 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; }