1 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "director.h"
6 #include "director-host.h"
7
director_host_cmp(const struct director_host * b1,const struct director_host * b2)8 static int director_host_cmp(const struct director_host *b1,
9 const struct director_host *b2)
10 {
11 int ret;
12
13 ret = net_ip_cmp(&b1->ip, &b2->ip);
14 if (ret != 0)
15 return ret;
16 return (int)b1->port - (int)b2->port;
17 }
18
director_host_cmp_p(struct director_host * const * host1,struct director_host * const * host2)19 int director_host_cmp_p(struct director_host *const *host1,
20 struct director_host *const *host2)
21 {
22 return director_host_cmp(*host1, *host2);
23 }
24
25 struct director_host *
director_host_add(struct director * dir,const struct ip_addr * ip,in_port_t port)26 director_host_add(struct director *dir,
27 const struct ip_addr *ip, in_port_t port)
28 {
29 struct director_host *host;
30
31 i_assert(director_host_lookup(dir, ip, port) == NULL);
32
33 host = i_new(struct director_host, 1);
34 host->dir = dir;
35 host->refcount = 1;
36 host->ip = *ip;
37 host->ip_str = i_strdup(net_ip2addr(&host->ip));
38 host->port = port;
39 host->name = i_strdup_printf("%s:%u", host->ip_str, port);
40
41 array_push_back(&dir->dir_hosts, &host);
42
43 /* there are few enough directors that sorting after each
44 addition should be fine */
45 array_sort(&dir->dir_hosts, director_host_cmp_p);
46 return host;
47 }
48
director_host_free(struct director_host ** _host)49 void director_host_free(struct director_host **_host)
50 {
51 struct director_host *host = *_host;
52
53 i_assert(host->refcount == 1);
54
55 *_host = NULL;
56 director_host_unref(host);
57 }
58
director_host_ref(struct director_host * host)59 void director_host_ref(struct director_host *host)
60 {
61 i_assert(host->refcount > 0);
62 host->refcount++;
63 }
64
director_host_unref(struct director_host * host)65 void director_host_unref(struct director_host *host)
66 {
67 struct director_host *const *hosts;
68 unsigned int i, count;
69
70 i_assert(host->refcount > 0);
71
72 if (--host->refcount > 0)
73 return;
74
75 hosts = array_get(&host->dir->dir_hosts, &count);
76 for (i = 0; i < count; i++) {
77 if (hosts[i] == host) {
78 array_delete(&host->dir->dir_hosts, i, 1);
79 break;
80 }
81 }
82 i_free(host->name);
83 i_free(host->ip_str);
84 i_free(host);
85 }
86
director_host_restarted(struct director_host * host)87 void director_host_restarted(struct director_host *host)
88 {
89 host->last_seq = 0;
90 host->last_sync_seq = 0;
91 host->last_sync_seq_counter = 0;
92 host->last_sync_timestamp = 0;
93 }
94
95 struct director_host *
director_host_get(struct director * dir,const struct ip_addr * ip,in_port_t port)96 director_host_get(struct director *dir, const struct ip_addr *ip,
97 in_port_t port)
98 {
99 struct director_host *host;
100
101 host = director_host_lookup(dir, ip, port);
102 if (host == NULL)
103 host = director_host_add(dir, ip, port);
104 return host;
105 }
106
107 struct director_host *
director_host_lookup(struct director * dir,const struct ip_addr * ip,in_port_t port)108 director_host_lookup(struct director *dir, const struct ip_addr *ip,
109 in_port_t port)
110 {
111 struct director_host *host;
112
113 array_foreach_elem(&dir->dir_hosts, host) {
114 if (net_ip_compare(&host->ip, ip) && host->port == port)
115 return host;
116 }
117 return NULL;
118 }
119
120 struct director_host *
director_host_lookup_ip(struct director * dir,const struct ip_addr * ip)121 director_host_lookup_ip(struct director *dir, const struct ip_addr *ip)
122 {
123 struct director_host *host;
124
125 array_foreach_elem(&dir->dir_hosts, host) {
126 if (net_ip_compare(&host->ip, ip))
127 return host;
128 }
129 return NULL;
130 }
131
director_host_cmp_to_self(const struct director_host * b1,const struct director_host * b2,const struct director_host * self)132 int director_host_cmp_to_self(const struct director_host *b1,
133 const struct director_host *b2,
134 const struct director_host *self)
135 {
136 int ret;
137
138 if ((ret = director_host_cmp(b1, b2)) >= 0)
139 return ret == 0 ? 0 : -director_host_cmp_to_self(b2, b1, self);
140
141 /* order -> return:
142 self, b1, b2 -> b2
143 b1, self, b2 -> b1
144 b1, b2, self -> b2
145 */
146 if (director_host_cmp(self, b1) < 0)
147 return 1; /* self, b1, b2 */
148 if (director_host_cmp(self, b2) < 0)
149 return -1; /* b1, self, b2 */
150 return 1; /* b1, b2, self */
151 }
152
director_host_add_string(struct director * dir,const char * host)153 static void director_host_add_string(struct director *dir, const char *host)
154 {
155 struct ip_addr *ips;
156 in_port_t port;
157 unsigned int i, ips_count;
158
159 if (net_str2hostport(host, dir->self_port, &host, &port) < 0)
160 i_fatal("Invalid director host:port in '%s'", host);
161
162 if (net_gethostbyname(host, &ips, &ips_count) < 0)
163 i_fatal("Unknown director host: %s", host);
164
165 for (i = 0; i < ips_count; i++) {
166 if (director_host_lookup(dir, &ips[i], port) == NULL)
167 (void)director_host_add(dir, &ips[i], port);
168 }
169 }
170
director_host_add_from_string(struct director * dir,const char * hosts)171 void director_host_add_from_string(struct director *dir, const char *hosts)
172 {
173 T_BEGIN {
174 const char *const *tmp;
175
176 tmp = t_strsplit_spaces(hosts, " ");
177 for (; *tmp != NULL; tmp++)
178 director_host_add_string(dir, *tmp);
179 } T_END;
180
181 if (array_count(&dir->dir_hosts) == 0) {
182 /* standalone director */
183 struct ip_addr ip;
184
185 if (net_addr2ip("127.0.0.1", &ip) < 0)
186 i_unreached();
187 dir->self_host = director_host_add(dir, &ip, 0);
188 dir->self_host->self = TRUE;
189 }
190 }
191