Postfix3.3.1
clnt_stream.c
[詳解]
1 /*++
2 /* NAME
3 /* clnt_stream 3
4 /* SUMMARY
5 /* client endpoint maintenance
6 /* SYNOPSIS
7 /* #include <clnt_stream.h>
8 /*
9 /* CLNT_STREAM *clnt_stream_create(class, service, timeout, ttl)
10 /* const char *class;
11 /* const char *service;
12 /* int timeout;
13 /* int ttl;
14 /*
15 /* VSTREAM *clnt_stream_access(clnt_stream)
16 /* CLNT_STREAM *clnt_stream;
17 /*
18 /* void clnt_stream_recover(clnt_stream)
19 /* CLNT_STREAM *clnt_stream;
20 /*
21 /* void clnt_stream_free(clnt_stream)
22 /* CLNT_STREAM *clnt_stream;
23 /* DESCRIPTION
24 /* This module maintains local 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 /* Server disconnect is detected by read-selecting the client endpoint.
29 /* The code assumes that the server has disconnected when the endpoint
30 /* becomes readable.
31 /*
32 /* clnt_stream_create() instantiates a client endpoint.
33 /*
34 /* clnt_stream_access() returns an open stream to the service specified
35 /* to clnt_stream_create(). The stream instance may change between calls.
36 /*
37 /* clnt_stream_recover() recovers from a server-initiated disconnect
38 /* that happened in the middle of an I/O operation.
39 /*
40 /* clnt_stream_free() destroys of the specified client endpoint.
41 /*
42 /* Arguments:
43 /* .IP class
44 /* The service class, private or public.
45 /* .IP service
46 /* The service endpoint name. The name is limited to local IPC
47 /* over sockets or equivalent.
48 /* .IP timeout
49 /* Idle time after which the client disconnects.
50 /* .IP ttl
51 /* Upper bound on the time that a connection is allowed to persist.
52 /* DIAGNOSTICS
53 /* Warnings: communication failure. Fatal error: mail system is down,
54 /* out of memory.
55 /* SEE ALSO
56 /* mail_proto(3h) low-level mail component glue.
57 /* LICENSE
58 /* .ad
59 /* .fi
60 /* The Secure Mailer license must be distributed with this software.
61 /* AUTHOR(S)
62 /* Wietse Venema
63 /* IBM T.J. Watson Research
64 /* P.O. Box 704
65 /* Yorktown Heights, NY 10598, USA
66 /*--*/
67 
68 /* System library. */
69 
70 #include <sys_defs.h>
71 
72 /* Utility library. */
73 
74 #include <msg.h>
75 #include <mymalloc.h>
76 #include <vstream.h>
77 #include <events.h>
78 #include <iostuff.h>
79 
80 /* Global library. */
81 
82 #include "mail_proto.h"
83 #include "mail_params.h"
84 #include "clnt_stream.h"
85 
86 /* Application-specific. */
87 
88  /*
89  * CLNT_STREAM is an opaque structure. None of the access methods can easily
90  * be implemented as a macro, and access is not performance critical anyway.
91  */
92 struct CLNT_STREAM {
93  VSTREAM *vstream; /* buffered I/O */
94  int timeout; /* time before client disconnect */
95  int ttl; /* time before client disconnect */
96  char *class; /* server class */
97  char *service; /* server name */
98 };
99 
100 static void clnt_stream_close(CLNT_STREAM *);
101 
102 /* clnt_stream_event - server-initiated disconnect or client-side timeout */
103 
104 static void clnt_stream_event(int unused_event, void *context)
105 {
106  CLNT_STREAM *clnt_stream = (CLNT_STREAM *) context;
107 
108  /*
109  * Sanity check. This routine causes the stream to be closed, so it
110  * cannot be called when the stream is already closed.
111  */
112  if (clnt_stream->vstream == 0)
113  msg_panic("clnt_stream_event: stream is closed");
114 
115  clnt_stream_close(clnt_stream);
116 }
117 
118 /* clnt_stream_ttl_event - client-side expiration */
119 
120 static void clnt_stream_ttl_event(int event, void *context)
121 {
122 
123  /*
124  * XXX This function is needed only because event_request_timer() cannot
125  * distinguish between requests that specify the same call-back routine
126  * and call-back context. The fix is obvious: specify a request ID along
127  * with the call-back routine, but there is too much code that would have
128  * to be changed.
129  *
130  * XXX Should we be concerned that an overly aggressive optimizer will
131  * eliminate this function and replace calls to clnt_stream_ttl_event()
132  * by direct calls to clnt_stream_event()? It should not, because there
133  * exists code that takes the address of both functions.
134  */
135  clnt_stream_event(event, context);
136 }
137 
138 /* clnt_stream_open - connect to service */
139 
140 static void clnt_stream_open(CLNT_STREAM *clnt_stream)
141 {
142 
143  /*
144  * Sanity check.
145  */
146  if (clnt_stream->vstream)
147  msg_panic("clnt_stream_open: stream is open");
148 
149  /*
150  * Schedule a read event so that we can clean up when the remote side
151  * disconnects, and schedule a timer event so that we can cleanup an idle
152  * connection. Note that both events are handled by the same routine.
153  *
154  * Finally, schedule an event to force disconnection even when the
155  * connection is not idle. This is to prevent one client from clinging on
156  * to a server forever.
157  */
158  clnt_stream->vstream = mail_connect_wait(clnt_stream->class,
159  clnt_stream->service);
161  event_enable_read(vstream_fileno(clnt_stream->vstream), clnt_stream_event,
162  (void *) clnt_stream);
163  event_request_timer(clnt_stream_event, (void *) clnt_stream,
164  clnt_stream->timeout);
165  event_request_timer(clnt_stream_ttl_event, (void *) clnt_stream,
166  clnt_stream->ttl);
167 }
168 
169 /* clnt_stream_close - disconnect from service */
170 
171 static void clnt_stream_close(CLNT_STREAM *clnt_stream)
172 {
173 
174  /*
175  * Sanity check.
176  */
177  if (clnt_stream->vstream == 0)
178  msg_panic("clnt_stream_close: stream is closed");
179 
180  /*
181  * Be sure to disable read and timer events.
182  */
183  if (msg_verbose)
184  msg_info("%s stream disconnect", clnt_stream->service);
186  event_cancel_timer(clnt_stream_event, (void *) clnt_stream);
187  event_cancel_timer(clnt_stream_ttl_event, (void *) clnt_stream);
188  (void) vstream_fclose(clnt_stream->vstream);
189  clnt_stream->vstream = 0;
190 }
191 
192 /* clnt_stream_recover - recover from server-initiated disconnect */
193 
195 {
196 
197  /*
198  * Clean up. Don't re-connect until the caller needs it.
199  */
200  if (clnt_stream->vstream)
201  clnt_stream_close(clnt_stream);
202 }
203 
204 /* clnt_stream_access - access a client stream */
205 
207 {
208 
209  /*
210  * Open a stream or restart the idle timer.
211  *
212  * Important! Do not restart the TTL timer!
213  */
214  if (clnt_stream->vstream == 0) {
215  clnt_stream_open(clnt_stream);
216  } else if (readable(vstream_fileno(clnt_stream->vstream))) {
217  clnt_stream_close(clnt_stream);
218  clnt_stream_open(clnt_stream);
219  } else {
220  event_request_timer(clnt_stream_event, (void *) clnt_stream,
221  clnt_stream->timeout);
222  }
223  return (clnt_stream->vstream);
224 }
225 
226 /* clnt_stream_create - create client stream connection */
227 
228 CLNT_STREAM *clnt_stream_create(const char *class, const char *service,
229  int timeout, int ttl)
230 {
231  CLNT_STREAM *clnt_stream;
232 
233  /*
234  * Don't open the stream until the caller needs it.
235  */
236  clnt_stream = (CLNT_STREAM *) mymalloc(sizeof(*clnt_stream));
237  clnt_stream->vstream = 0;
238  clnt_stream->timeout = timeout;
239  clnt_stream->ttl = ttl;
240  clnt_stream->class = mystrdup(class);
241  clnt_stream->service = mystrdup(service);
242  return (clnt_stream);
243 }
244 
245 /* clnt_stream_free - destroy client stream instance */
246 
247 void clnt_stream_free(CLNT_STREAM *clnt_stream)
248 {
249  if (clnt_stream->vstream)
250  clnt_stream_close(clnt_stream);
251  myfree(clnt_stream->class);
252  myfree(clnt_stream->service);
253  myfree((void *) clnt_stream);
254 }
int msg_verbose
Definition: msg.c:177
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
Definition: events.c:729
void myfree(void *ptr)
Definition: mymalloc.c:207
VSTREAM * mail_connect_wait(const char *class, const char *name)
Definition: mail_connect.c:108
char * mystrdup(const char *str)
Definition: mymalloc.c:225
VSTREAM * clnt_stream_access(CLNT_STREAM *clnt_stream)
Definition: clnt_stream.c:206
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define readable(fd)
Definition: iostuff.h:36
char * service
Definition: clnt_stream.c:97
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
CLNT_STREAM * clnt_stream_create(const char *class, const char *service, int timeout, int ttl)
Definition: clnt_stream.c:228
char * class
Definition: clnt_stream.c:96
VSTREAM * vstream
Definition: clnt_stream.c:93
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
#define vstream_fileno(vp)
Definition: vstream.h:115
#define CLOSE_ON_EXEC
Definition: iostuff.h:51
void clnt_stream_recover(CLNT_STREAM *clnt_stream)
Definition: clnt_stream.c:194
void event_disable_readwrite(int fd)
Definition: events.c:839
void clnt_stream_free(CLNT_STREAM *clnt_stream)
Definition: clnt_stream.c:247
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
Definition: events.c:965
int close_on_exec(int fd, int on)
Definition: close_on_exec.c:49
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
void msg_info(const char *fmt,...)
Definition: msg.c:199