ustream-example-client.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <libubox/usock.h>
  5. #include <libubox/uloop.h>
  6. #include "ustream-ssl.h"
  7. static struct uloop_fd fd;
  8. static struct ustream_fd stream, s_input;
  9. static struct ustream_ssl ssl;
  10. static const char *host, *port;
  11. static void *ctx;
  12. static void client_teardown(void)
  13. {
  14. if (s_input.fd.registered)
  15. ustream_free(&s_input.stream);
  16. ustream_free(&ssl.stream);
  17. ustream_free(&stream.stream);
  18. close(stream.fd.fd);
  19. uloop_end();
  20. }
  21. static void client_input_notify_read(struct ustream *s, int bytes)
  22. {
  23. char *buf;
  24. int len;
  25. buf = ustream_get_read_buf(s, &len);
  26. ustream_write(&ssl.stream, buf, len, false);
  27. ustream_consume(s, len);
  28. }
  29. static void client_ssl_notify_read(struct ustream *s, int bytes)
  30. {
  31. char *buf;
  32. int len;
  33. buf = ustream_get_read_buf(s, &len);
  34. fwrite(buf, len, 1, stdout);
  35. fflush(stdout);
  36. ustream_consume(s, len);
  37. }
  38. static void client_ssl_notify_write(struct ustream *s, int bytes)
  39. {
  40. fprintf(stderr, "Wrote %d bytes, pending %d\n", bytes, s->w.data_bytes);
  41. }
  42. static void client_notify_connected(struct ustream_ssl *ssl)
  43. {
  44. fprintf(stderr, "SSL connection established (CN verified: %d)\n", ssl->valid_cn);
  45. s_input.stream.notify_read = client_input_notify_read;
  46. ustream_fd_init(&s_input, 0);
  47. }
  48. static void client_notify_error(struct ustream_ssl *ssl, int error, const char *str)
  49. {
  50. fprintf(stderr, "SSL connection error(%d): %s\n", error, str);
  51. client_teardown();
  52. }
  53. static void client_notify_verify_error(struct ustream_ssl *ssl, int error, const char *str)
  54. {
  55. fprintf(stderr, "WARNING: SSL certificate error(%d): %s\n", error, str);
  56. }
  57. static void client_notify_state(struct ustream *us)
  58. {
  59. if (!us->write_error && !us->eof)
  60. return;
  61. fprintf(stderr, "Connection closed\n");
  62. client_teardown();
  63. }
  64. static void example_connect_ssl(int fd)
  65. {
  66. fprintf(stderr, "Starting SSL negotiation\n");
  67. ssl.notify_error = client_notify_error;
  68. ssl.notify_verify_error = client_notify_verify_error;
  69. ssl.notify_connected = client_notify_connected;
  70. ssl.stream.notify_read = client_ssl_notify_read;
  71. ssl.stream.notify_write = client_ssl_notify_write;
  72. ssl.stream.notify_state = client_notify_state;
  73. ustream_fd_init(&stream, fd);
  74. ustream_ssl_init(&ssl, &stream.stream, ctx, false);
  75. ustream_ssl_set_peer_cn(&ssl, host);
  76. }
  77. static void example_connect_cb(struct uloop_fd *f, unsigned int events)
  78. {
  79. if (fd.eof || fd.error) {
  80. fprintf(stderr, "Connection failed\n");
  81. uloop_end();
  82. return;
  83. }
  84. fprintf(stderr, "Connection established\n");
  85. uloop_fd_delete(&fd);
  86. example_connect_ssl(fd.fd);
  87. }
  88. static void connect_client(void)
  89. {
  90. fd.fd = usock(USOCK_TCP | USOCK_NONBLOCK, host, port);
  91. fd.cb = example_connect_cb;
  92. uloop_fd_add(&fd, ULOOP_WRITE | ULOOP_EDGE_TRIGGER);
  93. }
  94. static int usage(const char *progname)
  95. {
  96. fprintf(stderr,
  97. "Usage: %s [options] <hostname> <port>\n"
  98. "Options:\n"
  99. " -c <cert>: Load CA certificates from file <cert>\n"
  100. "\n", progname);
  101. return 1;
  102. }
  103. int main(int argc, char **argv)
  104. {
  105. const char *progname = argv[0];
  106. int ch;
  107. ctx = ustream_ssl_context_new(false);
  108. while ((ch = getopt(argc, argv, "c:")) != -1) {
  109. switch(ch) {
  110. case 'c':
  111. ustream_ssl_context_add_ca_crt_file(ctx, optarg);
  112. break;
  113. default:
  114. return usage(progname);
  115. }
  116. }
  117. argv += optind;
  118. argc -= optind;
  119. if (argc != 2)
  120. return usage(progname);
  121. uloop_init();
  122. host = argv[0];
  123. port = argv[1];
  124. connect_client();
  125. uloop_run();
  126. close(fd.fd);
  127. uloop_done();
  128. return 0;
  129. }