From d10756f1974af1d502a3cb01d92c5fdb62576f0e Mon Sep 17 00:00:00 2001 From: defanor Date: Sun, 23 Aug 2020 21:28:14 +0300 Subject: Comment examples/basic.c and include it into the manual --- examples/basic.c | 68 +++++++++++++++++++++++++++++++++++++++++--------------- rexmpp.texi | 5 +++++ 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/examples/basic.c b/examples/basic.c index cbc9f4f..88a1ca4 100644 --- a/examples/basic.c +++ b/examples/basic.c @@ -4,9 +4,10 @@ #include #include #include - #include +/* A logger callback. This one just prints all the logs into + stderr. */ void my_logger (rexmpp_t *s, int priority, const char *fmt, va_list args) { char *priority_str = "unknown"; switch (priority) { @@ -24,6 +25,9 @@ void my_logger (rexmpp_t *s, int priority, const char *fmt, va_list args) { fprintf(stderr, "\n"); } +/* A SASL property callback, used to retrieve credentials. This one + just asks user for a password and provides AUTHID based on the + initial JID. */ int my_sasl_property_cb (rexmpp_t *s, Gsasl_property prop) { if (prop == GSASL_PASSWORD) { char buf[4096]; @@ -48,6 +52,7 @@ int my_sasl_property_cb (rexmpp_t *s, Gsasl_property prop) { return GSASL_NO_CALLBACK; } +/* An XML in callback, printing what was received. */ int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) { char *xml_buf = rexmpp_xml_serialize(node); printf("recv: %s\n", xml_buf); @@ -55,6 +60,7 @@ int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) { return 0; } +/* An XML out callback, printing what is about to be sent. */ int my_xml_out_cb (rexmpp_t *s, xmlNodePtr node) { char *xml_buf = rexmpp_xml_serialize(node); printf("send: %s\n", xml_buf); @@ -63,43 +69,57 @@ int my_xml_out_cb (rexmpp_t *s, xmlNodePtr node) { } main (int argc, char **argv) { - rexmpp_t s; - rexmpp_err_t err; if (argc != 2) { printf("Usage: %s ", argv[0]); return -1; } + /* The minimal initialisation: provide an allocated rexmpp_t + structure and an initial jid. */ + rexmpp_t s; + rexmpp_err_t err; err = rexmpp_init(&s, argv[1]); + if (err != REXMPP_SUCCESS) { + puts("Failed to initialise rexmpp."); + return -1; + } + + /* Set the primary callback functions: for logging, SASL, XML in and + out. */ s.log_function = my_logger; s.sasl_property_cb = my_sasl_property_cb; s.xml_in_cb = my_xml_in_cb; s.xml_out_cb = my_xml_out_cb; - if (err != REXMPP_SUCCESS) { - puts("error"); - return -1; - } + + /* Could set a client certificate for SASL EXTERNAL authentication + here. */ /* gnutls_certificate_set_x509_key_file(s.gnutls_cred, */ /* "cert.pem", */ /* "key.pem", */ /* GNUTLS_X509_FMT_PEM); */ - fd_set read_fds, write_fds; - int nfds; - struct timeval tv; - struct timeval *mtv; - int n = 0; + /* Could also set various other things manually. */ /* s.socks_host = "127.0.0.1"; */ /* s.socks_port = 4321; */ /* s.manual_host = "foo.custom"; */ /* gnutls_certificate_set_x509_trust_file(s.gnutls_cred, */ /* "foo.custom.crt", */ /* GNUTLS_X509_FMT_PEM); */ - s.roster_cache_file = "roster.xml"; + /* Once the main structure is initialised and everything is + sufficiently configured, we are ready to run the main loop and + call rexmpp from it. */ + + fd_set read_fds, write_fds; + int nfds; + struct timeval tv; + struct timeval *mtv; + int n = 0; + do { + /* Check if we have some user input. */ if (n > 0 && FD_ISSET(STDIN_FILENO, &read_fds)) { char input[4097]; ssize_t input_len; @@ -110,6 +130,7 @@ main (int argc, char **argv) { input[input_len - 1] = '\0'; if (strlen(input) != 0) { if (input[0] == '<') { + /* Raw XML input. */ xmlDocPtr doc = xmlReadMemory(input, input_len, "", "utf-8", 0); if (doc != NULL) { xmlNodePtr node = xmlDocGetRootElement(doc); @@ -124,12 +145,10 @@ main (int argc, char **argv) { puts("Failed to read a document"); } } else if (strcmp(input, ".") == 0) { + /* Exit. */ rexmpp_stop(&s); - } else if (strcmp(input, "connerr") == 0) { - close(s.server_socket); - s.server_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - gnutls_transport_set_int(s.gnutls_session, s.server_socket); } else { + /* A test message for a fixed JID. */ xmlNodePtr msg = rexmpp_xml_add_id(&s, xmlNewNode(NULL, "message")); xmlNewProp(msg, "to", "test2@foo.custom"); xmlNewProp(msg, "type", "chat"); @@ -139,6 +158,8 @@ main (int argc, char **argv) { } } } + + /* Run a single rexmpp iteration. */ err = rexmpp_run(&s, &read_fds, &write_fds); if (err == REXMPP_SUCCESS) { puts("done"); @@ -148,6 +169,7 @@ main (int argc, char **argv) { puts("error"); break; } + /* Could inspect the state here. */ /* printf("res %d / conn %d / tls %d / sasl %d / stream %d / carbons %d\n", */ /* s.resolver_state, */ /* s.tcp_state, */ @@ -155,18 +177,28 @@ main (int argc, char **argv) { /* s.sasl_state, */ /* s.stream_state, */ /* s.carbons_state); */ + + /* Ask rexmpp which file descriptors it is interested in, and what + the timeouts should be. */ FD_ZERO(&read_fds); FD_ZERO(&write_fds); - nfds = rexmpp_fds(&s, &read_fds, &write_fds); mtv = rexmpp_timeout(&s, NULL, (struct timeval*)&tv); + /* Add other file descriptors we are interested in, particularly + stdin for user input. */ FD_SET(STDIN_FILENO, &read_fds); + + /* Run select(2) with all those file descriptors and timeouts, + waiting for either user input or some rexmpp event to occur. */ n = select(nfds, &read_fds, &write_fds, NULL, mtv); if (n == -1) { printf("select error: %s\n", strerror(errno)); break; } } while (1); + + /* Deinitialise the rexmpp structure in the end, freeing whatever it + allocated. */ rexmpp_done(&s); } diff --git a/rexmpp.texi b/rexmpp.texi index 5a23721..e92b969 100644 --- a/rexmpp.texi +++ b/rexmpp.texi @@ -21,6 +21,7 @@ @menu * Copying Conditions:: License information. * Introduction:: The basics. +* Examples:: usage examples. @end menu @node Copying Conditions @@ -51,5 +52,9 @@ in relevant standards: the intent is to keep the library flexible and simple, only handling (or assisting with) more complex and routine parts of the protocol. +@node Examples +@chapter Examples +@section A basic example +@verbatiminclude examples/basic.c @bye -- cgit v1.2.3