1 #include <gnutls/gnutls.h>
7 #include <netinet/in.h>
8 #include <sys/socket.h>
10 #include "libsoup/soup-address.h"
11 #include "libsoup/soup-socket.h"
12 #include "libsoup/soup-ssl.h"
18 gnutls_dh_params_t dh_params;
22 /* Read @bufsize bytes into @buf from @session. */
24 server_read (gnutls_session_t session, char *buf, int bufsize)
29 while (total < bufsize) {
30 nread = gnutls_record_recv (session, buf + total,
33 g_error ("server read failed at position %d", total);
38 /* Write @bufsize bytes from @buf to @session, forcing 3 rehandshakes
39 * along the way. (We do an odd number of rehandshakes to make sure
40 * they occur at weird times relative to the client's read buffer
44 server_write (gnutls_session_t session, char *buf, int bufsize)
47 int next_rehandshake = bufsize / 3;
50 while (total < bufsize) {
51 if (total >= next_rehandshake) {
52 if (gnutls_rehandshake (session) < 0)
53 g_error ("client refused rehandshake at position %d", total);
54 if (gnutls_handshake (session) < 0)
55 g_error ("server rehandshake failed at position %d", total);
56 next_rehandshake = MIN (bufsize, next_rehandshake + bufsize / 3);
59 nwrote = gnutls_record_send (session, buf + total,
60 next_rehandshake - total);
62 g_error ("server write failed at position %d: %d", total, nwrote);
67 const char *ssl_cert_file = SRCDIR "/test-cert.pem";
68 const char *ssl_key_file = SRCDIR "/test-key.pem";
71 server_thread (gpointer user_data)
73 int listener = GPOINTER_TO_INT (user_data), client;
74 gnutls_certificate_credentials creds;
75 gnutls_session_t session;
76 struct sockaddr_in sin;
81 gnutls_certificate_allocate_credentials (&creds);
82 if (gnutls_certificate_set_x509_key_file (creds,
83 ssl_cert_file, ssl_key_file,
84 GNUTLS_X509_FMT_PEM) != 0) {
85 g_error ("Failed to set SSL certificate and key files "
86 "(%s, %s).", ssl_cert_file, ssl_key_file);
88 gnutls_certificate_set_dh_params (creds, dh_params);
90 /* Create a new session */
91 gnutls_init (&session, GNUTLS_SERVER);
92 gnutls_set_default_priority (session);
93 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, creds);
94 gnutls_dh_set_prime_bits (session, DH_BITS);
96 /* Wait for client thread to connect */
98 client = accept (listener, (struct sockaddr *) &sin, (void *)&len);
99 gnutls_transport_set_ptr (session, GINT_TO_POINTER (client));
101 /* Initial handshake */
102 status = gnutls_handshake (session);
104 g_error ("initial handshake failed: %d", status);
106 /* Synchronous client test. */
107 server_read (session, buf, BUFSIZE);
108 server_write (session, buf, BUFSIZE);
110 /* Async client test. */
111 server_read (session, buf, BUFSIZE);
112 server_write (session, buf, BUFSIZE);
114 /* That's all, folks. */
115 gnutls_bye (session, GNUTLS_SHUT_WR);
116 gnutls_deinit (session);
118 gnutls_certificate_free_credentials (creds);
123 /* async client code */
126 char writebuf[BUFSIZE], readbuf[BUFSIZE];
131 async_read (SoupSocket *sock, gpointer user_data)
133 AsyncData *data = user_data;
134 SoupSocketIOStatus status;
136 GError *error = NULL;
139 status = soup_socket_read (sock, data->readbuf + data->total,
140 BUFSIZE - data->total, &n,
142 if (status == SOUP_SOCKET_OK)
144 } while (status == SOUP_SOCKET_OK && data->total < BUFSIZE);
146 if (status == SOUP_SOCKET_ERROR || status == SOUP_SOCKET_EOF) {
147 g_error ("Async read got status %d: %s", status,
148 error ? error->message : "(unknown)");
149 } else if (status == SOUP_SOCKET_WOULD_BLOCK)
152 if (memcmp (data->writebuf, data->readbuf, BUFSIZE) != 0)
153 g_error ("Sync read didn't match write");
156 g_main_loop_quit (loop);
160 async_write (SoupSocket *sock, gpointer user_data)
162 AsyncData *data = user_data;
163 SoupSocketIOStatus status;
165 GError *error = NULL;
168 status = soup_socket_write (sock, data->writebuf + data->total,
169 BUFSIZE - data->total, &n,
171 if (status == SOUP_SOCKET_OK)
173 } while (status == SOUP_SOCKET_OK && data->total < BUFSIZE);
175 if (status == SOUP_SOCKET_ERROR || status == SOUP_SOCKET_EOF) {
176 g_error ("Async write got status %d: %s", status,
177 error ? error->message : "(unknown)");
178 } else if (status == SOUP_SOCKET_WOULD_BLOCK)
182 async_read (sock, user_data);
186 start_writing (gpointer user_data)
188 SoupSocket *sock = user_data;
192 data = g_new (AsyncData, 1);
193 for (i = 0; i < BUFSIZE; i++)
194 data->writebuf[i] = i & 0xFF;
197 g_signal_connect (sock, "writable",
198 G_CALLBACK (async_write), data);
199 g_signal_connect (sock, "readable",
200 G_CALLBACK (async_read), data);
202 async_write (sock, data);
209 debug_log (int level, const char *str)
215 main (int argc, char **argv)
217 int opt, listener, sin_len, port, i;
218 struct sockaddr_in sin;
220 char writebuf[BUFSIZE], readbuf[BUFSIZE];
222 SoupSSLCredentials *creds;
225 SoupSocketIOStatus status;
226 GError *error = NULL;
228 g_thread_init (NULL);
231 while ((opt = getopt (argc, argv, "c:d:k:")) != -1) {
234 ssl_cert_file = optarg;
237 debug = atoi (optarg);
240 ssl_key_file = optarg;
244 fprintf (stderr, "Usage: %s [-d debuglevel] [-c ssl-cert-file] [-k ssl-key-file]\n",
251 gnutls_global_set_log_function (debug_log);
252 gnutls_global_set_log_level (debug);
255 /* Create server socket */
256 listener = socket (AF_INET, SOCK_STREAM, 0);
257 if (listener == -1) {
258 perror ("creating listening socket");
262 memset (&sin, 0, sizeof (sin));
263 sin.sin_family = AF_INET;
264 sin.sin_addr.s_addr = INADDR_ANY;
266 if (bind (listener, (struct sockaddr *) &sin, sizeof (sin)) == -1) {
267 perror ("binding listening socket");
271 if (listen (listener, 1) == -1) {
272 perror ("listening on socket");
276 sin_len = sizeof (sin);
277 getsockname (listener, (struct sockaddr *)&sin, (void *)&sin_len);
278 port = ntohs (sin.sin_port);
280 /* Create the client */
281 addr = soup_address_new ("127.0.0.1", port);
282 creds = soup_ssl_get_client_credentials (NULL);
283 sock = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, addr,
284 SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
285 SOUP_SOCKET_SSL_CREDENTIALS, creds,
287 g_object_unref (addr);
288 status = soup_socket_connect_sync (sock, NULL);
289 if (status != SOUP_STATUS_OK) {
290 g_error ("Could not create client socket: %s",
291 soup_status_get_phrase (status));
294 soup_socket_start_ssl (sock, NULL);
296 /* Now spawn server thread */
297 server = g_thread_create (server_thread, GINT_TO_POINTER (listener),
300 /* Synchronous client test */
301 for (i = 0; i < BUFSIZE; i++)
302 writebuf[i] = i & 0xFF;
305 while (total < BUFSIZE) {
306 status = soup_socket_write (sock, writebuf + total,
309 if (status != SOUP_SOCKET_OK)
310 g_error ("Sync write got status %d: %s", status,
311 error ? error->message : "(unknown)");
316 while (total < BUFSIZE) {
317 status = soup_socket_read (sock, readbuf + total,
320 if (status != SOUP_SOCKET_OK)
321 g_error ("Sync read got status %d: %s", status,
322 error ? error->message : "(unknown)");
326 if (memcmp (writebuf, readbuf, BUFSIZE) != 0)
327 g_error ("Sync read didn't match write");
329 printf ("SYNCHRONOUS SSL TEST PASSED\n");
331 /* Switch socket to async and do it again */
334 SOUP_SOCKET_FLAG_NONBLOCKING, TRUE,
337 g_idle_add (start_writing, sock);
338 loop = g_main_loop_new (NULL, TRUE);
339 g_main_loop_run (loop);
340 g_main_loop_unref (loop);
341 g_main_context_unref (g_main_context_default ());
343 printf ("ASYNCHRONOUS SSL TEST PASSED\n");
345 g_object_unref (sock);
346 soup_ssl_free_client_credentials (creds);
347 g_thread_join (server);