## Client library

Client library — The client library to implement a milter.

## Functions

void | milter_client_init ()
void | milter_client_quit ()
GOptionGroup * | milter_client_get_option_group ()

## Description

The milter-client library provides full milter protocol processing features on client-side. "client-side" means milter-side not MTA-side.

`MilterClient` and `MilterClientContext` is the main classes in the milter-client library. `MilterClient` accepts n-connections from MTA and each connection is processed by `MilterClientContext`.

#### Usage overview

You need to set connection spec and connect “connection-established” signal before entering mail loop.

Connection spec is a entry point of `MilterClient` for MTA. It has 'PROTOCOL:INFORMATION' format. For IPv4 socket, 'inet:PORT', 'inet:PORT@HOST' or 'inet:PORT@[ADDRESS]' are valid formats. For IPv6 socket, 'inet6:PORT', 'inet6:PORT@HOST' or 'inet6:PORT@[ADDRESS]' are valid formats. For UNIX domain socket, 'unix:PATH' is a valid format.

`MilterClient` emits “connection-established” signal. `MilterClientContext` setup should be done in the signal. In many cases, you just connect callbacks to the passed `MilterClientContext`. See `MilterClientContext` for available signals.

milter_client_run() is running main loop function. You can enter into main loop after you finish to prepare your `MilterClient`.

Here is an example codes that uses the milter-client library. See also tool/milter-test-client.c. It is an example milter implementation using the milter-client library.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    #include <stdlib.h>
    #include <milter/client.h>

    static void
    cb_connection_established (MilterClient *client,
                               MilterClientContext *context,
                               gpointer user_data)
    {
       connect_to_your_interesting_signals(client, context, user_data);
    }

    int
    main (int argc, char **argv)
    {
        gboolean success;
        const gchar spec[] = "inet:10025@localhost";
        MilterClient *client;
        GError *error = NULL;

        milter_init();
        milter_client_init();

        client = milter_client_new();
        if (!milter_client_set_connection_spec(client, spec, &error)) {
            g_print("%s\n", error->message);
            g_error_free(error);
            return EXIT_FAILURE;
        }
        g_signal_connect(client, "connection-established",
                         G_CALLBACK(cb_connection_established), NULL);
        milter_client_run(client);

        milter_client_quit();
        milter_quit();

        return success ? EXIT_SUCCESS : EXIT_FAILURE;
    }

#### Processing model

The libmilter provided by Sendmail uses a thread for each connection model. But the milter-client library doesn't use it. The milter-client library uses two threads. One thread is for `MilterClient` and other thread is for `MilterClientContext`s. `MilterClient` just accepting connections from MTA and dispatches it in the first thread. Each connection is associated with `MilterClientContext` and they are processed in the second thread. The milter-client library's model is the same model of memcached. (memcached uses libevent as its event loop backend but the milter-client library uses GLib's `GMainLoop` for it.)

The libmilter's model will have more cost to accept a connection rather than the milter-client library's model. Because the libmilter's model creates a thread but the milter-client library just allocate `MilterClientContext`. But in many case, this difference is not bottleneck. :-|

## Functions

### milter_client_init ()

    void
    milter_client_init (void);

Call this function before using any other the milter-client library functions.

### milter_client_quit ()

    void
    milter_client_quit (void);

Call this function after the milter-client library use.

### milter_client_get_option_group ()

    GOptionGroup *
    milter_client_get_option_group (MilterClient *client);

Gets a `GOptionGroup` for the `client` . The option group has common milter client options.

#### Parameters

client | a `MilterClient`. |

#### Returns

a new `GOptionGroup` for `client` .