int main(int unused_argc, char **argv) { HTABLE *table = htable_create(1); msg_vstream_init(argv[0], VSTREAM_ERR); msg_verbose = 1; htable_enter(table, "foo-name", mystrdup("foo-value")); htable_enter(table, "bar-name", mystrdup("bar-value")); attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE, ATTR_TYPE_INT, ATTR_NAME_INT, 4711, ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", ATTR_TYPE_HASH, table, ATTR_TYPE_END); attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE, ATTR_TYPE_INT, ATTR_NAME_INT, 4711, ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", ATTR_TYPE_END); if (vstream_fflush(VSTREAM_OUT) != 0) msg_fatal("write error: %m"); htable_free(table, myfree); return (0); }
static void anvil_remote_disconnect(VSTREAM *client_stream, const char *ident) { ANVIL_REMOTE *anvil_remote; ANVIL_LOCAL *anvil_local; const char *myname = "anvil_remote_disconnect"; if (msg_verbose) msg_info("%s fd=%d stream=0x%lx ident=%s", myname, vstream_fileno(client_stream), (unsigned long) client_stream, ident); /* * Update local and remote info if this remote connection is listed for * this local server. */ if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0 && (anvil_remote = (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) != 0 && ANVIL_LOCAL_REMOTE_LINKED(anvil_local, anvil_remote)) { ANVIL_REMOTE_DROP_ONE(anvil_remote); ANVIL_LOCAL_DROP_ONE(anvil_local, anvil_remote); } if (msg_verbose) msg_info("%s: anvil_local 0x%lx", myname, (unsigned long) anvil_local); /* * Respond to the local server. */ attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_END); }
static void anvil_remote_newtls_stat(VSTREAM *client_stream, const char *ident) { ANVIL_REMOTE *anvil_remote; int rate; /* * Be prepared for "postfix reload" after "connect". */ if ((anvil_remote = (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) { rate = 0; } /* * Do not report stale information. */ else { if (anvil_remote->start != 0 && anvil_remote->start + var_anvil_time_unit < event_time()) ANVIL_REMOTE_RSET_RATE(anvil_remote, 0); rate = anvil_remote->ntls; } /* * Respond to local server. */ attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_INT, ANVIL_ATTR_RATE, rate, ATTR_TYPE_END); }
static void anvil_remote_newtls(VSTREAM *client_stream, const char *ident) { ANVIL_REMOTE *anvil_remote; /* * Be prepared for "postfix reload" after "connect". */ if ((anvil_remote = (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) anvil_remote = anvil_remote_conn_update(client_stream, ident); /* * Update newtls rate and respond to local server. */ ANVIL_REMOTE_INCR_NTLS(anvil_remote); attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->ntls, ATTR_TYPE_END); /* * Update peak statistics. */ if (anvil_remote->ntls > max_ntls_rate.value) ANVIL_MAX_UPDATE(max_ntls_rate, anvil_remote->ntls, anvil_remote->ident); }
static void anvil_remote_connect(VSTREAM *client_stream, const char *ident) { ANVIL_REMOTE *anvil_remote; /* * Update or instantiate connection info. */ anvil_remote = anvil_remote_conn_update(client_stream, ident); /* * Respond to the local server. */ attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_INT, ANVIL_ATTR_COUNT, anvil_remote->count, ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->rate, ATTR_TYPE_END); /* * Update peak statistics. */ if (anvil_remote->rate > max_conn_rate.value) ANVIL_MAX_UPDATE(max_conn_rate, anvil_remote->rate, anvil_remote->ident); if (anvil_remote->count > max_conn_count.value) ANVIL_MAX_UPDATE(max_conn_count, anvil_remote->count, anvil_remote->ident); }
static void anvil_remote_lookup(VSTREAM *client_stream, const char *ident) { ANVIL_REMOTE *anvil_remote; const char *myname = "anvil_remote_lookup"; if (msg_verbose) msg_info("%s fd=%d stream=0x%lx ident=%s", myname, vstream_fileno(client_stream), (unsigned long) client_stream, ident); /* * Look up remote client information. */ if ((anvil_remote = (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) { attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_INT, ANVIL_ATTR_COUNT, 0, ATTR_TYPE_INT, ANVIL_ATTR_RATE, 0, ATTR_TYPE_INT, ANVIL_ATTR_MAIL, 0, ATTR_TYPE_INT, ANVIL_ATTR_RCPT, 0, ATTR_TYPE_INT, ANVIL_ATTR_NTLS, 0, ATTR_TYPE_END); } else { /* * Do not report stale information. */ if (anvil_remote->start != 0 && anvil_remote->start + var_anvil_time_unit < event_time()) ANVIL_REMOTE_RSET_RATE(anvil_remote, 0); attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_INT, ANVIL_ATTR_COUNT, anvil_remote->count, ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->rate, ATTR_TYPE_INT, ANVIL_ATTR_MAIL, anvil_remote->mail, ATTR_TYPE_INT, ANVIL_ATTR_RCPT, anvil_remote->rcpt, ATTR_TYPE_INT, ANVIL_ATTR_NTLS, anvil_remote->ntls, ATTR_TYPE_END); } }
static void anvil_service(VSTREAM *client_stream, char *unused_service, char **argv) { static VSTRING *request; static VSTRING *ident; static const ANVIL_REQ_TABLE request_table[] = { ANVIL_REQ_CONN, anvil_remote_connect, ANVIL_REQ_MAIL, anvil_remote_mail, ANVIL_REQ_RCPT, anvil_remote_rcpt, ANVIL_REQ_NTLS, anvil_remote_newtls, ANVIL_REQ_DISC, anvil_remote_disconnect, ANVIL_REQ_NTLS_STAT, anvil_remote_newtls_stat, ANVIL_REQ_LOOKUP, anvil_remote_lookup, 0, 0, }; const ANVIL_REQ_TABLE *rp; /* * Sanity check. This service takes no command-line arguments. */ if (argv[0]) msg_fatal("unexpected command-line argument: %s", argv[0]); /* * Initialize. */ if (request == 0) { request = vstring_alloc(10); ident = vstring_alloc(10); } /* * This routine runs whenever a client connects to the socket dedicated * to the client connection rate management service. All * connection-management stuff is handled by the common code in * multi_server.c. */ if (msg_verbose) msg_info("--- start request ---"); if (attr_scan_plain(client_stream, ATTR_FLAG_MISSING | ATTR_FLAG_STRICT, ATTR_TYPE_STR, ANVIL_ATTR_REQ, request, ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, ATTR_TYPE_END) == 2) { for (rp = request_table; /* see below */ ; rp++) { if (rp->name == 0) { msg_warn("unrecognized request: \"%s\", ignored", STR(request)); attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_FAIL, ATTR_TYPE_END); break; } if (STREQ(rp->name, STR(request))) { rp->action(client_stream, STR(ident)); break; } } vstream_fflush(client_stream); } else { /* Note: invokes anvil_service_done() */ multi_server_disconnect(client_stream); } if (msg_verbose) msg_info("--- end request ---"); }
int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, VSTRING *endp_prop) { SMTP_ITERATOR *iter = session->iterator; VSTREAM *mp; int fd; /* * Encode the delivery request next-hop to endpoint binding properties: * whether or not this server is best MX host for the delivery request * next-hop or fall-back logical destination (this information is needed * for loop handling in smtp_proto()). * * TODO: save SASL username and password information so that we can * correctly save a reused authenticated connection. * * These memory writes should never fail. */ if ((mp = vstream_memopen(dest_prop, O_WRONLY)) == 0 || attr_print_plain(mp, ATTR_FLAG_NONE, SEND_ATTR_STR(SESS_ATTR_DEST, STR(iter->dest)), SEND_ATTR_STR(SESS_ATTR_HOST, STR(iter->host)), SEND_ATTR_STR(SESS_ATTR_ADDR, STR(iter->addr)), SEND_ATTR_INT(SESS_ATTR_DEST_FEATURES, session->features & SMTP_FEATURE_DESTINATION_MASK), ATTR_TYPE_END) != 0 || vstream_fclose(mp) != 0) msg_fatal("smtp_session_passivate: can't save dest properties: %m"); /* * Encode the physical endpoint properties: all the session properties * except for "session from cache", "best MX", or "RSET failure". Plus * the TLS level, reuse count, and connection expiration time. * * XXX Should also record how many non-delivering mail transactions there * were during this session, and perhaps other statistics, so that we * don't reuse a session too much. * * TODO: passivate SASL username and password information so that we can * correctly save a reused authenticated connection. * * These memory writes should never fail. */ if ((mp = vstream_memopen(endp_prop, O_WRONLY)) == 0 || attr_print_plain(mp, ATTR_FLAG_NONE, #ifdef USE_TLS SEND_ATTR_INT(SESS_ATTR_TLS_LEVEL, session->state->tls->level), #endif SEND_ATTR_INT(SESS_ATTR_REUSE_COUNT, session->reuse_count), SEND_ATTR_INT(SESS_ATTR_ENDP_FEATURES, session->features & SMTP_FEATURE_ENDPOINT_MASK), SEND_ATTR_LONG(SESS_ATTR_EXPIRE_TIME, (long) session->expire_time), ATTR_TYPE_END) != 0 /* * Append the passivated TLS context. These memory writes should never * fail. */ #ifdef USE_TLS || (session->tls_context && attr_print_plain(mp, ATTR_FLAG_NONE, SEND_ATTR_FUNC(tls_proxy_context_print, (void *) session->tls_context), ATTR_TYPE_END) != 0) #endif || vstream_fclose(mp) != 0) msg_fatal("smtp_session_passivate: cannot save TLS context: %m"); /* * Salvage the underlying file descriptor, and destroy the session * object. */ fd = vstream_fileno(session->stream); vstream_fdclose(session->stream); session->stream = 0; smtp_session_free(session); return (fd); }