~ubuntu-branches/ubuntu/trusty/postfix/trusty-proposed

« back to all changes in this revision

Viewing changes to src/util/auto_clnt.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-02-27 09:33:07 UTC
  • Revision ID: james.westby@ubuntu.com-20050227093307-cn789t27ibnlh6tf
Tags: upstream-2.1.5
ImportĀ upstreamĀ versionĀ 2.1.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      auto_clnt 3
 
4
/* SUMMARY
 
5
/*      client endpoint maintenance
 
6
/* SYNOPSIS
 
7
/*      #include <auto_clnt.h>
 
8
/*
 
9
/*      AUTO_CLNT *auto_clnt_create(max_idle, max_ttl, open_action, context)
 
10
/*      int     max_idle;
 
11
/*      int     max_ttl;
 
12
/*      VSTREAM *(open_action)(void *context)
 
13
/*      void    *context;
 
14
/*
 
15
/*      VSTREAM *auto_clnt_access(auto_clnt)
 
16
/*      AUTO_CLNT *auto_clnt;
 
17
/*
 
18
/*      void    auto_clnt_recover(auto_clnt)
 
19
/*      AUTO_CLNT *auto_clnt;
 
20
/*
 
21
/*      void    auto_clnt_free(auto_clnt)
 
22
/*      AUTO_CLNT *auto_clnt;
 
23
/* DESCRIPTION
 
24
/*      This module maintains IPC client endpoints that automatically
 
25
/*      disconnect after a being idle for a configurable amount of time,
 
26
/*      that disconnect after a configurable time to live,
 
27
/*      and that transparently handle most server-initiated disconnects.
 
28
/*
 
29
/*      auto_clnt_create() instantiates a client endpoint.
 
30
/*
 
31
/*      auto_clnt_access() returns an open stream to the service specified
 
32
/*      to auto_clnt_create(). The stream instance may change between calls.
 
33
/*      The result is a null pointer in case of failure.
 
34
/*
 
35
/*      auto_clnt_recover() recovers from a server-initiated disconnect
 
36
/*      that happened in the middle of an I/O operation.
 
37
/*
 
38
/*      auto_clnt_free() destroys of the specified client endpoint.
 
39
/*
 
40
/*      Arguments:
 
41
/* .IP max_idle
 
42
/*      Idle time after which the client disconnects. Specify 0 to disable
 
43
/*      the limit.
 
44
/* .IP max_ttl
 
45
/*      Upper bound on the time that a connection is allowed to persist.
 
46
/*      Specify 0 to disable the limit.
 
47
/* .IP open_action
 
48
/*      Application call-back routine that opens a stream or returns a
 
49
/*      null pointer upon failure. In case of success, the call-back routine
 
50
/*      is expected to set the stream pathname to the server endpoint name.
 
51
/* .IP context
 
52
/*      Application context that is passed to the open_action routine.
 
53
/* DIAGNOSTICS
 
54
/*      Warnings: communication failure. Fatal error: out of memory.
 
55
/* LICENSE
 
56
/* .ad
 
57
/* .fi
 
58
/*      The Secure Mailer license must be distributed with this software.
 
59
/* AUTHOR(S)
 
60
/*      Wietse Venema
 
61
/*      IBM T.J. Watson Research
 
62
/*      P.O. Box 704
 
63
/*      Yorktown Heights, NY 10598, USA
 
64
/*--*/
 
65
 
 
66
/* System library. */
 
67
 
 
68
#include <sys_defs.h>
 
69
 
 
70
/* Utility library. */
 
71
 
 
72
#include <msg.h>
 
73
#include <mymalloc.h>
 
74
#include <vstream.h>
 
75
#include <events.h>
 
76
#include <iostuff.h>
 
77
#include <auto_clnt.h>
 
78
 
 
79
/* Application-specific. */
 
80
 
 
81
 /*
 
82
  * AUTO_CLNT is an opaque structure. None of the access methods can easily
 
83
  * be implemented as a macro, and access is not performance critical anyway.
 
84
  */
 
85
struct AUTO_CLNT {
 
86
    VSTREAM *vstream;                   /* buffered I/O */
 
87
    int     max_idle;                   /* time before client disconnect */
 
88
    int     max_ttl;                    /* time before client disconnect */
 
89
    VSTREAM *(*open_action) (void *);   /* callback */
 
90
    void   *context;                    /* callback context */
 
91
};
 
92
 
 
93
static void auto_clnt_close(AUTO_CLNT *);
 
94
 
 
95
/* auto_clnt_event - server-initiated disconnect or client-side max_idle */
 
96
 
 
97
static void auto_clnt_event(int unused_event, char *context)
 
98
{
 
99
    AUTO_CLNT *auto_clnt = (AUTO_CLNT *) context;
 
100
 
 
101
    /*
 
102
     * Sanity check. This routine causes the stream to be closed, so it
 
103
     * cannot be called when the stream is already closed.
 
104
     */
 
105
    if (auto_clnt->vstream == 0)
 
106
        msg_panic("auto_clnt_event: stream is closed");
 
107
 
 
108
    auto_clnt_close(auto_clnt);
 
109
}
 
110
 
 
111
/* auto_clnt_ttl_event - client-side expiration */
 
112
 
 
113
static void auto_clnt_ttl_event(int event, char *context)
 
