Loading...
Searching...
No Matches
imquic public API

The first thing you must do (and only once) to use the library is initializing it, which you can do with a call to imquic_init. A successful initialization will return 0 , so a negative value being return will indicate something went wrong and the library won't be usable. The only argument it expects is an optional path to a file to use for storing the exchanged crypto secret: this is only needed in case you want to, e.g., use tools like Wireshark to debug the QUIC message exchanges even when encrypted, pretty much as other applications do when using the SSLKEYLOGFILE format. For instance, initializing the stack like this:

        if(imquic_init("/home/lminiero/mykeys.log") < 0) {
                // Oh no!
                exit(1);
        }

will store all crypto secrets for all QUIC sessions in the provided file. Using that file in the "Master-Secret" section of the "Protocols/TLS" section of Wireshark will allow you to see the QUIC exchanges as unencrypted, for debugging purposes.

When you're done with the application, a call to imquic_deinit will take care of the cleanup.

You can configure the logging level of the library with a call to imquic_set_log_level. The logging level can be tweaked dynamically, which means you can make that part configurable in your application, if you so prefer. The library comes with a few macros to allow you to log messages at different debugging levels: IMQUIC_PRINT will always print the message, while IMQUIC_LOG will only show the message if the log level associated to the message is lower or equal to the configured log level. Check debug.h for details.

Versioning information can be obtained with different methods: imquic_get_version returns a synthetic numeric version, that's computed from major, minor and patch version, and ensures that any bump results in a higher number; imquic_get_version_major, imquic_get_version_minor and imquic_get_version_patch, instead, return the individual major, minor and patch version numbers. The version is also available as a string in imquic_get_version_string, which serializes major, minor and patch numbers separating them with a dot (e.g., 0.0.1). A release type of the current version (e.g., "alpha", "dev" or "stable") is provided in imquic_get_version_release. A complete representation of the current version as a string, which serialized version and release separated by a backslash, is instead available in imquic_get_version_string_full (e.g., 0.0.1/alpha). To conclude, the imquic_get_build_time and imquic_get_build_sha functions provide info on the code itself, namely when this specific build of the library was compiled, and which git hash it refers to (which is useful when needing to figure out debugging information).

As far as using the library is concerned, it usually involves going through the following steps:

  1. creating a QUIC server or client;
  2. configuring the callback functions for relevant events;
  3. starting the endpoint (waiting for connections, or initiating one);
  4. when a connection is available, add a reference the connection object, and performing the application logic (e.g., exchanging messages);
  5. programmatically send data, if needed, and/or reacting to incoming one;
  6. when a connection is notified as being closed, remove the previously obtained reference to the connection and, if needed, perform any application level cleanup (taking into account that, for server endpoints, more connections may arrive in the future).

In a nutshell, this summarizes a typical usage of the library, and specifically the one we've used in all of our demo examples. Of course, multiple client and server can be created at the same time, each with their own callback functions if required.

Creating a new QUIC endpoint means either creating a new QUIC server, or a new QUIC client. You can create a new QUIC server using imquic_create_server, while on the other end imquic_create_client will create a client endpoint instead. Both use a variable argument approach to dictate what these endpoints should be like, specifically using a sequence of imquic_config key/value properties started with a IMQUIC_CONFIG_INIT and ended by a IMQUIC_CONFIG_DONE .

Note Well: no matter what ALPN is negotiated, these functions will create a generic QUIC endpoint, where the application level protocol is entirely up to you and to the callbacks/methods that follow. If you want imquic to handle a specific protocol natively for you, it will need to be implemented within the library itself, with different methods to create endpoints and custom callbacks tailored to the functionality of the protocol itself. For an example, check the native support imquic offers for RTP Over QUIC (RoQ) in the Native support for RTP Over QUIC (RoQ) documentation, and Media Over QUIC (MoQ) in the Native support for Media Over QUIC (MoQ) documentation.

Whether you created a client or a server, you'll need to configure some callbacks to receive events (e.g., connections coming and going, or incoming data) before actually starting the endpoint with a call to imquic_start_endpoint.

Once an endpoint is live, the configured callbacks will be triggered on relevant events. A new client connecting to your server, or your client connecting to the server, will trigger a call to the callback function configured in imquic_set_new_connection_cb, with a pointer to the new imquic_connection instance associated to that specific connection. Further events associated to that connection will refer to the same instance, and using that pointer in active calls will allow you to interact with a connection (e.g., to send data, or close a connection). Considering the potentially multithread nature of the library and its use in your application, it's a good idea to increase a reference to the connection with imquic_connection_ref when you're first notified about it.

The imquic_set_stream_incoming_cb and imquic_set_datagram_incoming_cb functions allow you to configure callback functions to be notified about incoming data, on STREAM and DATAGRAM respectively. To send data, you can use imquic_send_on_stream and imquic_send_on_datagram instead. Notice that sending data on a STREAM will only possible if the stack knows about it, which means that either it's a stream your peer created, or one you created yourself with imquic_new_stream_id.

The imquic_set_connection_gone_cb connection notifies you when a connection failed or is not available anymore: this can happens when the the server is unreachable, the peer closed it remotely, an error occurred within the library (e.g., a protocol violation in the communication), or you programmatically closed the connection with a call to imquic_close_connection. If you increased the reference to the connection when first notified about it, you should decrease it when you don't need it anymore, and the connection gone callback function is a good place to do that, since the library won't notify you about that connection anymore after that. Of course you must not remove the reference if you didn't increase it in the first place, e.g., if the connection was never established and so this callback was invoked to notify you that the connection failed.