Portability improvements
[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   g_object_unref (connectable);
185
186   g_print ("Connected to %s\n",
187            socket_address_to_string (address));
188
189   /* TODO: Test non-blocking connect */
190   if (non_blocking)
191     g_socket_set_blocking (socket, FALSE);
192
193   src_address = g_socket_get_local_address (socket, &error);
194   if (!src_address)
195     {
196       g_printerr ("Error getting local address: %s\n",
197                   error->message);
198       return 1;
199     }
200   g_print ("local address: %s\n",
201            socket_address_to_string (src_address));
202   g_object_unref (src_address);
203
204   while (TRUE)
205     {
206       gchar buffer[4096] = { };
207       gssize size;
208       gsize to_send;
209
210       if (fgets (buffer, sizeof buffer, stdin) == NULL)
211         break;
212
213       to_send = strlen (buffer);
214       while (to_send > 0)
215         {
216           ensure_condition (socket, "send", cancellable, G_IO_OUT);
217           if (use_udp)
218             size = g_socket_send_to (socket, address,
219                                      buffer, to_send,
220                                      cancellable, &error);
221           else
222             size = g_socket_send (socket, buffer, to_send,
223                                   cancellable, &error);
224
225           if (size < 0)
226             {
227               if (g_error_matches (error,
228                                    G_IO_ERROR,
229                                    G_IO_ERROR_WOULD_BLOCK))
230                 {
231                   g_print ("socket send would block, handling\n");
232                   g_error_free (error);
233                   error = NULL;
234                   continue;
235                 }
236               else
237                 {
238                   g_printerr ("Error sending to socket: %s\n",
239                               error->message);
240                   return 1;
241                 }
242             }
243
244           g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size);
245
246           if (size == 0)
247             {
248               g_printerr ("Unexpected short write\n");
249               return 1;
250             }
251
252           to_send -= size;
253         }
254
255       ensure_condition (socket, "receive", cancellable, G_IO_IN);
256       if (use_udp)
257         size = g_socket_receive_from (socket, &src_address,
258                                       buffer, sizeof buffer,
259                                       cancellable, &error);
260       else
261         size = g_socket_receive (socket, buffer, sizeof buffer,
262                                  cancellable, &error);
263
264       if (size < 0)
265         {
266           g_printerr ("Error receiving from socket: %s\n",
267                       error->message);
268           return 1;
269         }
270
271       if (size == 0)
272         break;
273
274       g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size);
275       if (use_udp)
276         g_print (" from %s", socket_address_to_string (src_address));
277       g_print ("\n");
278
279       if (verbose)
280         g_print ("-------------------------\n"
281                  "%.*s"
282                  "-------------------------\n",
283                  (int)size, buffer);
284
285     }
286
287   g_print ("closing socket\n");
288
289   if (!g_socket_close (socket, &error))
290     {
291       g_printerr ("Error closing master socket: %s\n",
292                   error->message);
293       return 1;
294     }
295
296   g_object_unref (G_OBJECT (socket));
297   g_object_unref (G_OBJECT (address));
298
299   return 0;
300 }