5
/* client endpoint maintenance
7
/* #include <auto_clnt.h>
9
/* AUTO_CLNT *auto_clnt_create(max_idle, max_ttl, open_action, context)
12
/* VSTREAM *(open_action)(void *context)
15
/* VSTREAM *auto_clnt_access(auto_clnt)
16
/* AUTO_CLNT *auto_clnt;
18
/* void auto_clnt_recover(auto_clnt)
19
/* AUTO_CLNT *auto_clnt;
21
/* void auto_clnt_free(auto_clnt)
22
/* AUTO_CLNT *auto_clnt;
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.
29
/* auto_clnt_create() instantiates a client endpoint.
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.
35
/* auto_clnt_recover() recovers from a server-initiated disconnect
36
/* that happened in the middle of an I/O operation.
38
/* auto_clnt_free() destroys of the specified client endpoint.
42
/* Idle time after which the client disconnects. Specify 0 to disable
45
/* Upper bound on the time that a connection is allowed to persist.
46
/* Specify 0 to disable the limit.
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.
52
/* Application context that is passed to the open_action routine.
54
/* Warnings: communication failure. Fatal error: out of memory.
58
/* The Secure Mailer license must be distributed with this software.
61
/* IBM T.J. Watson Research
63
/* Yorktown Heights, NY 10598, USA
70
/* Utility library. */
77
#include <auto_clnt.h>
79
/* Application-specific. */
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.
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 */
93
static void auto_clnt_close(AUTO_CLNT *);
95
/* auto_clnt_event - server-initiated disconnect or client-side max_idle */
97
static void auto_clnt_event(int unused_event, char *context)
99
AUTO_CLNT *auto_clnt = (AUTO_CLNT *) context;
102
* Sanity check. This routine causes the stream to be closed, so it
103
* cannot be called when the stream is already closed.
105
if (auto_clnt->vstream == 0)
106
msg_panic("auto_clnt_event: stream is closed");
108
auto_clnt_close(auto_clnt);
111
/* auto_clnt_ttl_event - client-side expiration */
113
static void auto_clnt_ttl_event(int event, char *context)
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
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.
128
auto_clnt_event(event, context);
131
/* auto_clnt_open - connect to service */
133
static void auto_clnt_open(AUTO_CLNT *auto_clnt)
139
if (auto_clnt->vstream)
140
msg_panic("auto_clnt_open: stream is open");
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.
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.
152
auto_clnt->open_action(auto_clnt->context);
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,
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,
167
/* auto_clnt_close - disconnect from service */
169
static void auto_clnt_close(AUTO_CLNT *auto_clnt)
175
if (auto_clnt->vstream == 0)
176
msg_panic("auto_clnt_close: stream is closed");
179
* Be sure to disable read and timer events.
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;
190
/* auto_clnt_recover - recover from server-initiated disconnect */
192
void auto_clnt_recover(AUTO_CLNT *auto_clnt)
196
* Clean up. Don't re-connect until the caller needs it.
198
if (auto_clnt->vstream)
199
auto_clnt_close(auto_clnt);
202
/* auto_clnt_access - access a client stream */
204
VSTREAM *auto_clnt_access(AUTO_CLNT *auto_clnt)
208
* Open a stream or restart the idle timer.
210
* Important! Do not restart the TTL timer!
212
if (auto_clnt->vstream == 0) {
213
auto_clnt_open(auto_clnt);
215
if (auto_clnt->max_idle > 0)
216
event_request_timer(auto_clnt_event, (char *) auto_clnt,
217
auto_clnt->max_idle);
219
return (auto_clnt->vstream);
222
/* auto_clnt_create - create client stream connection */
224
AUTO_CLNT *auto_clnt_create(int max_idle, int max_ttl,
225
VSTREAM *(*open_action) (void *), void *context)
227
AUTO_CLNT *auto_clnt;
230
* Don't open the stream until the caller needs it.
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;
241
/* auto_clnt_free - destroy client stream instance */
243
void auto_clnt_free(AUTO_CLNT *auto_clnt)
245
if (auto_clnt->vstream)
246
auto_clnt_close(auto_clnt);
247
myfree((char *) auto_clnt);