Add GCancellables to GSocket ops
[platform/upstream/glib.git] / gio / tests / socket-client.c
1 #include <gio/gio.h>
2 #include <glib.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 GMainLoop *loop;
8
9 gboolean verbose = FALSE;
10 gboolean non_blocking = FALSE;
11 gboolean use_udp = FALSE;
12 gboolean use_source = FALSE;
13 int cancel_timeout = 0;
14
15 static GOptionEntry cmd_entries[] = {
16   {"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
17    "Cancel any op after the specified amount of seconds", NULL},
18   {"udp", 'u', 0, G_OPTION_ARG_NONE, &use_udp,
19    "Use udp instead of tcp", NULL},
20   {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
21    "Be verbose", NULL},
22   {"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking,
23    "Enable non-blocking i/o", NULL},
24   {"use-source", 's', 0, G_OPTION_ARG_NONE, &use_source,
25    "Use GSource to wait for non-blocking i/o", NULL},
26   {NULL}
27 };
28
29 static char *
30 socket_address_to_string (GSocketAddress *address)
31 {
32   GInetAddress *inet_address;
33   char *str, *res;
34   int port;
35
36   inet_address = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
37   str = g_inet_address_to_string (inet_address);
38   port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
39   res = g_strdup_printf ("%s:%d", str, port);
40   g_free (str);
41   return res;
42 }
43
44 static gboolean
45 source_ready (gpointer data,
46               GIOCondition condition)
47 {
48   g_main_loop_quit (loop);
49   return FALSE;
50 }
51
52 static void
53 ensure_condition (GSocket *socket,
54                   const char *where,
55                   GCancellable *cancellable,
56                   GIOCondition condition)
57 {
58   GError *error = NULL;
59   GSource *source;
60
61   if (!non_blocking)
62     return;
63
64   if (use_source)
65     {
66       source = g_socket_create_source (socket,
67                                        condition,
68                                        cancellable);
69       g_source_set_callback (source,
70                              (GSourceFunc) source_ready,
71                              NULL, NULL);
72       g_source_attach (source, NULL);
73       g_source_unref (source);
74       g_main_loop_run (loop);
75     }
76   else
77     {
78       if (!g_socket_condition_wait (socket, condition, cancellable, &error))
79         {
80           g_printerr ("condition wait error for %s: %s\n",
81                       where,
82                       error->message);
83           exit (1);
84         }
85     }
86 }
87
88 static gpointer
89 cancel_thread (gpointer data)
90 {
91   GCancellable *cancellable = data;
92
93   g_usleep (1000*1000*cancel_timeout);
94   g_print ("Cancelling\n");
95   g_cancellable_cancel (cancellable);
96   return NULL;
97 }
98
99 int
100 main (int argc,
101       char *argv[])
102 {
103   GSocket *socket;
104   GSocketAddress *src_address;
105   GSocketAddress *address;
106   GSocketType socket_type;
107   GError *error = NULL;
108   GOptionContext *context;
109   GCancellable *cancellable;
110   GSocketAddressEnumerator *enumerator;
111   GSocketConnectable *connectable;
112
113   g_thread_init (NULL);
114
115   g_type_init ();
116
117   context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff");
118   g_option_context_add_main_entries (context, cmd_entries, NULL);
119   if (!g_option_context_parse (context, &argc, &argv, &error))
120     {
121       g_printerr ("%s: %s\n", argv[0], error->message);
122       return 1;
123     }
124
125   if (argc != 2)
126     {
127       g_printerr ("%s: %s\n", argv[0], "Need to specify hostname");
128       return 1;
129     }
130
131   if (cancel_timeout)
132     {
133       cancellable = g_cancellable_new ();
134       g_thread_create (cancel_thread, cancellable, FALSE, NULL);
135     }
136   else
137     {
138       cancellable = NULL;
139     }
140
141   loop = g_main_loop_new (NULL, FALSE);
142
143   if (use_udp)
144     socket_type = G_SOCKET_TYPE_DATAGRAM;
145   else
146     socket_type = G_SOCKET_TYPE_STREAM;
147
148   socket = g_socket_new (G_SOCKET_FAMILY_IPV4, socket_type, 0, &error);
149   if (socket == NULL)
150     {
151       g_printerr ("%s: %s\n", argv[0], error->message);
152       return 1;
153     }
154
155   connectable = g_network_address_parse (argv[1], 7777, &error);
156   if (connectable == NULL)
157     {
158       g_printerr ("%s: %s\n", argv[0], error->message);
159       return 1;
160     }
161
162   enumerator = g_socket_connectable_enumerate (connectable);
163   while (TRUE)
164     {
165       address = g_socket_address_enumerator_next (enumerator, cancellable, &error);
166       if (address == NULL)
167         {
168           if (error == NULL)
169             g_printerr ("%s: No more addresses to try\n", argv[0]);
170           else
171             g_printerr ("%s: %s\n", argv[0], error->message);
172           return 1;
173         }
174
175       if (g_socket_connect (socket, address, cancellable, &error))
176         break;
177       g_printerr ("%s: Connection to %s failed: %s, trying next\n", argv[0], socket_address_to_string (address), error->message);
178       g_error_free (error);
179       error = NULL;
180
181       g_object_unref (address);
182     }
183   g_object_unref (enumerator);
184
185   g_print ("Connected to %s\n",
186            socket_address_to_string (address));
187
188   /* TODO: Test non-blocking connect */
189   if (non_blocking)
190     g_socket_set_blocking (socket, FALSE);
191
192   src_address = g_socket_get_local_address (socket, &error);
193   if (!src_address)
194     {
195       g_printerr ("Error getting local address: %s\n",
196                   error->message);
197       return 1;
198     }
199   g_print ("local address: %s\n",
200            socket_address_to_string (src_address));
201   g_object_unref (src_address);
202
203   while (TRUE)
204     {
205       gchar buffer[4096] = { };
206       gssize size;
207       gsize to_send;
208
209       if (fgets (buffer, sizeof buffer, stdin) == NULL)
210         break;
211
212       to_send = strlen (buffer);
213       while (to_send > 0)
214         {
215           ensure_condition (socket, "send", cancellable, G_IO_OUT);
216           if (use_udp)
217             size = g_socket_send_to (socket, address,
218                                      buffer, to_send,
219                                      cancellable, &error);
220           else
221             size = g_socket_send (socket, buffer, to_send,
222                                   cancellable, &error);
223
224           if (size < 0)
225             {
226               if (g_error_matches (error,
227                                    G_IO_ERROR,
228                                    G_IO_ERROR_WOULD_BLOCK))
229                 {
230                   g_print ("socket send would block, handling\n");
231                   g_error_free (error);
232                   error = NULL;
233                   continue;
234                 }
235               else
236                 {
237                   g_printerr ("Error sending to socket: %s\n",
238                               error->message);
239                   return 1;
240                 }
241             }
242
243           g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size);
244
245           if (size == 0)
246             {
247               g_printerr ("Unexpected short write\n");
248               return 1;
249             }
250
251           to_send -= size;
252         }
253
254       ensure_condition (socket, "receive", cancellable, G_IO_IN);
255       if (use_udp)
256         size = g_socket_receive_from (socket, &src_address,
257                                       buffer, sizeof buffer,
258                                       cancellable, &error);
259       else
260         size = g_socket_receive (socket, buffer, sizeof buffer,
261                                  cancellable, &error);
262
263       if (size < 0)
264         {
265           g_printerr ("Error receiving from socket: %s\n",
266                       error->message);
267           return 1;
268         }
269
270       if (size == 0)
271         break;
272
273       g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size);
274       if (use_udp)
275         g_print (" from %s", socket_address_to_string (src_address));
276       g_print ("\n");
277
278       if (verbose)
279         g_print ("-------------------------\n"
280                  "%.*s"
281                  "-------------------------\n",
282                  (int)size, buffer);
283
284     }
285
286   g_print ("closing socket\n");
287
288   if (!g_socket_close (socket, &error))
289     {
290       g_printerr ("Error closing master socket: %s\n",
291                   error->message);
292       return 1;
293     }
294
295   g_object_unref (G_OBJECT (socket));
296
297   return 0;
298 }