static void read_data(int unused_event, void *context) { SINK_STATE *state = (SINK_STATE *) context; int fd = vstream_fileno(state->stream); int count; /* * Refill the VSTREAM buffer, if necessary. */ if (VSTREAM_GETC(state->stream) == VSTREAM_EOF) netstring_except(state->stream, vstream_ftimeout(state->stream) ? NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); state->count--; /* * Flush the VSTREAM buffer. As documented, vstream_fseek() discards * unread input. */ if ((count = vstream_peek(state->stream)) > 0) { state->count -= count; if (state->count <= 0) { send_reply(state); return; } vstream_fpurge(state->stream, VSTREAM_PURGE_BOTH); } /* * Do not block while waiting for the arrival of more data. */ event_disable_readwrite(fd); event_enable_read(fd, read_data, context); }
static void psc_endpt_haproxy_event(int event, char *context) { const char *myname = "psc_endpt_haproxy_event"; PSC_HAPROXY_STATE *state = (PSC_HAPROXY_STATE *) context; int status = 0; MAI_HOSTADDR_STR smtp_client_addr; MAI_SERVPORT_STR smtp_client_port; MAI_HOSTADDR_STR smtp_server_addr; MAI_SERVPORT_STR smtp_server_port; int last_char = 0; const char *err; VSTRING *escape_buf; char read_buf[HAPROXY_MAX_LEN]; ssize_t read_len; char *cp; /* * We must not read(2) past the <CR><LF> that terminates the haproxy * line. For efficiency reasons we read the entire haproxy line in one * read(2) call when we know that the line is unfragmented. In the rare * case that the line is fragmented, we fall back and read(2) it one * character at a time. */ switch (event) { case EVENT_TIME: msg_warn("haproxy read: time limit exceeded"); status = -1; break; case EVENT_READ: /* Determine the initial VSTREAM read(2) buffer size. */ if (VSTRING_LEN(state->buffer) == 0) { if ((read_len = recv(vstream_fileno(state->stream), read_buf, sizeof(read_buf) - 1, MSG_PEEK)) > 0 && ((cp = memchr(read_buf, '\n', read_len)) != 0)) { read_len = cp - read_buf + 1; } else { read_len = 1; } vstream_control(state->stream, VSTREAM_CTL_BUFSIZE, read_len, VSTREAM_CTL_END); } /* Drain the VSTREAM buffer, otherwise this pseudo-thread will hang. */ do { if ((last_char = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) { if (vstream_ferror(state->stream)) msg_warn("haproxy read: %m"); else msg_warn("haproxy read: lost connection"); status = -1; break; } if (VSTRING_LEN(state->buffer) >= HAPROXY_MAX_LEN) { msg_warn("haproxy read: line too long"); status = -1; break; } VSTRING_ADDCH(state->buffer, last_char); } while (vstream_peek(state->stream) > 0); break; } /* * Parse the haproxy line. Note: the haproxy_srvr_parse() routine * performs address protocol checks, address and port syntax checks, and * converts IPv4-in-IPv6 address string syntax (:ffff::1.2.3.4) to IPv4 * syntax where permitted by the main.cf:inet_protocols setting. */ if (status == 0 && last_char == '\n') { VSTRING_TERMINATE(state->buffer); if ((err = haproxy_srvr_parse(vstring_str(state->buffer), &smtp_client_addr, &smtp_client_port, &smtp_server_addr, &smtp_server_port)) != 0) { escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2); escape(escape_buf, vstring_str(state->buffer), VSTRING_LEN(state->buffer)); msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf)); status = -1; vstring_free(escape_buf); } } /* * Are we done yet? */ if (status < 0 || last_char == '\n') { PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->stream), psc_endpt_haproxy_event, context); vstream_control(state->stream, VSTREAM_CTL_BUFSIZE, (ssize_t) VSTREAM_BUFSIZE, VSTREAM_CTL_END); state->notify(status, state->stream, &smtp_client_addr, &smtp_client_port, &smtp_server_addr, &smtp_server_port); /* Note: the stream may be closed at this point. */ vstring_free(state->buffer); myfree((char *) state); } }
SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, VSTRING *dest_prop, VSTRING *endp_prop) { const char *myname = "smtp_session_activate"; VSTREAM *mp; SMTP_SESSION *session; int endp_features; /* server features */ int dest_features; /* server features */ long expire_time; /* session re-use expiration time */ int reuse_count; /* # times reused */ #ifdef USE_TLS TLS_SESS_STATE *tls_context = 0; SMTP_TLS_POLICY *tls = iter->parent->tls; #define TLS_PROXY_CONTEXT_FREE() do { \ if (tls_context) \ tls_proxy_context_free(tls_context); \ } while (0) #else #define TLS_PROXY_CONTEXT_FREE() /* nothing */ #endif #define SMTP_SESSION_ACTIVATE_ERR_RETURN() do { \ TLS_PROXY_CONTEXT_FREE(); \ return (0); \ } while (0) /* * Sanity check: if TLS is required, the cached properties must contain a * TLS context. */ if ((mp = vstream_memopen(endp_prop, O_RDONLY)) == 0 || attr_scan_plain(mp, ATTR_FLAG_NONE, #ifdef USE_TLS RECV_ATTR_INT(SESS_ATTR_TLS_LEVEL, &tls->level), #endif RECV_ATTR_INT(SESS_ATTR_REUSE_COUNT, &reuse_count), RECV_ATTR_INT(SESS_ATTR_ENDP_FEATURES, &endp_features), RECV_ATTR_LONG(SESS_ATTR_EXPIRE_TIME, &expire_time), ATTR_TYPE_END) != 4 #ifdef USE_TLS || ((tls->level > TLS_LEV_MAY || (tls->level == TLS_LEV_MAY && vstream_peek(mp) > 0)) && attr_scan_plain(mp, ATTR_FLAG_NONE, RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) &tls_context), ATTR_TYPE_END) != 1) #endif || vstream_fclose(mp) != 0) { msg_warn("smtp_session_activate: bad cached endp properties"); SMTP_SESSION_ACTIVATE_ERR_RETURN(); } /* * Clobber the iterator's current nexthop, host and address fields with * cached-connection information. This is done when a session is looked * up by delivery request nexthop instead of address and port. It is the * caller's responsibility to save and restore the delivery request * nexthop with SMTP_ITER_SAVE_DEST() and SMTP_ITER_RESTORE_DEST(). * * TODO: Eliminate the duplication between SMTP_ITERATOR and SMTP_SESSION. * * TODO: restore SASL username and password information so that we can * correctly save a reused authenticated connection. */ if (dest_prop && VSTRING_LEN(dest_prop)) { if ((mp = vstream_memopen(dest_prop, O_RDONLY)) == 0 || attr_scan_plain(mp, ATTR_FLAG_NONE, RECV_ATTR_STR(SESS_ATTR_DEST, iter->dest), RECV_ATTR_STR(SESS_ATTR_HOST, iter->host), RECV_ATTR_STR(SESS_ATTR_ADDR, iter->addr), RECV_ATTR_INT(SESS_ATTR_DEST_FEATURES, &dest_features), ATTR_TYPE_END) != 4 || vstream_fclose(mp) != 0) { msg_warn("smtp_session_passivate: bad cached dest properties"); SMTP_SESSION_ACTIVATE_ERR_RETURN(); } } else { dest_features = 0; } #ifdef USE_TLS if (msg_verbose) msg_info("%s: tls_level=%d", myname, tls->level); #endif /* * Allright, bundle up what we have sofar. */ #define NO_FLAGS 0 session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), iter, (time_t) 0, NO_FLAGS); session->features = (endp_features | dest_features | SMTP_FEATURE_FROM_CACHE); #ifdef USE_TLS session->tls_context = tls_context; #endif CACHE_THIS_SESSION_UNTIL(expire_time); session->reuse_count = ++reuse_count; if (msg_verbose) msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, " "ttl=%ld, reuse=%d", myname, STR(iter->dest), STR(iter->host), STR(iter->addr), ntohs(iter->port), endp_features | dest_features, (long) (expire_time - time((time_t *) 0)), reuse_count); #if USE_TLS if (tls_context) tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_USED, session->tls_context); #endif return (session); }