xref: /netbsd-src/external/ibm-public/postfix/dist/src/qmgr/qmgr_peer.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
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 
qmgr_peer_create(QMGR_JOB * job,QMGR_QUEUE * queue)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 
qmgr_peer_free(QMGR_PEER * peer)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 
qmgr_peer_find(QMGR_JOB * job,QMGR_QUEUE * queue)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 
qmgr_peer_obtain(QMGR_JOB * job,QMGR_QUEUE * queue)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 
qmgr_peer_select(QMGR_JOB * job)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