1/* $NetBSD$ */ 2 3/*++ 4/* NAME 5/* qmgr_peer 3 6/* SUMMARY 7/* per-job peers 8/* SYNOPSIS 9/* #include "qmgr.h" 10/* 11/* QMGR_PEER *qmgr_peer_create(job, queue) 12/* QMGR_JOB *job; 13/* QMGR_QUEUE *queue; 14/* 15/* QMGR_PEER *qmgr_peer_find(job, queue) 16/* QMGR_JOB *job; 17/* QMGR_QUEUE *queue; 18/* 19/* QMGR_PEER *qmgr_peer_obtain(job, queue) 20/* QMGR_JOB *job; 21/* QMGR_QUEUE *queue; 22/* 23/* void qmgr_peer_free(peer) 24/* QMGR_PEER *peer; 25/* 26/* QMGR_PEER *qmgr_peer_select(job) 27/* QMGR_JOB *job; 28/* 29/* DESCRIPTION 30/* These routines add/delete/manipulate per-job peers. 31/* Each peer corresponds to a specific job and destination. 32/* It is similar to per-transport queue structure, but groups 33/* only the entries of the given job. 34/* 35/* qmgr_peer_create() creates an empty peer structure for the named 36/* job and destination. It is an error to call this function 37/* if a peer for given combination already exists. 38/* 39/* qmgr_peer_find() looks up the peer for the named destination 40/* for the named job. A null result means that the peer 41/* was not found. 42/* 43/* qmgr_peer_obtain() looks up the peer for the named destination 44/* for the named job. If it doesn't exist yet, it creates it. 45/* 46/* qmgr_peer_free() disposes of a per-job peer after all 47/* its entries have been taken care of. It is an error to dispose 48/* of a peer still in use. 49/* 50/* qmgr_peer_select() attempts to find a peer of named job that 51/* has messages pending delivery. This routine implements 52/* round-robin search among job's peers. 53/* DIAGNOSTICS 54/* Panic: consistency check failure. 55/* LICENSE 56/* .ad 57/* .fi 58/* The Secure Mailer license must be distributed with this software. 59/* AUTHOR(S) 60/* Patrik Rak 61/* patrik@raxoft.cz 62/*--*/ 63 64/* System library. */ 65 66#include <sys_defs.h> 67 68/* Utility library. */ 69 70#include <msg.h> 71#include <htable.h> 72#include <mymalloc.h> 73 74/* Application-specific. */ 75 76#include "qmgr.h" 77 78/* qmgr_peer_create - create and initialize message peer structure */ 79 80QMGR_PEER *qmgr_peer_create(QMGR_JOB *job, QMGR_QUEUE *queue) 81{ 82 QMGR_PEER *peer; 83 84 peer = (QMGR_PEER *) mymalloc(sizeof(QMGR_PEER)); 85 peer->queue = queue; 86 peer->job = job; 87 QMGR_LIST_APPEND(job->peer_list, peer, peers); 88 htable_enter(job->peer_byname, queue->name, (char *) peer); 89 peer->refcount = 0; 90 QMGR_LIST_INIT(peer->entry_list); 91 return (peer); 92} 93 94/* qmgr_peer_free - release peer structure */ 95 96void qmgr_peer_free(QMGR_PEER *peer) 97{ 98 const char *myname = "qmgr_peer_free"; 99 QMGR_JOB *job = peer->job; 100 QMGR_QUEUE *queue = peer->queue; 101 102 /* 103 * Sanity checks. It is an error to delete a referenced peer structure. 104 */ 105 if (peer->refcount != 0) 106 msg_panic("%s: refcount: %d", myname, peer->refcount); 107 if (peer->entry_list.next != 0) 108 msg_panic("%s: entry list not empty: %s", myname, queue->name); 109 110 QMGR_LIST_UNLINK(job->peer_list, QMGR_PEER *, peer, peers); 111 htable_delete(job->peer_byname, queue->name, (void (*) (char *)) 0); 112 myfree((char *) peer); 113} 114 115/* qmgr_peer_find - lookup peer associated with given job and queue */ 116 117QMGR_PEER *qmgr_peer_find(QMGR_JOB *job, QMGR_QUEUE *queue) 118{ 119 return ((QMGR_PEER *) htable_find(job->peer_byname, queue->name)); 120} 121 122/* qmgr_peer_obtain - find/create peer associated with given job and queue */ 123 124QMGR_PEER *qmgr_peer_obtain(QMGR_JOB *job, QMGR_QUEUE *queue) 125{ 126 QMGR_PEER *peer; 127 128 if ((peer = qmgr_peer_find(job, queue)) == 0) 129 peer = qmgr_peer_create(job, queue); 130 return (peer); 131} 132 133/* qmgr_peer_select - select next peer suitable for delivery within given job */ 134 135QMGR_PEER *qmgr_peer_select(QMGR_JOB *job) 136{ 137 QMGR_PEER *peer; 138 QMGR_QUEUE *queue; 139 140 /* 141 * If we find a suitable site, rotate the list to enforce round-robin 142 * selection. See similar selection code in qmgr_transport_select(). 143 */ 144 for (peer = job->peer_list.next; peer; peer = peer->peers.next) { 145 queue = peer->queue; 146 if (queue->window > queue->busy_refcount && peer->entry_list.next != 0) { 147 QMGR_LIST_ROTATE(job->peer_list, peer, peers); 148 if (msg_verbose) 149 msg_info("qmgr_peer_select: %s %s %s (%d of %d)", 150 job->message->queue_id, queue->transport->name, queue->name, 151 queue->busy_refcount + 1, queue->window); 152 return (peer); 153 } 154 } 155 return (0); 156} 157