#include #include #include #include #include #include "ustream-ssl.h" static struct uloop_fd fd; static struct ustream_fd stream, s_input; static struct ustream_ssl ssl; static const char *host, *port; static void *ctx; static void client_teardown(void) { if (s_input.fd.registered) ustream_free(&s_input.stream); ustream_free(&ssl.stream); ustream_free(&stream.stream); close(stream.fd.fd); uloop_end(); } static void client_input_notify_read(struct ustream *s, int bytes) { char *buf; int len; buf = ustream_get_read_buf(s, &len); ustream_write(&ssl.stream, buf, len, false); ustream_consume(s, len); } static void client_ssl_notify_read(struct ustream *s, int bytes) { char *buf; int len; buf = ustream_get_read_buf(s, &len); fwrite(buf, len, 1, stdout); fflush(stdout); ustream_consume(s, len); } static void client_ssl_notify_write(struct ustream *s, int bytes) { fprintf(stderr, "Wrote %d bytes, pending %d\n", bytes, s->w.data_bytes); } static void client_notify_connected(struct ustream_ssl *ssl) { fprintf(stderr, "SSL connection established (CN verified: %d)\n", ssl->valid_cn); s_input.stream.notify_read = client_input_notify_read; ustream_fd_init(&s_input, 0); } static void client_notify_error(struct ustream_ssl *ssl, int error, const char *str) { fprintf(stderr, "SSL connection error(%d): %s\n", error, str); client_teardown(); } static void client_notify_verify_error(struct ustream_ssl *ssl, int error, const char *str) { fprintf(stderr, "WARNING: SSL certificate error(%d): %s\n", error, str); } static void client_notify_state(struct ustream *us) { if (!us->write_error && !us->eof) return; fprintf(stderr, "Connection closed\n"); client_teardown(); } static void example_connect_ssl(int fd) { fprintf(stderr, "Starting SSL negotiation\n"); ssl.notify_error = client_notify_error; ssl.notify_verify_error = client_notify_verify_error; ssl.notify_connected = client_notify_connected; ssl.stream.notify_read = client_ssl_notify_read; ssl.stream.notify_write = client_ssl_notify_write; ssl.stream.notify_state = client_notify_state; ustream_fd_init(&stream, fd); ustream_ssl_init(&ssl, &stream.stream, ctx, false); ustream_ssl_set_peer_cn(&ssl, host); } static void example_connect_cb(struct uloop_fd *f, unsigned int events) { if (fd.eof || fd.error) { fprintf(stderr, "Connection failed\n"); uloop_end(); return; } fprintf(stderr, "Connection established\n"); uloop_fd_delete(&fd); example_connect_ssl(fd.fd); } static void connect_client(void) { fd.fd = usock(USOCK_TCP | USOCK_NONBLOCK, host, port); fd.cb = example_connect_cb; uloop_fd_add(&fd, ULOOP_WRITE | ULOOP_EDGE_TRIGGER); } static int usage(const char *progname) { fprintf(stderr, "Usage: %s [options] \n" "Options:\n" " -c : Load CA certificates from file \n" "\n", progname); return 1; } int main(int argc, char **argv) { const char *progname = argv[0]; int ch; ctx = ustream_ssl_context_new(false); while ((ch = getopt(argc, argv, "c:")) != -1) { switch(ch) { case 'c': ustream_ssl_context_add_ca_crt_file(ctx, optarg); break; default: return usage(progname); } } argv += optind; argc -= optind; if (argc != 2) return usage(progname); uloop_init(); host = argv[0]; port = argv[1]; connect_client(); uloop_run(); close(fd.fd); uloop_done(); return 0; }