diff --git a/.gitignore b/.gitignore index e3a4fe4..805cc8c 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ tags examples/active examples/basic examples/bot +examples/complex examples/component examples/register examples/roster diff --git a/Makefile.am b/Makefile.am index 4418e04..959e955 100644 --- a/Makefile.am +++ b/Makefile.am @@ -123,6 +123,7 @@ noinst_PROGRAMS = \ examples/active \ examples/basic \ examples/bot \ + examples/complex \ examples/component \ examples/roster \ examples/uuid \ @@ -138,6 +139,9 @@ examples_basic_LDADD = $(STROPHE_LIBS) examples_bot_SOURCES = examples/bot.c examples_bot_CFLAGS = $(STROPHE_FLAGS) examples_bot_LDADD = $(STROPHE_LIBS) +examples_complex_SOURCES = examples/complex.c +examples_complex_CFLAGS = $(STROPHE_FLAGS) +examples_complex_LDADD = $(STROPHE_LIBS) examples_component_SOURCES = examples/component.c examples_component_CFLAGS = $(STROPHE_FLAGS) examples_component_LDADD = $(STROPHE_LIBS) diff --git a/examples/basic.c b/examples/basic.c index 491873b..3e7f9e9 100644 --- a/examples/basic.c +++ b/examples/basic.c @@ -19,20 +19,6 @@ #define KA_TIMEOUT 60 #define KA_INTERVAL 1 -static void print_tlscert(const xmpp_tlscert_t *cert) -{ - const char *name; - size_t n; - for (n = 0; n < (unsigned)XMPP_CERT_ELEMENT_MAX; ++n) { - printf("\t%32s: %s\n", xmpp_tlscert_get_description(n), - xmpp_tlscert_get_string(cert, n)); - } - n = 0; - while ((name = xmpp_tlscert_get_dnsname(cert, n++)) != NULL) - printf("\t%32s: %s\n", "dnsName", name); - printf("PEM:\n%s\n", xmpp_tlscert_get_pem(cert)); -} - /* define a handler for connection events */ static void conn_handler(xmpp_conn_t *conn, xmpp_conn_event_t status, @@ -41,21 +27,12 @@ static void conn_handler(xmpp_conn_t *conn, void *userdata) { xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; - int secured; (void)error; (void)stream_error; if (status == XMPP_CONN_CONNECT) { fprintf(stderr, "DEBUG: connected\n"); - secured = xmpp_conn_is_secured(conn); - fprintf(stderr, "DEBUG: connection is %s.\n", - secured ? "secured" : "NOT secured"); - if (secured) { - xmpp_tlscert_t *cert = xmpp_conn_get_peer_cert(conn); - print_tlscert(cert); - xmpp_tlscert_free(cert); - } xmpp_disconnect(conn); } else { fprintf(stderr, "DEBUG: disconnected\n"); @@ -63,23 +40,6 @@ static void conn_handler(xmpp_conn_t *conn, } } -static int certfail_handler(const xmpp_tlscert_t *cert, - const char *const errormsg) -{ - char read_char[16] = {0}; - printf("Received certificate can't be validated!\n"); - printf("Reason: %s\n", errormsg); - print_tlscert(cert); - printf("Do you agree to connect?\n[y(es)|n(o)]: "); - fflush(stdout); - if (fgets(read_char, sizeof(read_char), stdin) == NULL) { - printf("fgets() failed\n"); - return 0; - } - printf("\n"); - return read_char[0] == 'y' || read_char[0] == 'Y'; -} - static void usage(int exit_code) { fprintf(stderr, @@ -87,20 +47,11 @@ static void usage(int exit_code) "Options:\n" " --jid The JID to use to authenticate.\n" " --pass The password of the JID.\n" - " --tls-cert Path to client certificate.\n" - " --capath Path to an additional CA trust store " - "(directory).\n" - " --cafile Path to an additional CA trust store " - "(single file).\n" - " --tls-key Path to private key.\n\n" " --disable-tls Disable TLS.\n" " --mandatory-tls Deny plaintext connection.\n" " --trust-tls Trust TLS certificate.\n" - " --enable-certfail Enable certfail handler.\n" " --legacy-ssl Use old style SSL.\n" " --legacy-auth Allow legacy authentication.\n" - " --verbose Increase the verbosity level.\n" - " --tcp-keepalive Configure TCP keepalive.\n\n" "Note: --disable-tls conflicts with --mandatory-tls or " "--legacy-ssl\n"); @@ -112,10 +63,8 @@ int main(int argc, char **argv) xmpp_ctx_t *ctx; xmpp_conn_t *conn; xmpp_log_t *log; - char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL, - *capath = NULL, *cafile = NULL; + char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL; long flags = 0; - int tcp_keepalive = 0, verbosity = 0, certfail = 0; int i; unsigned long port = 0; @@ -133,28 +82,14 @@ int main(int argc, char **argv) flags |= XMPP_CONN_FLAG_LEGACY_SSL; else if (strcmp(argv[i], "--legacy-auth") == 0) flags |= XMPP_CONN_FLAG_LEGACY_AUTH; - else if (strcmp(argv[i], "--verbose") == 0) - verbosity++; - else if (strcmp(argv[i], "--tcp-keepalive") == 0) - tcp_keepalive = 1; - else if (strcmp(argv[i], "--enable-certfail") == 0) - certfail = 1; else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc)) jid = argv[i]; else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc)) password = argv[i]; - else if ((strcmp(argv[i], "--tls-cert") == 0) && (++i < argc)) - cert = argv[i]; - else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc)) - key = argv[i]; - else if ((strcmp(argv[i], "--capath") == 0) && (++i < argc)) - capath = argv[i]; - else if ((strcmp(argv[i], "--cafile") == 0) && (++i < argc)) - cafile = argv[i]; else break; } - if ((!jid && (!cert || !key)) || (argc - i) > 2) { + if ((!jid) || (argc - i) > 2) { usage(1); } @@ -175,16 +110,12 @@ int main(int argc, char **argv) log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* create a context */ ctx = xmpp_ctx_new(NULL, log); - xmpp_ctx_set_verbosity(ctx, verbosity); /* create a connection */ conn = xmpp_conn_new(ctx); /* configure connection properties (optional) */ xmpp_conn_set_flags(conn, flags); - /* configure TCP keepalive (optional) */ - if (tcp_keepalive) - xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL); /* setup authentication information */ if (cert && key) { @@ -195,13 +126,6 @@ int main(int argc, char **argv) if (password) xmpp_conn_set_pass(conn, password); - if (certfail) - xmpp_conn_set_certfail_handler(conn, certfail_handler); - if (capath) - xmpp_conn_set_capath(conn, capath); - if (cafile) - xmpp_conn_set_cafile(conn, cafile); - /* initiate connection */ if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { diff --git a/examples/complex.c b/examples/complex.c new file mode 100644 index 0000000..9b8df46 --- /dev/null +++ b/examples/complex.c @@ -0,0 +1,221 @@ +/* complex.c +** libstrophe XMPP client library -- more complex usage example +** +** Copyright (C) 2005-2009 Collecta, Inc. +** +** This software is provided AS-IS with no warranty, either express +** or implied. +** +** This program is dual licensed under the MIT and GPLv3 licenses. +*/ + +#include +#include +#include + +#include + +/* hardcoded TCP keepalive timeout and interval */ +#define KA_TIMEOUT 60 +#define KA_INTERVAL 1 + +static void print_tlscert(const xmpp_tlscert_t *cert) +{ + const char *name; + size_t n; + for (n = 0; n < (unsigned)XMPP_CERT_ELEMENT_MAX; ++n) { + printf("\t%32s: %s\n", xmpp_tlscert_get_description(n), + xmpp_tlscert_get_string(cert, n)); + } + n = 0; + while ((name = xmpp_tlscert_get_dnsname(cert, n++)) != NULL) + printf("\t%32s: %s\n", "dnsName", name); + printf("PEM:\n%s\n", xmpp_tlscert_get_pem(cert)); +} + +/* define a handler for connection events */ +static void conn_handler(xmpp_conn_t *conn, + xmpp_conn_event_t status, + int error, + xmpp_stream_error_t *stream_error, + void *userdata) +{ + xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; + int secured; + + (void)error; + (void)stream_error; + + if (status == XMPP_CONN_CONNECT) { + fprintf(stderr, "DEBUG: connected\n"); + secured = xmpp_conn_is_secured(conn); + fprintf(stderr, "DEBUG: connection is %s.\n", + secured ? "secured" : "NOT secured"); + if (secured) { + xmpp_tlscert_t *cert = xmpp_conn_get_peer_cert(conn); + print_tlscert(cert); + xmpp_tlscert_free(cert); + } + xmpp_disconnect(conn); + } else { + fprintf(stderr, "DEBUG: disconnected\n"); + xmpp_stop(ctx); + } +} + +static int certfail_handler(const xmpp_tlscert_t *cert, + const char *const errormsg) +{ + char read_char[16] = {0}; + printf("Received certificate can't be validated!\n"); + printf("Reason: %s\n", errormsg); + print_tlscert(cert); + printf("Do you agree to connect?\n[y(es)|n(o)]: "); + fflush(stdout); + if (fgets(read_char, sizeof(read_char), stdin) == NULL) { + printf("fgets() failed\n"); + return 0; + } + printf("\n"); + return read_char[0] == 'y' || read_char[0] == 'Y'; +} + +static void usage(int exit_code) +{ + fprintf(stderr, + "Usage: basic [options] [ []]\n\n" + "Options:\n" + " --jid The JID to use to authenticate.\n" + " --pass The password of the JID.\n" + " --tls-cert Path to client certificate.\n" + " --tls-key Path to private key.\n\n" + " --capath Path to an additional CA trust store " + "(directory).\n" + " --cafile Path to an additional CA trust store " + "(single file).\n" + " --disable-tls Disable TLS.\n" + " --mandatory-tls Deny plaintext connection.\n" + " --trust-tls Trust TLS certificate.\n" + " --enable-certfail Enable certfail handler.\n" + " --legacy-ssl Use old style SSL.\n" + " --legacy-auth Allow legacy authentication.\n" + " --verbose Increase the verbosity level.\n" + " --tcp-keepalive Configure TCP keepalive.\n\n" + "Note: --disable-tls conflicts with --mandatory-tls or " + "--legacy-ssl\n"); + + exit(exit_code); +} + +int main(int argc, char **argv) +{ + xmpp_ctx_t *ctx; + xmpp_conn_t *conn; + xmpp_log_t *log; + char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL, + *capath = NULL, *cafile = NULL; + long flags = 0; + int tcp_keepalive = 0, verbosity = 0, certfail = 0; + int i; + unsigned long port = 0; + + /* take a jid and password on the command line */ + for (i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--help") == 0) + usage(0); + else if (strcmp(argv[i], "--disable-tls") == 0) + flags |= XMPP_CONN_FLAG_DISABLE_TLS; + else if (strcmp(argv[i], "--mandatory-tls") == 0) + flags |= XMPP_CONN_FLAG_MANDATORY_TLS; + else if (strcmp(argv[i], "--trust-tls") == 0) + flags |= XMPP_CONN_FLAG_TRUST_TLS; + else if (strcmp(argv[i], "--legacy-ssl") == 0) + flags |= XMPP_CONN_FLAG_LEGACY_SSL; + else if (strcmp(argv[i], "--legacy-auth") == 0) + flags |= XMPP_CONN_FLAG_LEGACY_AUTH; + else if (strcmp(argv[i], "--verbose") == 0) + verbosity++; + else if (strcmp(argv[i], "--tcp-keepalive") == 0) + tcp_keepalive = 1; + else if (strcmp(argv[i], "--enable-certfail") == 0) + certfail = 1; + else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc)) + jid = argv[i]; + else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc)) + password = argv[i]; + else if ((strcmp(argv[i], "--tls-cert") == 0) && (++i < argc)) + cert = argv[i]; + else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc)) + key = argv[i]; + else if ((strcmp(argv[i], "--capath") == 0) && (++i < argc)) + capath = argv[i]; + else if ((strcmp(argv[i], "--cafile") == 0) && (++i < argc)) + cafile = argv[i]; + else + break; + } + if ((!jid && (!cert || !key)) || (argc - i) > 2) { + usage(1); + } + + if (i < argc) + host = argv[i]; + if (i + 1 < argc) + port = strtoul(argv[i + 1], NULL, 0); + + /* + * Note, this example doesn't handle errors. Applications should check + * return values of non-void functions. + */ + + /* init library */ + xmpp_initialize(); + + /* pass NULL instead to silence output */ + log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); + /* create a context */ + ctx = xmpp_ctx_new(NULL, log); + xmpp_ctx_set_verbosity(ctx, verbosity); + + /* create a connection */ + conn = xmpp_conn_new(ctx); + + /* configure connection properties (optional) */ + xmpp_conn_set_flags(conn, flags); + /* configure TCP keepalive (optional) */ + if (tcp_keepalive) + xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL); + + /* setup authentication information */ + if (cert && key) { + xmpp_conn_set_client_cert(conn, cert, key); + } + if (jid) + xmpp_conn_set_jid(conn, jid); + if (password) + xmpp_conn_set_pass(conn, password); + + if (certfail) + xmpp_conn_set_certfail_handler(conn, certfail_handler); + if (capath) + xmpp_conn_set_capath(conn, capath); + if (cafile) + xmpp_conn_set_cafile(conn, cafile); + + /* initiate connection */ + if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { + + /* enter the event loop - + our connect handler will trigger an exit */ + xmpp_run(ctx); + } + + /* release our connection and context */ + xmpp_conn_release(conn); + xmpp_ctx_free(ctx); + + /* final shutdown of the library */ + xmpp_shutdown(); + + return 0; +}