GTlsDatabase and related objects
[platform/upstream/glib.git] / gio / tests / socket-client.c
1 #include <gio/gio.h>
2 #include <gio/gunixsocketaddress.h>
3 #include <glib.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "gtlsconsoleinteraction.h"
9
10 GMainLoop *loop;
11
12 gboolean verbose = FALSE;
13 gboolean non_blocking = FALSE;
14 gboolean use_udp = FALSE;
15 int cancel_timeout = 0;
16 int read_timeout = 0;
17 gboolean unix_socket = FALSE;
18 gboolean tls = FALSE;
19
20 static GOptionEntry cmd_entries[] = {
21   {"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
22    "Cancel any op after the specified amount of seconds", NULL},
23   {"udp", 'u', 0, G_OPTION_ARG_NONE, &use_udp,
24    "Use udp instead of tcp", NULL},
25   {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
26    "Be verbose", NULL},
27   {"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking,
28    "Enable non-blocking i/o", NULL},
29 #ifdef G_OS_UNIX
30   {"unix", 'U', 0, G_OPTION_ARG_NONE, &unix_socket,
31    "Use a unix socket instead of IP", NULL},
32 #endif
33   {"timeout", 't', 0, G_OPTION_ARG_INT, &read_timeout,
34    "Time out reads after the specified number of seconds", NULL},
35   {"tls", 'T', 0, G_OPTION_ARG_NONE, &tls,
36    "Use TLS (SSL)", NULL},
37   {NULL}
38 };
39
40 #include "socket-common.c"
41
42 static gboolean
43 accept_certificate (GTlsClientConnection *conn, GTlsCertificate *cert,
44                     GTlsCertificateFlags errors, gpointer user_data)
45 {
46   g_print ("Certificate would have been rejected ( ");
47   if (errors & G_TLS_CERTIFICATE_UNKNOWN_CA)
48     g_print ("unknown-ca ");
49   if (errors & G_TLS_CERTIFICATE_BAD_IDENTITY)
50     g_print ("bad-identity ");
51   if (errors & G_TLS_CERTIFICATE_NOT_ACTIVATED)
52     g_print ("not-activated ");
53   if (errors & G_TLS_CERTIFICATE_EXPIRED)
54     g_print ("expired ");
55   if (errors & G_TLS_CERTIFICATE_REVOKED)
56     g_print ("revoked ");
57   if (errors & G_TLS_CERTIFICATE_INSECURE)
58     g_print ("insecure ");
59   g_print (") but accepting anyway.\n");
60
61   return TRUE;
62 }
63
64 static GTlsCertificate *
65 lookup_client_certificate (GTlsClientConnection *conn, GError **error)
66 {
67   GList *l, *accepted;
68   GList *c, *certificates;
69   GTlsDatabase *database;
70   GTlsCertificate *certificate = NULL;
71   GTlsConnection *base;
72
73   accepted = g_tls_client_connection_get_accepted_cas (conn);
74   for (l = accepted; l != NULL; l = g_list_next (l))
75     {
76       base = G_TLS_CONNECTION (conn);
77       database = g_tls_connection_get_database (base);
78       certificates = g_tls_database_lookup_certificates_issued_by (database, l->data,
79                                                                    g_tls_connection_get_interaction (base),
80                                                                    G_TLS_DATABASE_LOOKUP_KEYPAIR,
81                                                                    NULL, error);
82       if (error && *error)
83         break;
84
85       if (certificates)
86           certificate = g_object_ref (certificates->data);
87
88       for (c = certificates; c != NULL; c = g_list_next (c))
89         g_object_unref (c->data);
90       g_list_free (certificates);
91     }
92
93   for (l = accepted; l != NULL; l = g_list_next (l))
94     g_byte_array_unref (l->data);
95   g_list_free (accepted);
96
97   if (certificate == NULL && error && !*error)
98     g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED,
99                          "Server requested a certificate, but could not find relevant certificate in database.");
100   return certificate;
101 }
102
103 static gboolean
104 make_connection (const char *argument, GTlsCertificate *certificate, GCancellable *cancellable,
105                  GSocket **socket, GSocketAddress **address, GIOStream **connection,
106                  GInputStream **istream, GOutputStream **ostream, GError **error)
107 {
108   GSocketType socket_type;
109   GSocketFamily socket_family;
110   GSocketAddressEnumerator *enumerator;
111   GSocketConnectable *connectable;
112   GSocketAddress *src_address;
113   GTlsInteraction *interaction;
114   GError *err = NULL;
115
116   if (use_udp)
117     socket_type = G_SOCKET_TYPE_DATAGRAM;
118   else
119     socket_type = G_SOCKET_TYPE_STREAM;
120
121   if (unix_socket)
122     socket_family = G_SOCKET_FAMILY_UNIX;
123   else
124     socket_family = G_SOCKET_FAMILY_IPV4;
125
126   *socket = g_socket_new (socket_family, socket_type, 0, error);
127   if (*socket == NULL)
128     return FALSE;
129
130   if (read_timeout)
131     g_socket_set_timeout (*socket, read_timeout);
132
133   if (unix_socket)
134     {
135       GSocketAddress *addr;
136
137       addr = socket_address_from_string (argument);
138       if (addr == NULL)
139         {
140           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
141                        "Could not parse '%s' as unix socket name", argument);
142           return FALSE;
143         }
144       connectable = G_SOCKET_CONNECTABLE (addr);
145     }
146   else
147     {
148       connectable = g_network_address_parse (argument, 7777, error);
149       if (connectable == NULL)
150         return FALSE;
151     }
152
153   enumerator = g_socket_connectable_enumerate (connectable);
154   while (TRUE)
155     {
156       *address = g_socket_address_enumerator_next (enumerator, cancellable, error);
157       if (*address == NULL)
158         {
159           if (error == NULL)
160             g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
161                                  "No more addresses to try");
162           return FALSE;
163         }
164
165       if (g_socket_connect (*socket, *address, cancellable, &err))
166         break;
167       g_message ("Connection to %s failed: %s, trying next\n", socket_address_to_string (*address), err->message);
168       g_clear_error (&err);
169
170       g_object_unref (*address);
171     }
172   g_object_unref (enumerator);
173
174   g_print ("Connected to %s\n",
175            socket_address_to_string (*address));
176
177   src_address = g_socket_get_local_address (*socket, error);
178   if (!src_address)
179     {
180       g_prefix_error (error, "Error getting local address: ");
181       return FALSE;
182     }
183
184   g_print ("local address: %s\n",
185            socket_address_to_string (src_address));
186   g_object_unref (src_address);
187
188   if (use_udp)
189     {
190       *connection = NULL;
191       *istream = NULL;
192       *ostream = NULL;
193     }
194   else
195     *connection = G_IO_STREAM (g_socket_connection_factory_create_connection (*socket));
196
197   if (tls)
198     {
199       GIOStream *tls_conn;
200
201       tls_conn = g_tls_client_connection_new (*connection, connectable, error);
202       if (!tls_conn)
203         {
204           g_prefix_error (error, "Could not create TLS connection: ");
205           return FALSE;
206         }
207
208       g_signal_connect (tls_conn, "accept-certificate",
209                         G_CALLBACK (accept_certificate), NULL);
210
211       interaction = g_tls_console_interaction_new ();
212       g_tls_connection_set_interaction (G_TLS_CONNECTION (tls_conn), interaction);
213       g_object_unref (interaction);
214
215       if (certificate)
216         g_tls_connection_set_certificate (G_TLS_CONNECTION (tls_conn), certificate);
217
218       g_object_unref (*connection);
219       *connection = G_IO_STREAM (tls_conn);
220
221       if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
222                                        cancellable, error))
223         {
224           g_prefix_error (error, "Error during TLS handshake: ");
225           return FALSE;
226         }
227     }
228   g_object_unref (connectable);
229
230   if (*connection)
231     {
232       *istream = g_io_stream_get_input_stream (*connection);
233       *ostream = g_io_stream_get_output_stream (*connection);
234     }
235
236   return TRUE;
237 }
238
239 int
240 main (int argc,
241       char *argv[])
242 {
243   GSocket *socket;
244   GSocketAddress *address;
245   GError *error = NULL;
246   GOptionContext *context;
247   GCancellable *cancellable;
248   GIOStream *connection;
249   GInputStream *istream;
250   GOutputStream *ostream;
251   GSocketAddress *src_address;
252   GTlsCertificate *certificate = NULL;
253   gint i;
254
255   g_thread_init (NULL);
256
257   g_type_init ();
258
259   context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff");
260   g_option_context_add_main_entries (context, cmd_entries, NULL);
261   if (!g_option_context_parse (context, &argc, &argv, &error))
262     {
263       g_printerr ("%s: %s\n", argv[0], error->message);
264       return 1;
265     }
266
267   if (argc != 2)
268     {
269       g_printerr ("%s: %s\n", argv[0], "Need to specify hostname / unix socket name");
270       return 1;
271     }
272
273   if (use_udp && tls)
274     {
275       g_printerr ("DTLS (TLS over UDP) is not supported");
276       return 1;
277     }
278
279   if (cancel_timeout)
280     {
281       cancellable = g_cancellable_new ();
282       g_thread_create (cancel_thread, cancellable, FALSE, NULL);
283     }
284   else
285     {
286       cancellable = NULL;
287     }
288
289   loop = g_main_loop_new (NULL, FALSE);
290
291   for (i = 0; i < 2; i++)
292     {
293       if (make_connection (argv[1], certificate, cancellable, &socket, &address,
294                            &connection, &istream, &ostream, &error))
295           break;
296
297       if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED))
298         {
299           g_clear_error (&error);
300           certificate = lookup_client_certificate (G_TLS_CLIENT_CONNECTION (connection), &error);
301           if (certificate != NULL)
302             continue;
303         }
304
305       g_printerr ("%s: %s", argv[0], error->message);
306       return 1;
307     }
308
309   /* TODO: Test non-blocking connect/handshake */
310   if (non_blocking)
311     g_socket_set_blocking (socket, FALSE);
312
313   while (TRUE)
314     {
315       gchar buffer[4096];
316       gssize size;
317       gsize to_send;
318
319       if (fgets (buffer, sizeof buffer, stdin) == NULL)
320         break;
321
322       to_send = strlen (buffer);
323       while (to_send > 0)
324         {
325           if (use_udp)
326             {
327               ensure_socket_condition (socket, G_IO_OUT, cancellable);
328               size = g_socket_send_to (socket, address,
329                                        buffer, to_send,
330                                        cancellable, &error);
331             }
332           else
333             {
334               ensure_connection_condition (connection, G_IO_OUT, cancellable);
335               size = g_output_stream_write (ostream,
336                                             buffer, to_send,
337                                             cancellable, &error);
338             }
339
340           if (size < 0)
341             {
342               if (g_error_matches (error,
343                                    G_IO_ERROR,
344                                    G_IO_ERROR_WOULD_BLOCK))
345                 {
346                   g_print ("socket send would block, handling\n");
347                   g_error_free (error);
348                   error = NULL;
349                   continue;
350                 }
351               else
352                 {
353                   g_printerr ("Error sending to socket: %s\n",
354                               error->message);
355                   return 1;
356                 }
357             }
358
359           g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size);
360
361           if (size == 0)
362             {
363               g_printerr ("Unexpected short write\n");
364               return 1;
365             }
366
367           to_send -= size;
368         }
369
370       if (use_udp)
371         {
372           ensure_socket_condition (socket, G_IO_IN, cancellable);
373           size = g_socket_receive_from (socket, &src_address,
374                                         buffer, sizeof buffer,
375                                         cancellable, &error);
376         }
377       else
378         {
379           ensure_connection_condition (connection, G_IO_IN, cancellable);
380           size = g_input_stream_read (istream,
381                                       buffer, sizeof buffer,
382                                       cancellable, &error);
383         }
384
385       if (size < 0)
386         {
387           g_printerr ("Error receiving from socket: %s\n",
388                       error->message);
389           return 1;
390         }
391
392       if (size == 0)
393         break;
394
395       g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size);
396       if (use_udp)
397         g_print (" from %s", socket_address_to_string (src_address));
398       g_print ("\n");
399
400       if (verbose)
401         g_print ("-------------------------\n"
402                  "%.*s"
403                  "-------------------------\n",
404                  (int)size, buffer);
405
406     }
407
408   g_print ("closing socket\n");
409
410   if (connection)
411     {
412       if (!g_io_stream_close (connection, cancellable, &error))
413         {
414           g_printerr ("Error closing connection: %s\n",
415                       error->message);
416           return 1;
417         }
418       g_object_unref (connection);
419     }
420   else
421     {
422       if (!g_socket_close (socket, &error))
423         {
424           g_printerr ("Error closing master socket: %s\n",
425                       error->message);
426           return 1;
427         }
428     }
429
430   g_object_unref (socket);
431   g_object_unref (address);
432
433   return 0;
434 }