/* * 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. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: qm_gen_li.c,v 1.8 2006/10/02 05:07:49 ca Exp $") #include "sm/error.h" #include "sm/assert.h" #include "sm/io.h" #include "sm/rcb.h" #include "sm/qmgr.h" #include "sm/qmgr-int.h" #include "sm/rcbcomm.h" #include "qmgr.h" #include "log.h" /* ** QM_GEN_LI -- Handle new connections from SMTPS/SMTPC ** This runs as a (listen) task. ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code ** ** Last code review: 2003-10-17 16:33:39, see below ** Last code change: 2006-03-10 17:15:00 */ sm_ret_T qm_gen_li(sm_evthr_task_P tsk) { int fd, i, r; uint32_t j; sm_ret_T ret; sm_evthr_task_P task; qmgr_ctx_P qmgr_ctx; qm_gli_P qm_gli; qsm_gen_P qm_sm_ctx; SM_IS_EVTHR_TSK(tsk); SM_REQUIRE(tsk->evthr_t_nc != NULL); qm_gli = (qm_gli_P) tsk->evthr_t_actx; SM_IS_GLI(qm_gli); qmgr_ctx = qm_gli->qm_gli_qmgr_ctx; SM_IS_QMGR_CTX(qmgr_ctx); QM_LEV_DPRINTFC(QDC_Q2S, 2, (QM_DEBFP, "func=qm_gen_li, status=new_connection\n")); fd = tsk->evthr_t_nc->evthr_a_fd; if (!is_valid_fd(fd)) { sm_log_write(qmgr_ctx->qmgr_lctx, QM_LCAT_COMM, QM_LMOD_COMM, SM_LOG_ERROR, 4, "sev=ERROR, func=qm_gen_li, fd=%d", fd); return EVTHR_WAITQ; } r = pthread_mutex_lock(&qmgr_ctx->qmgr_mutex); SM_LOCK_OK(r); if (r != 0) { sm_log_write(qmgr_ctx->qmgr_lctx, QM_LCAT_COMM, QM_LMOD_COMM, SM_LOG_CRIT, 4, "sev=ERROR, func=qm_gen_li, lock=%d", r); goto error; } QM_LEV_DPRINTFC(QDC_Q2S, 8, (QM_DEBFP, "func=qm_gen_li, lock=gotit\n")); if (qm_gli->qm_gli_nfd >= QM_N_GLI(qmgr_ctx)) { /* too many: don't accept it */ /* maybe turn off accept job if max is reached?? */ sm_log_write(qmgr_ctx->qmgr_lctx, QM_LCAT_COMM, QM_LMOD_COMM, SM_LOG_ERROR, 4, "sev=ERROR, func=qm_gen_li, status=too_many_connections, current_connections=%d" , qm_gli->qm_gli_nfd); goto err2; } qm_sm_ctx = NULL; /* search for free ctx */ for (j = 1, i = 0; i < QM_N_GLI(qmgr_ctx); i++, j *= 2) { if ((qm_gli->qm_gli_used & j) == 0) { qm_gli->qm_gli_used |= j; qm_sm_ctx = (qsm_gen_P) qm_gli->qm_gli_ctx[i]; qm_sm_ctx->qsm_gen_status = QSS_ST_NONE; qm_sm_ctx->qsm_gen_id = QSS_ID_NONE; qm_sm_ctx->qsm_gen_bit = j; ret = sm_rcb_open_rcv(qm_sm_ctx->qsm_gen_com.rcbcom_rdrcb); if (sm_is_err(ret)) { sm_log_write(qmgr_ctx->qmgr_lctx, QM_LCAT_COMM, QM_LMOD_COMM, SM_LOG_ERROR, 4, "sev=ERROR, func=qm_gen_li, sm_rcb_open_rcv=%m" , ret); goto err3; } break; } } if (i >= QM_N_GLI(qmgr_ctx)) { /* see above */ sm_log_write(qmgr_ctx->qmgr_lctx, QM_LCAT_COMM, QM_LMOD_COMM, SM_LOG_ERROR, 4, "sev=ERROR, func=qm_gen_li, status=no_free_connection, current_connections=%d" , qm_gli->qm_gli_nfd); goto err2; } ret = sm_fd_nonblock(fd, true); if (sm_is_err(ret)) { sm_log_write(qmgr_ctx->qmgr_lctx, QM_LCAT_COMM, QM_LMOD_COMM, SM_LOG_ERROR, 4, "sev=ERROR, func=qm_gen_li, sm_fd_nonblock=%m" , ret); goto err3; } qm_gli->qm_gli_nfd++; /* start a task for the new connection */ ret = evthr_task_new(qmgr_ctx->qmgr_ev_ctx, &task, EVTHR_EV_RD, fd, NULL, qm_gli->qm_gli_fct, qm_sm_ctx); if (sm_is_err(ret)) { sm_log_write(qmgr_ctx->qmgr_lctx, QM_LCAT_COMM, QM_LMOD_COMM, SM_LOG_ERROR, 4, "sev=ERROR, func=qm_gen_li, evthr_task_new=%m" , ret); goto err3; } else QM_LEV_DPRINTFC(QDC_Q2S, 2, (QM_DEBFP, "func=qm_gen_li, fd=%d, task=%p\n", fd, task)); SM_IS_EVTHR_TSK(task); qm_sm_ctx->qsm_gen_com.rcbcom_tsk = task; #if EVTHR_PRIOS > 1 if (qmgr_smtps == qm_gli->qm_gli_fct) EVTHR_T_PRIO_SET(task, EVTHR_PRIOS - 1); #endif r = pthread_mutex_unlock(&qmgr_ctx->qmgr_mutex); SM_ASSERT(r == 0); return EVTHR_WAITQ; err3: qm_gli->qm_gli_used &= ~j; err2: r = pthread_mutex_unlock(&qmgr_ctx->qmgr_mutex); SM_ASSERT(r == 0); error: if (is_valid_fd(fd)) close(fd); return EVTHR_WAITQ; }