PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/gio/tests/socket-client.c

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