/* Upper bound on the time that a connection is allowed to persist.
/* DIAGNOSTICS
/* Fatal error: memory allocation problem;
+/* warning: communication error;
/* panic: internal consistency failure.
/* SEE ALSO
/* scache(3), generic session cache API
#define STR(x) vstring_str(x)
+#define SCACHE_MAX_TRIES 2
+
/* scache_clnt_save_endp - save endpoint */
static void scache_clnt_save_endp(SCACHE *scache, int endp_ttl,
const char *myname = "scache_clnt_save_endp";
VSTREAM *stream;
int status;
+ int tries;
if (msg_verbose)
msg_info("%s: endp=%s prop=%s fd=%d",
msg_panic("%s: bad endp_ttl: %d", myname, endp_ttl);
/*
- * Keep trying until we get a complete response. The session cache
- * service is CPU bound and making the client asynchronous would just
- * complicate the code.
+ * Try a few times before disabling the cache. We use synchronous calls;
+ * the session cache service is CPU bound and making the client
+ * asynchronous would just complicate the code.
*/
- for (;;) {
+ for (tries = 0; sp->clnt_stream != 0 ; tries++) {
stream = clnt_stream_access(sp->clnt_stream);
errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
VSTREAM_PATH(stream));
+ /* Give up or recover. */
} else {
- if (close(fd) < 0)
- msg_warn("%s: close(%d): %m", myname, fd);
+ if (msg_verbose && status != 0)
+ msg_warn("%s: descriptor save failed with status %d",
+ myname, status);
+ break;
+ }
+ /* Give up or recover. */
+ if (tries >= SCACHE_MAX_TRIES - 1) {
+ msg_warn("disabling connection caching");
+ clnt_stream_free(sp->clnt_stream);
+ sp->clnt_stream = 0;
break;
}
sleep(1); /* XXX make configurable */
clnt_stream_recover(sp->clnt_stream);
}
+ /* Always close the descriptor before returning. */
+ if (close(fd) < 0)
+ msg_warn("%s: close(%d): %m", myname, fd);
}
/* scache_clnt_find_endp - look up cached session */
const char *myname = "scache_clnt_find_endp";
VSTREAM *stream;
int status;
+ int tries;
int fd;
/*
- * Keep trying until we get a complete response. The session cache
- * service is CPU bound and making the client asynchronous would just
- * complicate the code.
+ * Try a few times before disabling the cache. We use synchronous calls;
+ * the session cache service is CPU bound and making the client
+ * asynchronous would just complicate the code.
*/
- for (;;) {
+ for (tries = 0; sp->clnt_stream != 0 ; tries++) {
stream = clnt_stream_access(sp->clnt_stream);
errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
|| attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
- ATTR_TYPE_END) != 2
- || (status == 0
- && (
+ ATTR_TYPE_END) != 2) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else if (status != 0) {
+ if (msg_verbose)
+ msg_info("%s: not found: %s", myname, endp_label);
+ return (-1);
+ } else if (
#ifdef CANT_WRITE_BEFORE_SENDING_FD
- attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream) != 0
- || read_wait(vstream_fileno(stream),
- stream->timeout) < 0 || /* XXX */
+ attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream) != 0
+ || read_wait(vstream_fileno(stream),
+ stream->timeout) < 0 || /* XXX */
#endif
- (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0))) {
+ (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
VSTREAM_PATH(stream));
+ /* Give up or recover. */
} else {
- break;
+#ifdef MUST_READ_AFTER_SENDING_FD
+ (void) attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END);
+ (void) vstream_fflush(stream);
+#endif
+ if (msg_verbose)
+ msg_info("%s: endp=%s prop=%s fd=%d",
+ myname, endp_label, STR(endp_prop), fd);
+ return (fd);
+ }
+ /* Give up or recover. */
+ if (tries >= SCACHE_MAX_TRIES - 1) {
+ msg_warn("disabling connection caching");
+ clnt_stream_free(sp->clnt_stream);
+ sp->clnt_stream = 0;
+ return (-1);
}
sleep(1); /* XXX make configurable */
clnt_stream_recover(sp->clnt_stream);
}
-
- if (status == 0) {
- if (msg_verbose)
- msg_info("%s: endp=%s prop=%s fd=%d",
- myname, endp_label, STR(endp_prop), fd);
- return (fd);
- }
- if (msg_verbose)
- msg_info("%s: not found: %s", myname, endp_label);
- return (-1);
}
/* scache_clnt_save_dest - create destination/endpoint association */
const char *myname = "scache_clnt_save_dest";
VSTREAM *stream;
int status;
+ int tries;
if (msg_verbose)
msg_info("%s: dest_label=%s dest_prop=%s endp_label=%s",
msg_panic("%s: bad dest_ttl: %d", myname, dest_ttl);
/*
- * Keep trying until we get a complete response. The session cache
- * service is CPU bound and making the client asynchronous would just
- * complicate the code.
+ * Try a few times before disabling the cache. We use synchronous calls;
+ * the session cache service is CPU bound and making the client
+ * asynchronous would just complicate the code.
*/
- for (;;) {
+ for (tries = 0; sp->clnt_stream != 0 ; tries++) {
stream = clnt_stream_access(sp->clnt_stream);
errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
VSTREAM_PATH(stream));
+ /* Give up or recover. */
} else {
+ if (msg_verbose && status != 0)
+ msg_warn("%s: destination save failed with status %d",
+ myname, status);
+ break;
+ }
+ /* Give up or recover. */
+ if (tries >= SCACHE_MAX_TRIES - 1) {
+ msg_warn("disabling connection caching");
+ clnt_stream_free(sp->clnt_stream);
+ sp->clnt_stream = 0;
break;
}
sleep(1); /* XXX make configurable */
const char *myname = "scache_clnt_find_dest";
VSTREAM *stream;
int status;
+ int tries;
int fd;
/*
- * Keep trying until we get a complete response. The session cache
- * service is CPU bound and making the client asynchronous would just
- * complicate the code.
+ * Try a few times before disabling the cache. We use synchronous calls;
+ * the session cache service is CPU bound and making the client
+ * asynchronous would just complicate the code.
*/
- for (;;) {
+ for (tries = 0; sp->clnt_stream != 0 ; tries++) {
stream = clnt_stream_access(sp->clnt_stream);
errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_STR, MAIL_ATTR_PROP, dest_prop,
ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
- ATTR_TYPE_END) != 3
- || (status == 0
- && (
+ ATTR_TYPE_END) != 3) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else if (status != 0) {
+ if (msg_verbose)
+ msg_info("%s: not found: %s", myname, dest_label);
+ return (-1);
+ } else if (
#ifdef CANT_WRITE_BEFORE_SENDING_FD
- attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream) != 0
- || read_wait(vstream_fileno(stream),
- stream->timeout) < 0 || /* XXX */
+ attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream) != 0
+ || read_wait(vstream_fileno(stream),
+ stream->timeout) < 0 || /* XXX */
#endif
- (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0))) {
+ (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
VSTREAM_PATH(stream));
+ /* Give up or recover. */
} else {
- break;
+#ifdef MUST_READ_AFTER_SENDING_FD
+ (void) attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END);
+ (void) vstream_fflush(stream);
+#endif
+ if (msg_verbose)
+ msg_info("%s: dest=%s dest_prop=%s endp_prop=%s fd=%d",
+ myname, dest_label, STR(dest_prop), STR(endp_prop), fd);
+ return (fd);
+ }
+ /* Give up or recover. */
+ if (tries >= SCACHE_MAX_TRIES - 1) {
+ msg_warn("disabling connection caching");
+ clnt_stream_free(sp->clnt_stream);
+ sp->clnt_stream = 0;
+ return (-1);
}
sleep(1); /* XXX make configurable */
clnt_stream_recover(sp->clnt_stream);
}
-
- if (status == 0) {
- if (msg_verbose)
- msg_info("%s: dest=%s dest_prop=%s endp_prop=%s fd=%d",
- myname, dest_label, STR(dest_prop), STR(endp_prop), fd);
- return (fd);
- }
- if (msg_verbose)
- msg_info("%s: not found: %s", myname, dest_label);
-
- return (-1);
}
/* scache_clnt_size - dummy */
{
SCACHE_CLNT *sp = (SCACHE_CLNT *) scache;
- clnt_stream_free(sp->clnt_stream);
+ if (sp->clnt_stream)
+ clnt_stream_free(sp->clnt_stream);
#ifdef CANT_WRITE_BEFORE_SENDING_FD
vstring_free(sp->dummy);
#endif
sp->scache->size = scache_clnt_size;
sp->scache->free = scache_clnt_free;
+ /* XXX Need flags to stop looping on ECONNREFUSED errors. */
sp->clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE, server,
idle_limit, ttl_limit);
#ifdef CANT_WRITE_BEFORE_SENDING_FD
#endif
(fd = LOCAL_RECV_FD(vstream_fileno(client_stream))) < 0) {
msg_warn("%s: unable to receive file descriptor: %m", myname);
- attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
- ATTR_TYPE_END);
+ (void) attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
+ ATTR_TYPE_END);
return;
} else {
scache_save_endp(scache,
ttl > var_scache_ttl_lim ? var_scache_ttl_lim : ttl,
STR(scache_endp_label), STR(scache_endp_prop), fd);
- attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
- ATTR_TYPE_END);
+ (void) attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
+ ATTR_TYPE_END);
scache_size(scache, &size);
if (size.endp_count > scache_endp_count)
scache_endp_count = size.endp_count;
ATTR_TYPE_STR, MAIL_ATTR_DUMMY, scache_dummy,
ATTR_TYPE_END) != 1
#endif
- || LOCAL_SEND_FD(vstream_fileno(client_stream), fd) < 0)
+ || LOCAL_SEND_FD(vstream_fileno(client_stream), fd) < 0
+#ifdef MUST_READ_AFTER_SENDING_FD
+ || attr_scan(client_stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, scache_dummy,
+ ATTR_TYPE_END) != 1
+#endif
+ )
msg_warn("%s: cannot send file descriptor: %m", myname);
if (close(fd) < 0)
msg_warn("close(%d): %m", fd);
ATTR_TYPE_STR, MAIL_ATTR_DUMMY, scache_dummy,
ATTR_TYPE_END) != 1
#endif
- || LOCAL_SEND_FD(vstream_fileno(client_stream), fd) < 0)
+ || LOCAL_SEND_FD(vstream_fileno(client_stream), fd) < 0
+#ifdef MUST_READ_AFTER_SENDING_FD
+ || attr_scan(client_stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, scache_dummy,
+ ATTR_TYPE_END) != 1
+#endif
+ )
msg_warn("%s: cannot send file descriptor: %m", myname);
if (close(fd) < 0)
msg_warn("close(%d): %m", fd);