Client library

Client library — The client library to implement a milter.

Synopsis

#define             MILTER_CLIENT_ERROR
enum                MilterClientError;
                    MilterClient;
GQuark              milter_client_error_quark           (void);
MilterClient*       milter_client_new                   (void);
gchar*              milter_client_get_default_connection_spec
                                                        (MilterClient *client);
gboolean            milter_client_set_connection_spec   (MilterClient *client,
                                                         const gchar *spec,
                                                         GError **error);
GIOChannel*         milter_client_get_listen_channel    (MilterClient *client);
void                milter_client_set_listen_channel    (MilterClient *client,
                                                         GIOChannel *channel);
void                milter_client_set_listen_backlog    (MilterClient *client,
                                                         gint backlog);
gboolean            milter_client_is_remove_unix_socket_on_create
                                                        (MilterClient *client);
void                milter_client_set_remove_unix_socket_on_create
                                                        (MilterClient *client,
                                                         gboolean remove);
void                milter_client_set_timeout           (MilterClient *client,
                                                         guint timeout);
guint               milter_client_get_unix_socket_mode  (MilterClient *client);
guint               milter_client_get_default_unix_socket_mode
                                                        (MilterClient *client);
void                milter_client_set_default_unix_socket_mode
                                                        (MilterClient *client,
                                                         guint mode);
const gchar*        milter_client_get_unix_socket_group (MilterClient *client);
const gchar*        milter_client_get_default_unix_socket_group
                                                        (MilterClient *client);
void                milter_client_set_default_unix_socket_group
                                                        (MilterClient *client,
                                                         const gchar *group);
gboolean            milter_client_is_remove_unix_socket_on_close
                                                        (MilterClient *client);
gboolean            milter_client_get_default_remove_unix_socket_on_close
                                                        (MilterClient *client);
void                milter_client_set_default_remove_unix_socket_on_close
                                                        (MilterClient *client,
                                                         gboolean remove);
gboolean            milter_client_main                  (MilterClient *client);
void                milter_client_shutdown              (MilterClient *client);

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_main() is mail loop function. You can enter into mail 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.

#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();

    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_main(client);

    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 MilterClientContexts. 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. :-|

Details

MILTER_CLIENT_ERROR

#define MILTER_CLIENT_ERROR           (milter_client_error_quark())

Used to get the GError quark for MilterClient errors.


enum MilterClientError

typedef enum
{
    MILTER_CLIENT_ERROR_RUNNING,
    MILTER_CLIENT_ERROR_UNIX_SOCKET,
    MILTER_CLIENT_ERROR_IO_ERROR
} MilterClientError;

These identify the variable errors that can occur while calling MilterClient functions.

MILTER_CLIENT_ERROR_RUNNING

Indicates main loop has been running.

MILTER_CLIENT_ERROR_UNIX_SOCKET

Indicates UNIX domain socket related error.

MILTER_CLIENT_ERROR_IO_ERROR

Indicates IO related error.

MilterClient

typedef struct {
    GObject object;
} MilterClient;

MilterClient is a front object. It accepts connections from MTA and dispatches it.


milter_client_error_quark ()

GQuark              milter_client_error_quark           (void);

Returns :


milter_client_new ()

MilterClient*       milter_client_new                   (void);

Creates a new client.

Returns :

a new MilterClient object.

milter_client_get_default_connection_spec ()

gchar*              milter_client_get_default_connection_spec
                                                        (MilterClient *client);

Gets the default connection specification. The default connection specification should be freed when no longer needed.

client :

a MilterClient.

Returns :

the copy of default connection specification.

milter_client_set_connection_spec ()

gboolean            milter_client_set_connection_spec   (MilterClient *client,
                                                         const gchar *spec,
                                                         GError **error);

Sets a connection specification. If spec is invalid format and error is not NULL, error detail is stored into error.

client :

a MilterClient.

spec :

a connection specification like inet:10025.

error :

return location for an error, or NULL.

Returns :

TRUE on success.

milter_client_get_listen_channel ()

GIOChannel*         milter_client_get_listen_channel    (MilterClient *client);

Gets the channel for listening connection.

client :

a MilterClient.

Returns :

the listen channel.

milter_client_set_listen_channel ()

