/*
 * Copyright (c) 2002-2005 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: s2q.h,v 1.53 2007/10/19 02:30:19 ca Exp $
 */

#ifndef S2Q_H
#define S2Q_H 1

#include "sm/generic.h"
#include "sm/socket.h"
#include "sm/sockcnf.h"
#include "sm/reccom.h"
#include "statethreads/st.h"
#include "sm/rcbst.h"
#include "sm/qmgrcomm.h"
#include "smtps-str.h"
#include "sm/mta.h"

#ifndef SSQ_DEBUG
# define SSQ_DEBUG	0
#endif

#if SSQ_DEBUG
# include <stdio.h>
# define SSQ_DPRINTF(x) do {			\
	time_t currt = st_time();		\
	sm_io_fprintf(smioerr, "%6ld: ", (long) currt);	\
	sm_io_fprintf x;				\
	} while (0)

#else /* SSQ_DEBUG */
# define SSQ_DPRINTF(x)
#endif /* SSQ_DEBUG */

/* basic size for RCB in s2q_ctx */
#define S2Q_RCB_SIZE	8192

struct s2q_ctx_S
{
	ss_ctx_P	 s2q_ss_ctx;	/* pointer back to ss_ctx */
	int		 s2q_status;	/* status */
	st_netfd_t	 s2q_fd;	/* fd for communication */
	st_mutex_t	 s2q_wr_mutex;	/* mutex for write */
	uint		 s2q_maxrcbs;	/* max. # of outstanding requests */
	uint		 s2q_currcbs;	/* current # of outstanding requests */

	/*
	**  Current index of "server".  This is used to keep track of
	**  "server" restarts to avoid using a "stale" connection.
	**  Problem: as there are multiple s2q_ctx's ss_sess_ctx should
	**  have multiple q_idx's. However, currently this is only used
	**  for pmilter, hence only that should be tested.
	**  A value of S2Q_ID_NONE means "match".
	*/

	int		 s2q_q_id;

	/* server type (S2Q_T_*): index in ss_sess_ctx->ssse_s2q_id[] */
	uint		 s2q_srv_type;

/*
**  The size of the next two arrays is equal to the number of maximum threads.
**  Therefore each thread can have one outstanding communication request.
**  The arrays are used to associate incoming RCBs with the appropriate
**  session (each thread handles one session); each RCB contains a session
**  (or transaction) id. Looking it up in s2q_sids leads to the session
**  which is stored at the same index in s2q_sess.
**  If a session can have more than one outstanding request, then the
**  the size of these arrays must be changed appropriately.
**  Note: a session uses ssse_s2q_idx to determine whether a reference to
**  it is stored in this array. If there are multiple outstanding requests,
**  then there needs to be a different way (e.g., multiple indices or some
**  other algorithm).
**  Note: as long as the 1-1 relation is maintained, we could use the
**  thread index of an smtps session context as index into these arrays.
**  However, currently an ss_sess_ctx does not have a thread index.
*/

	sessta_id_P	*s2q_sids;	/* array of session/transaction ids */
	ss_sess_P	*s2q_sess;	/* array of session ctx */
};

#define S2Q_ST_OK	0
#define S2Q_ST_IOERR	1
#define S2Q_ST_CLOSED	(-1)

/* use flags? */
#define S2Q_IS_IOERR(s2q_ctx)	(S2Q_ST_IOERR == (s2q_ctx)->s2q_status)
#define S2Q_SET_IOERR(s2q_ctx)	(s2q_ctx)->s2q_status = S2Q_ST_IOERR
#define S2Q_CLR_IOERR(s2q_ctx)	(s2q_ctx)->s2q_status = S2Q_ST_OK

#define S2Q_CONN_OK(ss_sess, s2q_ctx)	(S2Q_ST_OK == (s2q_ctx)->s2q_status)

/*
**  Check connection state (to qmgr/smar/pmilter).
**  Note: if you change the error codes in here, you must change
**  SSPM_TRY_AGAIN(ss_ctx) in smtps/pmilter.h
**  Note: sm_s2q_id_match() checks isn't necessary for a stateless server
**  like smar.
*/

