1 /* $NetBSD: qmgr_peer.c,v 1.2 2017/02/14 01:16:47 christos Exp $ */ 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 80 QMGR_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, (void *) 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 96 void 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 (*) (void *)) 0); 112 myfree((void *) peer); 113 } 114 115 /* qmgr_peer_find - lookup peer associated with given job and queue */ 116 117 QMGR_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 124 QMGR_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 135 QMGR_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