/*
* 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 <stdio.h>
# 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 */
syntax highlighted by Code2HTML, v. 0.9.1