#define S2Q_CHK_CONN_R(ss_sess, s2q_ctx)				\
do									\
{									\
	if (S2Q_ST_CLOSED == (s2q_ctx)->s2q_status)			\
		return sm_error_temp(SM_EM_SMTPS, SM_E_CONN_CLSD);	\
	if (!S2Q_CONN_OK((ss_sess), (s2q_ctx)))				\
		return sm_error_temp(SM_EM_SMTPS, EIO);			\
	if (!sm_s2q_id_match((ss_sess), (s2q_ctx)))			\
		return sm_error_temp(SM_EM_SMTPS, SM_E_WRONG_ID);	\
} while (0)

/* which type of server? */
#define S2Q_T_QMGR	SS_COMM_QMGR
#define S2Q_T_SMAR	SS_COMM_SMAR
#define S2Q_T_PMILTER	SS_COMM_PMILTER
#define S2Q_IS_STATELESS(srv_type)	(SS_COMM_SMAR == (srv_type))

bool	 sm_s2q_id_match(ss_sess_P _ss_sess, s2q_ctx_P _s2q_ctx);

sm_ret_T sm_s2q_create(s2q_ctx_P *_ps2q_ctx, ss_ctx_P _ss_ctx, uint _maxrcbs);
sm_ret_T sm_s2q_open(s2q_ctx_P _s2q_ctx, sockspec_P _sockspec, uint _wait4srv, uint _max_threads, uint _srv_type, uint32_t _flags);
sm_ret_T sm_s2q_init(s2q_ctx_P *_ps2q_ctx, ss_ctx_P _ss_ctx, sockspec_P _sockspec, uint _wait4srv, uint _max_threads, int _smtps_id, uint _maxrcbs, uint _srv_type, uint32_t _flags);
sm_ret_T sm_s2q_init_u(s2q_ctx_P *_ps2q_ctx, ss_ctx_P _ss_ctx, const char *_sockname, uint _wait4srv, uint _max_threads, int _smtps_id, uint _maxrcbs, uint _srv_type, uint32_t _flags);
sm_ret_T sm_s2q_stop(s2q_ctx_P _s2q_ctx);

sm_ret_T sm_s2q_nseid(ss_sess_P _ss_sess, s2q_ctx_P _s2q_ctx, sessta_id_P _sid);
sm_ret_T sm_s2q_cseid(ss_sess_P _ss_sess, s2q_ctx_P _s2q_ctx, sessta_id_P _sid);
sm_ret_T sm_s2q_1taid(ss_sess_P _ss_sess, s2q_ctx_P _s2q_ctx);
#if MTA_USE_PMILTER && 0
sm_ret_T sm_s2q_rcpts(ss_sess_P _ss_sess, s2q_ctx_P _s2q_ctx,
			uint _first_idx, uint _last_idx);
#endif
sm_ret_T sm_w4q2s_reply(ss_sess_P _sess, uint _tmo, s2q_ctx_P _s2q_ctx);

sm_ret_T sm_s2a_rcptid(ss_sess_P _ss_sess, s2q_ctx_P _s2a_ctx,
			sessta_id_P _tid, int _rcpt_idx,
			uint32_t _lt, uint32_t _lfl, sm_str_P _rcpt);
sm_ret_T sm_s2a_addr(ss_sess_P _ss_sess, s2q_ctx_P _s2a_ctx,
			sessta_id_P _tid, sm_str_P _addr, uint32_t _what, uint32_t _ltype,
			uint32_t _lflags);
sm_ret_T sm_s2a_clt(ss_sess_P _ss_sess, s2q_ctx_P _s2a_ctx,
			sessta_id_P _sid, sm_str_P _clt,
			uint32_t _what, uint32_t _ltype, uint32_t _lflags);
sm_ret_T sm_s2a_tls(ss_sess_P _ss_sess, s2q_ctx_P _s2a_ctx);
sm_ret_T sm_s2a_str(ss_sess_P _ss_sess, s2q_ctx_P _s2a_ctx, sessta_id_P _sid, sm_str_P _str, uint32_t _rt, uint32_t _lt, uint32_t _lfl);

sm_ret_T ss_clr_sess_rq(s2q_ctx_P _s2q_ctx, ss_sess_P _ss_sess);

sm_ret_T ss_add_rq(ss_sess_P _ss_sess, sessta_id_P _tid, s2q_ctx_P _s2q_ctx, uint *_pi);
sm_ret_T ss_send_rq(ss_sess_P _ss_sess, sessta_id_P _tid, s2q_ctx_P _s2q_ctx, sm_rcb_P _rcb, bool _reply);

#endif /* S2Q_H */


syntax highlighted by Code2HTML, v. 0.9.1