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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
/*++
/* NAME
/* clnt_stream 3
/* SUMMARY
/* client endpoint maintenance
/* SYNOPSIS
/* #include <clnt_stream.h>
/*
/* CLNT_STREAM *clnt_stream_create(class, service, timeout)
/* const char *class;
/* const char *service;
/* int timeout;
/*
/* VSTREAM *clnt_stream_access(clnt_stream)
/* CLNT_STREAM *clnt_stream;
/*
/* void clnt_stream_recover(clnt_stream)
/* CLNT_STREAM *clnt_stream;
/*
/* void clnt_stream_free(clnt_stream)
/* CLNT_STREAM *clnt_stream;
/* DESCRIPTION
/* This module maintains local IPC client endpoints that automatically
/* disconnect after a being idle for a configurable amount of time,
/* and that transparently handle most server-initiated disconnects.
/* Server disconnect is detected by read-selecting the client endpoint.
/* The code assumes that the server has disconnected when the endpoint
/* becomes readable.
/*
/* clnt_stream_create() instantiates a client endpoint.
/*
/* clnt_stream_access() returns an open stream to the service specified
/* to clnt_stream_create(). The stream instance may change between calls.
/*
/* clnt_stream_recover() recovers from a server-initiated disconnect
/* that happened in the middle of an I/O operation.
/*
/* clnt_stream_free() destroys of the specified client endpoint.
/* DIAGNOSTICS
/* Warnings: communication failure. Fatal error: mail system is down,
/* out of memory.
/* SEE ALSO
/* mail_proto(3h) low-level mail component glue.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <vstream.h>
#include <events.h>
#include <iostuff.h>
/* Global library. */
#include "mail_proto.h"
#include "mail_params.h"
#include "clnt_stream.h"
/* Application-specific. */
/*
* CLNT_STREAM is an opaque structure. None of the access methods can easily
* be implemented as a macro, and access is not performance critica anyway.
*/
struct CLNT_STREAM {
VSTREAM *vstream; /* buffered I/O */
int timeout; /* time before client disconnect */
char *class; /* server class */
char *service; /* server name */
};
static void clnt_stream_close(CLNT_STREAM *);
/* clnt_stream_event - server-initiated disconnect or client-side timeout */
static void clnt_stream_event(int unused_event, char *context)
{
CLNT_STREAM *clnt_stream = (CLNT_STREAM *) context;
/*
* Sanity check. This routine causes the stream to be closed, so it
* cannot be called when the stream is already closed.
*/
if (clnt_stream->vstream == 0)
msg_panic("clnt_stream_event: stream is closed");
clnt_stream_close(clnt_stream);
}
/* clnt_stream_open - connect to service */
static void clnt_stream_open(CLNT_STREAM *clnt_stream)
{
/*
* Sanity check.
*/
if (clnt_stream->vstream)
msg_panic("clnt_stream_open: stream is open");
/*
* Schedule a read event so that we can clean up when the remote side
* disconnects, and schedule a timer event so that we can cleanup an idle
* connection. Note that both events are handled by the same routine.
*/
clnt_stream->vstream = mail_connect_wait(clnt_stream->class,
clnt_stream->service);
close_on_exec(vstream_fileno(clnt_stream->vstream), CLOSE_ON_EXEC);
event_enable_read(vstream_fileno(clnt_stream->vstream), clnt_stream_event,
(char *) clnt_stream);
event_request_timer(clnt_stream_event, (char *) clnt_stream,
clnt_stream->timeout);
}
/* clnt_stream_close - disconnect from service */
static void clnt_stream_close(CLNT_STREAM *clnt_stream)
{
/*
* Sanity check.
*/
if (clnt_stream->vstream == 0)
msg_panic("clnt_stream_close: stream is closed");
/*
* Be sure to disable read and timer events.
*/
if (msg_verbose)
msg_info("%s stream disconnect", clnt_stream->service);
event_disable_readwrite(vstream_fileno(clnt_stream->vstream));
event_cancel_timer(clnt_stream_event, (char *) clnt_stream);
(void) vstream_fclose(clnt_stream->vstream);
clnt_stream->vstream = 0;
}
/* clnt_stream_recover - recover from server-initiated disconnect */
void clnt_stream_recover(CLNT_STREAM *clnt_stream)
{
/*
* Clean up. Don't re-connect until the caller needs it.
*/
if (clnt_stream->vstream)
clnt_stream_close(clnt_stream);
}
/* clnt_stream_access - access a client stream */
VSTREAM *clnt_stream_access(CLNT_STREAM *clnt_stream)
{
/*
* Open a stream or restart the idle timer.
*/
if (clnt_stream->vstream == 0) {
clnt_stream_open(clnt_stream);
} else {
event_request_timer(clnt_stream_event, (char *) clnt_stream,
clnt_stream->timeout);
}
return (clnt_stream->vstream);
}
/* clnt_stream_create - create client stream connection */
CLNT_STREAM *clnt_stream_create(const char *class, const char *service,
int timeout)
{
CLNT_STREAM *clnt_stream;
/*
* Don't open the stream until the caller needs it.
*/
clnt_stream = (CLNT_STREAM *) mymalloc(sizeof(*clnt_stream));
clnt_stream->vstream = 0;
clnt_stream->timeout = timeout;
clnt_stream->class = mystrdup(class);
clnt_stream->service = mystrdup(service);
return (clnt_stream);
}
/* clnt_stream_free - destroy client stream instance */
void clnt_stream_free(CLNT_STREAM *clnt_stream)
{
if (clnt_stream->vstream)
clnt_stream_close(clnt_stream);
myfree(clnt_stream->class);
myfree(clnt_stream->service);
myfree((char *) clnt_stream);
}
|