static void async_write (SoupSocket *sock, gpointer user_data) { AsyncData *data = user_data; SoupSocketIOStatus status; gsize n; GError *error = NULL; do { status = soup_socket_write (sock, data->writebuf + 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 write got status %d: %s", status, error ? error->message : "(unknown)"); } else if (status == SOUP_SOCKET_WOULD_BLOCK) return; data->total = 0; async_read (sock, user_data); }
/* Attempts to write @len bytes from @data. See the note at * read_metadata() for an explanation of the return value. */ static gboolean write_data (SoupMessage *msg, const char *data, guint len, gboolean body) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; SoupSocketIOStatus status; gsize nwrote; GError *error = NULL; SoupBuffer *chunk; const char *start; while (len > io->written) { status = soup_socket_write (io->sock, data + io->written, len - io->written, &nwrote, NULL, &error); switch (status) { case SOUP_SOCKET_EOF: case SOUP_SOCKET_ERROR: io_error (io->sock, msg, error); return FALSE; case SOUP_SOCKET_WOULD_BLOCK: return FALSE; case SOUP_SOCKET_OK: start = data + io->written; io->written += nwrote; if (body) { if (io->write_length) io->write_length -= nwrote; chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY, start, nwrote); SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_wrote_body_data (msg, chunk); soup_buffer_free (chunk); SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE); } break; } } io->written = 0; return TRUE; }
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; }