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