/* * Copyright (c) 2002-2006 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * * $Id: smtpc.h,v 1.136 2007/05/27 15:13:00 ca Exp $ */ #ifndef SMTPC_H #define SMTPC_H 1 #include "sm/generic.h" #include "sm/magic.h" #include "sm/rpool.h" #include "sm/time.h" #include "sm/io.h" #include "sm/rfc2821.h" #include "sm/mta.h" #include "sm/rcb.h" #include "statethreads/st.h" #include "sm/stsock.h" #include "sm/log.h" #include "sm/cdb.h" #include "sm/tls.h" #include "sm/sm-conf.h" #include "sm/scdef.h" #include "sm/sccnf.h" #include "sm/hdrmod.h" #ifndef SC_PIPELINING # define SC_PIPELINING 1 #endif #ifndef SC_STATS # define SC_STATS 1 #endif #ifndef SC_DEBUG # define SC_DEBUG 0 #endif #ifndef MTA_USE_RSAD # define MTA_USE_RSAD 1 /* RCPT status after final dot */ #endif #include "sm/sccnfdef.h" #if SC_DEBUG # include # define SC_DPRINTF(x) sm_io_fprintf x # define SC_LEV_DPRINTF(sc_ctx, lev, x) do \ { \ if ((lev) < (sc_ctx)->scc_cnf.sc_cnf_debug) \ sm_io_fprintf x; \ } while (0) #else /* SC_DEBUG */ # define SC_DPRINTF(x) # define SC_LEV_DPRINTF(sc_ctx, lev, x) #endif /* SC_DEBUG */ #define REQUEST_TIMEOUT 20 /* requests from QMGR */ /* QMGR read timeout (in seconds) */ #define TMO_W4Q2C 10 extern sm_stream_T SmStThrIO; void *handle_request(void *arg); #define SMTPC_OK_REPLY(ret) ((ret) == SMTP_OK || (ret) == SMTP_NO_REPLY) #define SMTPC_R_IS_OK(ret) ((ret) == SMTP_OK || (ret) == SMTP_NO_REPLY) #define NO_RCPTS(sc_ta) (0 == (sc_ta)->scta_rcpts_ok) /* SMTPC context */ typedef struct sc_ctx_S sc_ctx_T, *sc_ctx_P; /* client context per thread */ typedef struct sc_t_ctx_S sc_t_ctx_T, *sc_t_ctx_P; /* session context */ typedef struct sc_sess_S sc_sess_T, *sc_sess_P; /* transaction context */ typedef struct sc_ta_S sc_ta_T, *sc_ta_P; struct sc_ctx_S { sm_magic_T sm_magic; /* ** add pointer to c2q_ctx? That requires that we either use ** struct ... * ** or include the struct definition here. ** ** rename some components? ** ** note: scc_ is SmtpC Context, to avoid conflicts on HP: sc_flags */ sc_cnf_T scc_cnf; st_utime_t scc_qmgr_tmo; /* sc_cnf_qmgr_tmo as micro seconds */ /* ** invariant: ** scc_thrds_wait >= scc_thrds_idle + scc_thrds_clsng ** i.e., every idle/closing thread is also a waiting thread */ uint scc_thrds_wait; /* # of threads waiting */ uint scc_thrds_idle; /* # of idle threads */ uint scc_thrds_clsng; /* # of closing threads */ uint scc_thrds_busy; /* # of threads processing request */ /* statistics */ uint scc_thrds_max_used; /* max number of threads used */ uint scc_rqst_count; /* Total # of processed requests */ uint32_t scc_flags; /* SMTPC flags */ sm_str_P scc_hostname; /* SMTPC hostname */ sm_log_ctx_P scc_lctx; sm_logconfig_P scc_lcfg; cdb_ctx_P scc_cdb_ctx; #if SC_STATS uint scc_mail_count; /* Total # of processed transactions */ uint scc_rcpt_count; /* Total # of recipients */ uint scc_rcpt_cnt_ok; /* Total # of sent recipients */ uint scc_ta_cnt_ok; /* Total # of sent transactions */ uint scc_reuse; /* # of reused sessions */ uint scc_busy; uint scc_open_se; /* concurrently open sessions */ uint scc_max_open_se; /* max concurrently open sessions */ ulong scc_total; #endif /* SC_STATS */ #if MTA_USE_TLS SSL_CTX *scc_ssl_ctx; tlsl_ctx_P scc_tlsl_ctx; #endif /* MTA_USE_TLS */ sc_t_ctx_P *scc_scts; /* array of sct's */ }; #define SM_IS_SC_CTX(sc_ctx) SM_REQUIRE_ISA((sc_ctx), SM_SC_CTX_MAGIC) /* SMTP Client Context flags: more? */ #define SCC_FL_NOTRDY 0 /* not ready yet */ #define SCC_FL_INIT 0x00000001 /* being initialized */ #define SCC_FL_COMMOK 0x00000002 /* sc_rcb_from_qmgr() may start */ #define SCC_FL_NOTIFIED 0x00000004 /* sc_rcb_from_qmgr() notified */ #define SCC_FL_OK 0x00000100 /* ok */ #define SCC_FL_TLS_OK 0x00000200 /* TLS ok */ #define SCC_FL_SHUTDOWN 0x00010000 /* shutting down */ #define SCC_FL_STOPPED 0x00100000 /* stopped */ #define SC_IS_FLAG(sc_ctx, flag) ((((sc_ctx)->scc_flags) & (flag)) != 0) #define SC_SET_FLAG(sc_ctx, flag) ((sc_ctx)->scc_flags) |= (flag) /* ** Configuration flags; currently these are only for testing. ** NOTE: these must be the same as SCSE_FL_* */ #define SCC_CFL_LMTP 0x00000001 /* use LMTP */ /* see also sm/scdef.h! #define SCC_CFL_NOTTM 0x00000002 * don't check "talk to myself" * */ /* mask for "inheriting" sc_cnf_confflags */ #define SCC_CFL_INHMASK 0x00000003 #define SCC_CFL_BACKGROUND 0x00000010 /* run in background mode */ /* see also sm/scdef.h! */ #define SC_IS_CFLAG(sc_ctx, flag) ((((sc_ctx)->scc_cnf.sc_cnf_confflags) & (flag)) != 0) #define SC_CLR_CFLAG(sc_ctx, flag) ((sc_ctx)->scc_cnf.sc_cnf_confflags) &= ~(flag) #define SC_SET_CFLAG(sc_ctx, flag) ((sc_ctx)->scc_cnf.sc_cnf_confflags) |= (flag) /* ** Thread context. ** Currently sess and thread are 1-1 related. */ struct sc_t_ctx_S { sm_magic_T sm_magic; sc_ctx_P sct_sc_ctx; /* pointer back to sc_ctx */ uint sct_thr_id; /* thread id (debugging) */ uint sct_status; st_cond_t sct_cond_rd; /* received data from QMGR */ sc_sess_P sct_sess; /* current session */ sm_rcb_P sct_rcb; /* rcb for communication with QMGR */ }; #define SM_IS_SC_T_CTX(sc_t_ctx) SM_REQUIRE_ISA((sc_t_ctx), SM_SC_T_CTX_MAGIC) /* sc_t status: more? */ #define SC_T_NOTRDY 0 /* not ready for use */ #define SC_T_FREE 1 /* can be used */ #define SC_T_IDLE 2 /* open session, but no active TA */ #define SC_T_CLOSING 3 /* an idle session is closing */ #define SC_T_BUSY 4 /* is busy */ #define SC_T_REUSE 5 /* a closing task will be reused */ struct sc_sess_S { sm_magic_T sm_magic; sc_t_ctx_P scse_sct_ctx; /* pointer to thread context */ sm_file_T *scse_fp; /* file to use (SMTP) */ sm_str_P scse_rd; /* smtp read buffer */ sm_str_P scse_wr; /* smtp write buffer */ sm_str_P scse_str; /* str for general use */ sm_str_P scse_reply; /* SMTP reply (for error reporting) */ sm_rpool_P scse_rpool; uint scse_cap; /* server capabilities, see below */ uint scse_flags; uint scse_state; uint scse_err_st; /* state which caused an error */ #if 0 sm_ret_T scse_ret; /* error code */ struct in_addr *scse_client; /* fixme: use a generic struct! */ #endif sc_ta_P scse_ta; /* current transaction */ sessta_id_T scse_id; sessta_id_T scse_id2; uint scse_da_idx; /* DA idx */ sm_sockaddr_T scse_rmt_addr; /* remote address */ st_netfd_t scse_rmt_fd; /* fd */ int scse_c2q_idx; /* index in c2q session array */ /* only useful if the size of the message is known... */ off_t scse_max_sz_b; /* SIZE value advertised by server */ #if MTA_USE_TLS SSL *scse_con; sm_file_T *scse_fptls; tlsi_ctx_P scse_tlsi; sm_conf_T *scse_cnf; tlsreq_cnf_T scse_tlsreq_cnf; #endif /* MTA_USE_TLS */ }; #define SM_IS_SC_SE(sc_sess) SM_REQUIRE_ISA((sc_sess), SM_SC_SESS_MAGIC) #define SCSE_C2Q_IDX_NONE (-1) /* initial value for c2q_idx */ /* session states (should these be flags too?) */ #define SCSE_ST_NONE 0 /* no session active */ #define SCSE_ST_NEW 1 /* new session */ #define SCSE_ST_CONNECTED 2 /* connection succeeded */ #define SCSE_ST_GREETED 3 /* received greeting */ #define SCSE_ST_OPEN 4 /* connection open */ #define SCSE_ST_CLOSED 8 /* close session */ /* session flags */ #define SCSE_FL_NONE 0x00000000 /* guess */ /* NOTE: these must be the same as SCC_CFL_* */ #define SCSE_FL_LMTP 0x00000001 /* use LMTP */ #define SCSE_FL_NOTTM 0x00000002 /* don't check "talk to myself" */ #define SCSE_FL_CLOSE_EX 0x00000008 /* close existing session */ #define SCSE_FL_EHLO 0x00000010 /* sent EHLO */ #define SCSE_FL_HELO 0x00000020 /* sent HELO */ #define SCSE_FL_RSET 0x00000040 /* sent RSET */ #define SCSE_FL_AUTH 0x00000100 /* AUTH */ #define SCSE_FL_STARTTLS 0x00000200 /* STARTTLS */ #define SCSE_FL_QUIT_S 0x00000400 /* sent QUIT */ #define SCSE_FL_QUIT_R 0x00000800 /* received reply for QUIT */ #define SCSE_FL_SSD 0x00001000 /* encountered 421 */ #define SCSE_FL_RSAD 0x00004000 /* used RCPT status after dot */ /* ** close session; note: this can be set during SMTP and will cause a session ** close ASAP. Do NOT set this in response to a qmgr task! */ #define SCSE_FL_CLOSE 0x00004000 /* last TA: close session afterwards */ #define SCSE_FL_LAST_TA 0x00010000 #define SCSE_FL_LWR 0x00020000 /* lower case recipient */ #define SCSE_FL_RETPATH 0x00040000 /* add Return-Path: */ #define SCSE_FL_ERROR 0x00100000 /* error occurred */ #define SCSE_FL_IO_ERR 0x00200000 /* I/O error occurred */ #define SCSE_FL_LOGGED 0x00400000 /* error already logged */ /* need to send status (in sc_t_ctx->sct_rcb) to QMGR */ #define SCSE_FL_SND_ST 0x01000000 /* tell QMGR about session close (cleared as soon as it was done somewhere) */ #define SCSE_FL_SE_CLS2QMGR 0x02000000 #define SCSE_SET_FLAG(sc_sess, fl) (sc_sess)->scse_flags |= (fl) #define SCSE_CLR_FLAG(sc_sess, fl) (sc_sess)->scse_flags &= ~(fl) #define SCSE_IS_FLAG(sc_sess, fl) (((sc_sess)->scse_flags & (fl)) != 0) #define SCSE_INHERIT_FLAG(sc_sess) (sc_sess)->scse_flags = (sc_sess)->scse_sct_ctx->sct_sc_ctx->scc_cnf.sc_cnf_confflags & SCC_CFL_INHMASK /* server capabilities */ #define SCSE_CAP_NONE 0x0000 /* guess */ #define SCSE_CAP_ESMTP 0x0001 /* ESMTP */ #define SCSE_CAP_PIPELINING 0x0010 /* PIPELINING */ #define SCSE_CAP_8BITMIME 0x0020 /* 8BITMIME */ #define SCSE_CAP_SIZE 0x0040 /* SIZE */ #define SCSE_CAP_ENHSTAT 0x0080 /* ENHANCEDSTATUSCODES */ #define SCSE_CAP_AUTH 0x0100 /* AUTH */ #define SCSE_CAP_STARTTLS 0x0200 /* STARTTLS */ #define SCSE_CAP_RSAD 0x0800 /* used RCPT status after dot */ #define SCSE_SET_CAP(sc_sess, cap) (sc_sess)->scse_cap |= (cap) #define SCSE_CLR_CAP(sc_sess, cap) (sc_sess)->scse_cap &= ~(cap) #define SCSE_IS_CAP(sc_sess, cap) (((sc_sess)->scse_cap & (cap)) != 0) typedef struct sc_mail_S sc_mail_T, *sc_mail_P; struct sc_mail_S { sm_str_P scm_pa; /* mail */ /* parameters?? */ smtp_status_T scm_st; /* status */ sm_str_P scm_reply; /* reply text */ /* enhanced status, reply text?? */ }; typedef struct sc_rcpt_S sc_rcpt_T, *sc_rcpt_P; typedef struct sc_rcpts_S sc_rcpts_T, *sc_rcpts_P; struct sc_rcpt_S { sm_str_P scr_pa; /* rcpt */ /* parameters?? */ rcpt_idx_T scr_idx; /* rcpt index */ smtp_status_T scr_st; /* status */ uint scr_flags; /* flags; see below */ sm_str_P scr_reply; /* reply text */ #if MTA_USE_TLS sm_conf_T *scr_cnf; tlsreq_cnf_T scr_tlsreq_cnf; #endif /* enhanced status, reply text?? */ TAILQ_ENTRY(sc_rcpt_S) scr_l; /* links */ }; /* recipient flags (scr_flags) */ #define SCR_FL_NONE 0x00000000 /* guess */ #define SCR_FL_RCVD 0x00000001 /* received from qmgr */ #define SCR_FL_SENT 0x00000002 /* sent to SMTP server */ #define SCR_FL_STAT 0x00000004 /* got status from SMTP server */ #define SCR_FL_LOGGED 0x00000010 /* status has been logged */ #define SCR_SET_FLAG(sc_rcpt, fl) (sc_rcpt)->scr_flags |= (fl) #define SCR_CLR_FLAG(sc_rcpt, fl) (sc_rcpt)->scr_flags &= ~(fl) #define SCR_IS_FLAG(sc_rcpt, fl) (((sc_rcpt)->scr_flags & (fl)) != 0) TAILQ_HEAD(sc_rcpts_S, sc_rcpt_S); /* operations on rcpt lists */ #define SC_RCPTS_INIT(rcpts) TAILQ_INIT(rcpts) #define SC_RCPTS_EMPTY(rcpts) TAILQ_EMPTY(rcpts) #define SC_RCPTS_FIRST(rcpts) TAILQ_FIRST(rcpts) #define SC_RCPTS_END(rcpts) TAILQ_END(rcpts) #define SC_RCPTS_NEXT(rcpts) TAILQ_NEXT(rcpts, scr_l) #define SC_RCPTS_INSERT_TAIL(rcpts, rcpt) TAILQ_INSERT_TAIL(rcpts, rcpt, scr_l) #define SC_RCPTS_INSERT_HEAD(rcpts, rcpt) TAILQ_INSERT_HEAD(rcpts, rcpt, scr_l) #define SC_RCPTS_REMOVE(rcpts, rcpt) TAILQ_REMOVE(rcpts, rcpt, scr_l) #define SC_RCPTS_REMOVE_FREE(ta, rcpts, rcpt) do { \ TAILQ_REMOVE((rcpts), (rcpt), scr_l); \ scr_free((ta), (rcpt)); \ } while (0) #define SM_IS_SC_TA(sc_ta) SM_REQUIRE_ISA((sc_ta), SM_SC_TA_MAGIC) /* SMTPC Transaction context */ struct sc_ta_S { sm_magic_T sm_magic; sc_sess_P scta_sess; /* pointer to session */ sm_rpool_P scta_rpool; sm_file_T *scta_cdb_fp; /* cdb fp */ sc_mail_P scta_mail; /* mail from */ sc_rcpts_T scta_rcpts; /* rcpts */ #if SC_PIPELINING sc_rcpt_P scta_rcpt_p; /* current rcpt for reply */ uint scta_rcpts_rcvd; /* # of recipients replies received */ #endif uint scta_rcpts_tot; /* number of recipients total */ uint scta_rcpts_snt; /* number of recipients sent */ uint scta_rcpts_ok; /* number of recipients ok */ uint scta_rcpts_dot; /* #rcpts still to collect after data */ uint scta_state; /* see below */ uint scta_flags; /* see below */ uint scta_err_state; /* state which caused an error: da.h */ smtp_status_T scta_status; /* SMTP status code (if applicable) */ /* add sm_ret_T scta_err_status; ? */ sessta_id_T scta_id; /* DA transaction id */ sessta_id_T scta_ssta_id; /* SMTPS transaction id (logging) */ sm_str_P scta_reply; /* reply text (data/dot) */ sm_str_P scta_cdb_id; /* CDB id */ sm_str_P scta_b_msg; /* bounce message (hack) */ size_t scta_msg_sz_b; /* message size (bytes) */ sm_hdrmodhd_P scta_hdrmodhd; }; /* ** Transaction states, these must be sorted! ** This is a combination of flags (bit values) and state (ordered values) */ #define SCTA_NONE 0x00000000 /* must be 0 */ #define SCTA_INIT 0x00000001 /* ta initialized */ #define SCTA_MAIL_S 0x00000002 /* sent MAIL */ #define SCTA_MAIL_R 0x00000004 /* received reply for MAIL */ #define SCTA_RCPT_S 0x00000010 /* sent RCPT */ #define SCTA_RCPT_R 0x00000020 /* received replies for RCPT */ #define SCTA_DATA_S 0x00000040 /* sent DATA */ #define SCTA_DATA_R 0x00000080 /* received reply for DATA */ #define SCTA_DOT_S 0x00000100 /* sent final dot */ #define SCTA_DOT_R 0x00000200 /* received reply for final dot */ #define SCTA_L_RCPT_R 0x00000400 /* received replies for LMTP RCPT */ #define SCTA_D_RCPT_R 0x00000800 /* rcvd replies for RCPT Status after dot */ #define SCTA_R_PERM 0x00001000 /* one RCPT had a perm.error */ #define SCTA_R_TEMP 0x00002000 /* one RCPT had a temp.error */ #define SCTA_FAIL_TEMP 0x00010000 /* ta temp failed */ #define SCTA_FAIL_PERM 0x00020000 /* ta perm failed */ #define SCTA_COMPLETE 0x00040000 /* ta completed */ #define SCTA_DOT_F_R 0x00080000 /* received final reply for dot (RSAD) */ #define SCTA_SET_STATE(sc_ta, fl) (sc_ta)->scta_state |= (fl) #define SCTA_CLR_STATE(sc_ta, fl) (sc_ta)->scta_state &= ~(fl) #define SCTA_IS_STATE(sc_ta, fl) (((sc_ta)->scta_state & (fl)) != 0) #define SCTA_FL_NONE 0x00000000 /* must be 0 */ /* see sm/da.h */ #define SCTA_FL_HDR_ONLY DA_FL_HDR_ONLY /* send bounce with headers only */ #define SCTA_FL_DSN_MIME DA_FL_DSN_MIME /* DSN in MIME format (not yet impl) */ #define SCTA_FL_DELAY 0x00000010 /* ta describes a delay DSN */ #define SCTA_FL_BOUNCE 0x00000020 /* ta describes a bounce */ #define SCTA_FL_DBOUNCE 0x00000040 /* ta describes a double bounce */ #define SCTA_FL_NO_BODY 0x00000080 /* send bounce without body */ #define SCTA_FL_CUT_HDR 0x00000200 /* cutoff at header has been done */ #define SCTA_FL_CUT_DOT 0x00000400 /* cutoff at dot has been done */ #define SCTA_FL_CDB_CUT (SCTA_FL_CUT_DOT|SCTA_FL_CUT_HDR) /* header scanning necessary for modifications */ #define SCTA_FL_HDR_SCAN 0x00001000 #define SCTA_FL_DSN (SCTA_FL_DELAY|SCTA_FL_BOUNCE|SCTA_FL_DBOUNCE) #define SCTA_SET_FLAG(sc_ta, fl) (sc_ta)->scta_flags |= (fl) #define SCTA_CLR_FLAG(sc_ta, fl) (sc_ta)->scta_flags &= ~(fl) #define SCTA_IS_FLAG(sc_ta, fl) (((sc_ta)->scta_flags & (fl)) != 0) void *sc_hdl_requests(void *arg); sm_ret_T sc_read_cnf(sc_ctx_P _sc_ctx, const char *_fn, sm_conf_T **_psmc); sc_t_ctx_P get_free_thr(sc_ctx_P _sc_ctx); sm_ret_T sc_sess_open(sc_t_ctx_P _sc_t_ctx); sm_ret_T sc_sess_close(sc_t_ctx_P _sc_t_ctx); sm_ret_T sc_one_ta(sc_t_ctx_P _sc_t_ctx); sm_ret_T sc_t_ctx_new(sc_ctx_P _sc_ctx, sc_t_ctx_P *_sc_t_ctx, uint _thr_id); sm_ret_T sc_t_ctx_free(sc_ctx_P _sc_ctx, sc_t_ctx_P _sc_t_ctx); sm_ret_T sc_t_ctx_clr(sc_t_ctx_P _sc_t_ctx); sm_ret_T sc_sess_new(sc_sess_P *_sc_sess, sc_t_ctx_P _sc_t_ctx); sm_ret_T sc_sess_free(sc_sess_P _sc_sess, sc_t_ctx_P _sc_t_ctx); sm_ret_T sc_sess_clr(sc_sess_P _sc_sess); sm_ret_T sc_ta_new(sc_ta_P *_sc_ta, sc_sess_P _sc_sess); sm_ret_T sc_ta_free(sc_ta_P _sc_ta); sm_ret_T sc_ta_clr(sc_ta_P _sc_ta); sm_ret_T sc_mail_new(sc_ta_P _sc_ta); sm_ret_T sc_mail_free(sc_ta_P _sc_ta); sm_ret_T sc_rcpts_new(sc_ta_P _sc_ta, sm_str_P _rcpt_pa, rcpt_idx_T _rcpt_idx, sc_rcpt_P *_prcpt); sm_ret_T sc_rcpt_free(sc_ta_P _sc_ta, sc_rcpt_P _addr); sm_ret_T sc_rcpts_free(sc_ta_P _sc_ta); sm_ret_T sc_hdrmod_new(sc_ta_P _sc_ta, sm_hdrmod_P *_psm_hdrmod); sm_ret_T sc_hdrmod_rm(sc_ta_P _sc_ta); #define SC_MAX_WAIT_THREADS(sc_ctx) ((sc_ctx)->scc_cnf.sc_cnf_max_wait_threads) #define SC_MIN_WAIT_THREADS(sc_ctx) ((sc_ctx)->scc_cnf.sc_cnf_min_wait_threads) #define SC_MAX_THREADS(sc_ctx) ((sc_ctx)->scc_cnf.sc_cnf_max_threads) #define SC_MAX_USED_THREADS(sc_ctx) ((sc_ctx)->scc_thrds_max_used) #define SC_WAIT_THREADS(sc_ctx) ((sc_ctx)->scc_thrds_wait) #define SC_BUSY_THREADS(sc_ctx) ((sc_ctx)->scc_thrds_busy) #define SC_IDLE_THREADS(sc_ctx) ((sc_ctx)->scc_thrds_idle) #define SC_CLOSING_THREADS(sc_ctx) ((sc_ctx)->scc_thrds_clsng) #define SC_AVAIL_THREADS(sc_ctx) (SC_WAIT_THREADS(sc_ctx) - SC_IDLE_THREADS(sc_ctx) - SC_CLOSING_THREADS(sc_ctx)) #define SC_TOTAL_THREADS(sc_ctx) (SC_WAIT_THREADS(sc_ctx) + SC_BUSY_THREADS(sc_ctx)) #define SC_RQST_COUNT(sc_ctx) ((sc_ctx)->scc_rqst_count) #if SC_STATS # define SC_BUSY(sc_t_ctx) ((sc_t_ctx)->sct_sc_ctx->scc_busy) # define SC_TOTAL(sc_t_ctx) ((sc_t_ctx)->sct_sc_ctx->scc_total) # define SC_MAIL_COUNT(sc_ctx) ((sc_ctx)->scc_mail_count) # define SC_RCPT_COUNT(sc_ctx) ((sc_ctx)->scc_rcpt_count) # define SC_TA_CNT_OK(sc_ctx) ((sc_ctx)->scc_ta_cnt_ok) # define SC_RCPT_CNT_OK(sc_ctx) ((sc_ctx)->scc_rcpt_cnt_ok) # define SC_SE_REUSE(sc_ctx) ((sc_ctx)->scc_reuse) # define SC_OPEN_SE(sc_ctx) ((sc_ctx)->scc_open_se) # define SC_MAX_OPEN_SE(sc_ctx) ((sc_ctx)->scc_max_open_se) #endif /* SC_STATS */ /* ** Number of file descriptors needed to handle one client session ** 1 client communication ** 1 data file */ #define SC_FD_PER_THREAD 2 #if SC_TIMING # define SC_DEBFP smioerr # if HAVE_GETHRTIME # define SC_HRT_DPRINTF(x) do \ { \ hrtime_t hrt; \ hrt = gethrtime(); \ sm_io_fprintf(SC_DEBFP, "r=%lld: ", hrt); \ sm_io_fprintf x; \ } while (0) # endif # if HAVE_GETHRVTIME # define SC_HRVT_DPRINTF(x) do \ { \ hrtime_t hrt; \ hrt = gethrvtime(); \ sm_io_fprintf(SC_DEBFP, "v=%lld: ", hrt); \ sm_io_fprintf x; \ } while (0) # endif # if HAVE_GETHRVTIME && HAVE_GETHRTIME # define SC_HRBT_DPRINTF(x) do \ { \ hrtime_t hrvt, hrt; \ hrt = gethrtime(); \ hrvt = gethrvtime(); \ sm_io_fprintf(SC_DEBFP, "r=%lld, v=%lld: ", hrt, hrvt); \ sm_io_fprintf x; \ } while (0) # elif HAVE_CLOCK_GETTIME # define SC_HRBT_DPRINTF(x) do \ { \ struct timespec tsr, tsv; \ int r; \ r = clock_gettime(CLOCK_MONOTONIC, &tsr); \ if (r != 0) timespecclear(&tsr); \ r = clock_gettime(CLOCK_PROF, &tsv); \ if (r != 0) timespecclear(&tsv); \ sm_io_fprintf(SC_DEBFP, "r=%d.%09ld, v=%d.%09ld: ", tsr.tv_sec, tsr.tv_nsec, tsv.tv_sec, tsv.tv_nsec); \ sm_io_fprintf x; \ } while (0) # endif #endif /* SC_TIMING */ #ifndef SC_HRT_DPRINTF # define SC_HRT_DPRINTF(x) #endif #ifndef SC_HRVT_DPRINTF # define SC_HRVT_DPRINTF(x) #endif #ifndef SC_HRBT_DPRINTF # define SC_HRBT_DPRINTF(x) #endif #endif /* SMTPC_H */