void                milter_client_set_listen_channel    (MilterClient *client,
                                                         GIOChannel *channel);

Sets a channel for listening connection.

client :

a MilterClient.

channel :

a channel for listening connection.

milter_client_set_listen_backlog ()

void                milter_client_set_listen_backlog    (MilterClient *client,
                                                         gint backlog);

Sets a backlog for listen(2).

client :

a MilterClient.

backlog :

a backlog for listen(2).

milter_client_is_remove_unix_socket_on_create ()

gboolean            milter_client_is_remove_unix_socket_on_create
                                                        (MilterClient *client);

Gets whether removing UNIX domain socket before new UNIX domain socket is created.

client :

a MilterClient.

Returns :

TRUE if removing UNIX domain socket on create, FALSE otherwise.

milter_client_set_remove_unix_socket_on_create ()

void                milter_client_set_remove_unix_socket_on_create
                                                        (MilterClient *client,
                                                         gboolean remove);

Sets whether removing UNIX domain socket before new UNIX domain socket is created.

client :

a MilterClient.

remove :

TRUE if removing UNIX domain socket before new UNIX domain socket is create.

milter_client_set_timeout ()

void                milter_client_set_timeout           (MilterClient *client,
                                                         guint timeout);

Sets the timeout value for established MilterClientContext.

client :

a MilterClient.

timeout :

a timeout by seconds.

milter_client_get_unix_socket_mode ()

guint               milter_client_get_unix_socket_mode  (MilterClient *client);

Gets the UNIX domain socket mode.

client :

a MilterClient.

Returns :

the UNIX domain socket mode.

milter_client_get_default_unix_socket_mode ()

guint               milter_client_get_default_unix_socket_mode
                                                        (MilterClient *client);

Gets the default UNIX domain socket mode.

client :

a MilterClient.

Returns :

the default UNIX domain socket mode.

milter_client_set_default_unix_socket_mode ()

void                milter_client_set_default_unix_socket_mode
                                                        (MilterClient *client,
                                                         guint mode);

Sets the default UNIX domain socket mode.

client :

a MilterClient.

mode :

the UNIX domain socket mode.

milter_client_get_unix_socket_group ()

const gchar*        milter_client_get_unix_socket_group (MilterClient *client);

Gets the group of UNIX domain socket.

client :

a MilterClient.

Returns :

the group name for UNIX domain socket.

milter_client_get_default_unix_socket_group ()

const gchar*        milter_client_get_default_unix_socket_group
                                                        (MilterClient *client);

Gets the default group of UNIX domain socket.

client :

a MilterClient.

Returns :

the default group name for UNIX domain socket.

milter_client_set_default_unix_socket_group ()

void                milter_client_set_default_unix_socket_group
                                                        (MilterClient *client,
                                                         const gchar *group);

Sets the default group of UNIX domain socket.

client :

a MilterClient.

group :

the group name.

milter_client_is_remove_unix_socket_on_close ()

gboolean            milter_client_is_remove_unix_socket_on_close
                                                        (MilterClient *client);

Gets whether removing UNIX domain socket after the socket is closed.

client :

a MilterClient.

Returns :

TRUE if removing UNIX domain socket on close, FALSE otherwise.

milter_client_get_default_remove_unix_socket_on_close ()

gboolean            milter_client_get_default_remove_unix_socket_on_close
                                                        (MilterClient *client);

Gets default value whether removing UNIX domain socket after the socket is closed.

client :

a MilterClient.

Returns :

TRUE if removing UNIX domain socket on close, FALSE otherwise.

milter_client_set_default_remove_unix_socket_on_close ()

void                milter_client_set_default_remove_unix_socket_on_close
                                                        (MilterClient *client,
                                                         gboolean remove);

Gets default value whether removing UNIX domain socket after the socket is closed.

client :

a MilterClient.

remove :

TRUE if removing UNIX domain socket after the socket is closed.

milter_client_main ()

gboolean            milter_client_main                  (MilterClient *client);

Starts main loop.

client :

a MilterClient.

Returns :

TRUE if main loop is quitted successfully, FALSE otherwise.

milter_client_shutdown ()

void                milter_client_shutdown              (MilterClient *client);

Shuts main loop down.

client :

a MilterClient.