114
{
 
115
 
 
116
    /*
 
117
     * XXX This function is needed only because event_request_timer() cannot
 
118
     * distinguish between requests that specify the same call-back routine
 
119
     * and call-back context. The fix is obvious: specify a request ID along
 
120
     * with the call-back routine, but there is too much code that would have
 
121
     * to be changed.
 
122
     * 
 
123
     * XXX Should we be concerned that an overly agressive optimizer will
 
124
     * eliminate this function and replace calls to auto_clnt_ttl_event() by
 
125
     * direct calls to auto_clnt_event()? It should not, because there exists
 
126
     * code that takes the address of both functions.
 
127
     */
 
128
    auto_clnt_event(event, context);
 
129
}
 
130
 
 
131
/* auto_clnt_open - connect to service */
 
132
 
 
133
static void auto_clnt_open(AUTO_CLNT *auto_clnt)
 
134
{
 
135
 
 
136
    /*
 
137
     * Sanity check.
 
138
     */
 
139
    if (auto_clnt->vstream)
 
140
        msg_panic("auto_clnt_open: stream is open");
 
141
 
 
142
    /*
 
143
     * Schedule a read event so that we can clean up when the remote side
 
144
     * disconnects, and schedule a timer event so that we can cleanup an idle
 
145
     * connection. Note that both events are handled by the same routine.
 
146
     * 
 
147
     * Finally, schedule an event to force disconnection even when the
 
148
     * connection is not idle. This is to prevent one client from clinging on
 
149
     * to a server forever.
 
150
     */
 
151
    auto_clnt->vstream =
 
152
        auto_clnt->open_action(auto_clnt->context);
 
153
 
 
154
    if (auto_clnt->vstream != 0) {
 
155
        close_on_exec(vstream_fileno(auto_clnt->vstream), CLOSE_ON_EXEC);
 
156
        event_enable_read(vstream_fileno(auto_clnt->vstream), auto_clnt_event,
 
157
                          (char *) auto_clnt);
 
158
        if (auto_clnt->max_idle > 0)
 
159
            event_request_timer(auto_clnt_event, (char *) auto_clnt,
 
160
                                auto_clnt->max_idle);
 
161
        if (auto_clnt->max_ttl > 0)
 
162
            event_request_timer(auto_clnt_ttl_event, (char *) auto_clnt,
 
163
                                auto_clnt->max_ttl);
 
164
    }
 
165
}
 
166
 
 
167
/* auto_clnt_close - disconnect from service */
 
168
 
 
169
static void auto_clnt_close(AUTO_CLNT *auto_clnt)
 
170
{
 
171
 
 
172
    /*
 
173
     * Sanity check.
 
174
     */
 
175
    if (auto_clnt->vstream == 0)
 
176
        msg_panic("auto_clnt_close: stream is closed");
 
177
 
 
178
    /*
 
179
     * Be sure to disable read and timer events.
 
180
     */
 
181
    if (msg_verbose)
 
182
        msg_info("%s stream disconnect", VSTREAM_PATH(auto_clnt->vstream));
 
183
    event_disable_readwrite(vstream_fileno(auto_clnt->vstream));
 
184
    event_cancel_timer(auto_clnt_event, (char *) auto_clnt);
 
185
    event_cancel_timer(auto_clnt_ttl_event, (char *) auto_clnt);
 
186
    (void) vstream_fclose(auto_clnt->vstream);
 
187
    auto_clnt->vstream = 0;
 
188
}
 
189
 
 
190
/* auto_clnt_recover - recover from server-initiated disconnect */
 
191
 
 
192
void    auto_clnt_recover(AUTO_CLNT *auto_clnt)
 
193
{
 
194
 
 
195
    /*
 
196
     * Clean up. Don't re-connect until the caller needs it.
 
197
     */
 
198
    if (auto_clnt->vstream)
 
199
        auto_clnt_close(auto_clnt);
 
200
}
 
201
 
 
202
/* auto_clnt_access - access a client stream */
 
203
 
 
204
VSTREAM *auto_clnt_access(AUTO_CLNT *auto_clnt)
 
205
{
 
206
 
 
207
    /*
 
208
     * Open a stream or restart the idle timer.
 
209
     * 
 
210
     * Important! Do not restart the TTL timer!
 
211
     */
 
212
    if (auto_clnt->vstream == 0) {
 
213
        auto_clnt_open(auto_clnt);
 
214
    } else {
 
215
        if (auto_clnt->max_idle > 0)
 
216
            event_request_timer(auto_clnt_event, (char *) auto_clnt,
 
217
                                auto_clnt->max_idle);
 
218
    }
 
219
    return (auto_clnt->vstream);
 
220
}
 
221
 
 
222
/* auto_clnt_create - create client stream connection */
 
223
 
 
224
AUTO_CLNT *auto_clnt_create(int max_idle, int max_ttl,
 
225
                       VSTREAM *(*open_action) (void *), void *context)
 
226
{
 
227
    AUTO_CLNT *auto_clnt;
 
228
 
 
229
    /*
 
230
     * Don't open the stream until the caller needs it.
 
231
     */
 
232
    auto_clnt = (AUTO_CLNT *) mymalloc(sizeof(*auto_clnt));
 
233
    auto_clnt->vstream = 0;
 
234
    auto_clnt->max_idle = max_idle;
 
235
    auto_clnt->max_ttl = max_ttl;
 
236
    auto_clnt->open_action = open_action;
 
237
    auto_clnt->context = context;
 
238
    return (auto_clnt);
 
239
}
 
240
 
 
241
/* auto_clnt_free - destroy client stream instance */
 
242
 
 
243
void    auto_clnt_free(AUTO_CLNT *auto_clnt)
 
244
{
 
245
    if (auto_clnt->vstream)
 
246
        auto_clnt_close(auto_clnt);
 
247
    myfree((char *) auto_clnt);
 
248
}