0
|
1 /* Distributed Checksum Clearinghouse |
|
2 * |
|
3 * send a request from client to server |
|
4 * |
|
5 * Copyright (c) 2008 by Rhyolite Software, LLC |
|
6 * |
|
7 * This agreement is not applicable to any entity which sells anti-spam |
|
8 * solutions to others or provides an anti-spam solution as part of a |
|
9 * security solution sold to other entities, or to a private network |
|
10 * which employs the DCC or uses data provided by operation of the DCC |
|
11 * but does not provide corresponding data to other users. |
|
12 * |
|
13 * Permission to use, copy, modify, and distribute this software without |
|
14 * changes for any purpose with or without fee is hereby granted, provided |
|
15 * that the above copyright notice and this permission notice appear in all |
|
16 * copies and any distributed versions or copies are either unchanged |
|
17 * or not called anything similar to "DCC" or "Distributed Checksum |
|
18 * Clearinghouse". |
|
19 * |
|
20 * Parties not eligible to receive a license under this agreement can |
|
21 * obtain a commercial license to use DCC by contacting Rhyolite Software |
|
22 * at sales@rhyolite.com. |
|
23 * |
|
24 * A commercial license would be for Distributed Checksum and Reputation |
|
25 * Clearinghouse software. That software includes additional features. This |
|
26 * free license for Distributed ChecksumClearinghouse Software does not in any |
|
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse |
|
28 * software |
|
29 * |
|
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL |
|
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
|
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC |
|
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES |
|
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
37 * SOFTWARE. |
|
38 * |
|
39 * Rhyolite Software DCC 1.3.103-1.198 $Revision$ |
|
40 */ |
|
41 |
|
42 #include "dcc_clnt.h" |
|
43 #ifdef USE_POLL |
|
44 #include <poll.h> |
|
45 #endif |
|
46 #ifdef HAVE_ARPA_NAMESER_H |
|
47 #include <arpa/nameser.h> |
|
48 #endif |
|
49 #ifdef HAVE_RESOLV_H |
|
50 #include <resolv.h> |
|
51 #endif |
|
52 |
|
53 DCC_CLNT_INFO *dcc_clnt_info; /* memory mapped shared data */ |
|
54 u_char dcc_all_srvrs = 0; /* try to contact all servers */ |
|
55 |
|
56 /* #define CLNT_LOSSES */ |
|
57 #ifdef CLNT_LOSSES |
|
58 static u_int clnt_losses; |
|
59 #endif |
|
60 |
|
61 u_char dcc_clnt_debug; |
|
62 int dcc_debug_ttl; |
|
63 |
|
64 |
|
65 #define AGE_AVG(_v,_n,_a,_b) ((_v) = ((_v)*_a + (_n)*_b + (_a+_b)/2)/(_a+_b)) |
|
66 |
|
67 /* send NOPs to measure the RTTs to servers when the current server |
|
68 * becomes slow this often */ |
|
69 #define FAST_RTT_SECS (15*60) |
|
70 |
|
71 |
|
72 char dcc_clnt_hostname[MAXHOSTNAMELEN]; /* local hostname */ |
|
73 static u_int32_t dcc_clnt_hid; /* our DCC host-ID */ |
|
74 |
|
75 |
|
76 /* Each client knows about one or more servers, lest the current server |
|
77 * crash. To ensure that counts of spam accumulate as quickly as possible, |
|
78 * all of the processes on a client try to use a single server. The |
|
79 * closest (or fastest) server is preferred. It is desirable for the |
|
80 * servers to convert the hostnames of the servers to IP addresses |
|
81 * frequently enough to track changes in address records, but not so |
|
82 * often that a lot of time is wasted on the DNS. |
|
83 * |
|
84 * All of that implies that independent processes on the client need to |
|
85 * cooperate in measuring the round trip time to the servers and maintaining |
|
86 * their IP addresses. On UNIX systems, this is accomplished with mmap() |
|
87 * and a well known file. |
|
88 * |
|
89 * The DCC client uses 3 locks: |
|
90 * 1. mutex to ensure that only one thread in process sends bursts of NOPs |
|
91 * to measure RTTs or resolves DNS names |
|
92 * 2. mutex protecting the shared information in the map file for threads |
|
93 * within a process |
|
94 * 3. fcntl() lock on the file to protect the shared information among processes |
|
95 * |
|
96 * To avoid ABBA deadlocks, the locks are always sought in that order. |
|
97 * For most operaitons, only #2/#3 is needed. Sometimes only #2. |
|
98 * |
|
99 * Some systems have broken fcntl() locking (e.g. NFS in Solaris). |
|
100 * They lock the entire file. */ |
|
101 |
|
102 |
|
103 /* the contexts must be locked to read or change these values */ |
|
104 static int info_fd = -1; |
|
105 #ifdef DCC_WIN32 |
|
106 HANDLE info_map = INVALID_HANDLE_VALUE; |
|
107 #endif |
|
108 DCC_PATH dcc_info_nm; |
|
109 |
|
110 /* info_locked is set when the file system lock on changing the mapped file is |
|
111 * held. The contexts must be locked while info_locked is set, as well as |
|
112 * when it is checked or changed. */ |
|
113 static u_char info_locked; |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 /* Get the RTT used to pick servers. |
|
119 * It includes the local bias and the penalty for version mismatches */ |
|
120 static int |
|
121 effective_rtt(const DCC_SRVR_CLASS *class, const DCC_SRVR_ADDR *ap) |
|
122 { |
|
123 NAM_INX nam_inx; |
|
124 int rtt; |
|
125 |
|
126 rtt = ap->rtt; |
|
127 if (rtt >= DCC_MAX_RTT) |
|
128 return DCC_RTT_BAD; |
|
129 |
|
130 nam_inx = ap->nam_inx; |
|
131 if (!GOOD_NAM(nam_inx)) |
|
132 return DCC_RTT_BAD; |
|
133 |
|
134 rtt += class->nms[nam_inx].rtt_adj; |
|
135 /* penalize servers with strange versions */ |
|
136 if (ap->srvr_pkt_vers < DCC_PKT_VERSION |
|
137 #ifdef DCC_PKT_VERSION7 |
|
138 /* protocol version 7 and 8 are the same for the free code */ |
|
139 && ap->srvr_pkt_vers+1 != DCC_PKT_VERSION |
|
140 #endif |
|
141 && ap->srvr_id != DCC_ID_INVALID) |
|
142 rtt += DCC_RTT_VERS_ADJ; |
|
143 |
|
144 if (rtt >= DCC_RTT_BAD) |
|
145 return DCC_RTT_BAD; |
|
146 return rtt; |
|
147 } |
|
148 |
|
149 |
|
150 |
|
151 static inline u_char |
|
152 good_rtt(const DCC_SRVR_CLASS *class) |
|
153 { |
|
154 int rtt; |
|
155 |
|
156 if (!HAVE_SRVR(class)) |
|
157 return 0; |
|
158 |
|
159 rtt = effective_rtt(class, &class->addrs[class->srvr_inx]); |
|
160 if (rtt > class->avg_thold_rtt) |
|
161 return 0; |
|
162 |
|
163 return 1; |
|
164 } |
|
165 |
|
166 |
|
167 #define AP2CLASS(ap) DCC_GREY2CLASS(ap >= dcc_clnt_info->grey.addrs) |
|
168 |
|
169 |
|
170 /* compare addresses while trying to ignore IPv4 vs. IPv6 details */ |
|
171 static u_char /* 0=the addresses are equal */ |
|
172 dcc_cmp_ap2su(const DCC_SRVR_ADDR *ap, const DCC_SOCKU *su) |
|
173 { |
|
174 DCC_SRVR_ADDR ap4; |
|
175 struct in_addr su_addr4; |
|
176 |
|
177 if (ap->ip.port != DCC_SU_PORT(su)) |
|
178 return 1; |
|
179 |
|
180 if (ap->ip.family == AF_INET6 |
|
181 && dcc_ipv6toipv4(&ap4.ip.u.v4, &ap->ip.u.v6)) { |
|
182 ap4.ip.family = AF_INET; |
|
183 ap = &ap4; |
|
184 } |
|
185 |
|
186 if (su->sa.sa_family == AF_INET) { |
|
187 return (ap->ip.family != AF_INET |
|
188 || ap->ip.u.v4.s_addr != su->ipv4.sin_addr.s_addr); |
|
189 } |
|
190 |
|
191 if (dcc_ipv6toipv4(&su_addr4, &su->ipv6.sin6_addr)) { |
|
192 return (ap->ip.family != AF_INET |
|
193 || ap->ip.u.v4.s_addr != su_addr4.s_addr); |
|
194 } |
|
195 |
|
196 if (ap->ip.family != AF_INET6) |
|
197 return 1; |
|
198 |
|
199 /* both are real IPv6 and not ::1 */ |
|
200 return memcmp(&ap->ip.u.v6, &su->ipv6.sin6_addr, sizeof(ap->ip.u.v6)); |
|
201 } |
|
202 |
|
203 |
|
204 |
|
205 int |
|
206 dcc_ap2str_opt(char *buf, int buf_len, |
|
207 const DCC_SRVR_CLASS *class, u_char inx, |
|
208 char port_str) /* '\0' or '-' */ |
|
209 { |
|
210 const DCC_SRVR_ADDR *ap; |
|
211 char *buf1; |
|
212 int len; |
|
213 |
|
214 ap = &class->addrs[inx]; |
|
215 dcc_ip2str(buf, buf_len, &ap->ip); |
|
216 |
|
217 len = strlen(buf); |
|
218 buf1 = buf+len; |
|
219 buf_len -= len; |
|
220 if (ap->ip.port == DCC_CLASS2PORT(class)) { |
|
221 if (port_str) { |
|
222 if (buf_len >= 1) { |
|
223 *buf1 = ','; |
|
224 if (buf_len >= 2) |
|
225 *++buf1 = port_str; |
|
226 *++buf1 = '\0'; |
|
227 } |
|
228 } |
|
229 } else if (buf_len > 0) { |
|
230 len = snprintf(buf1, buf_len, ",%d", ntohs(ap->ip.port)); |
|
231 if (len >= buf_len) |
|
232 len = buf_len-1; |
|
233 buf1 += len; |
|
234 } |
|
235 |
|
236 return buf1-buf; |
|
237 } |
|
238 |
|
239 |
|
240 |
|
241 static const char * |
|
242 addr2str(char *buf, u_int buf_len, const DCC_SRVR_CLASS *class, |
|
243 int addrs_gen, const DCC_SRVR_ADDR *ap, const DCC_SOCKU *sup) |
|
244 { |
|
245 DCC_SOCKU su; |
|
246 char str[DCC_SU2STR_SIZE]; |
|
247 const char *host; |
|
248 |
|
249 if (class->gen == addrs_gen) { |
|
250 if (!sup) { |
|
251 dcc_mk_su(&su, ap->ip.family, &ap->ip.u, ap->ip.port); |
|
252 sup = &su; |
|
253 } |
|
254 dcc_su2str(str, sizeof(str), sup); |
|
255 if (GOOD_NAM(ap->nam_inx) |
|
256 && (host = class->nms[ap->nam_inx].hostname, |
|
257 !strncmp(host, str, strlen(host)))) { |
|
258 snprintf(buf, buf_len, "%s (%s)", host, str); |
|
259 } else { |
|
260 snprintf(buf, buf_len, "%s", str); |
|
261 } |
|
262 |
|
263 } else if (sup) { |
|
264 dcc_su2str(buf, buf_len, sup); |
|
265 |
|
266 } else { |
|
267 snprintf(buf, buf_len, DCC_IS_GREY_STR(class)); |
|
268 } |
|
269 return buf; |
|
270 } |
|
271 |
|
272 |
|
273 |
|
274 /* display or log the current error message if debugging */ |
|
275 static inline void |
|
276 flush_emsg(DCC_EMSG emsg, u_char debug) |
|
277 { |
|
278 if (!emsg) |
|
279 return; |
|
280 if (!debug) |
|
281 return; |
|
282 if (*emsg != '\0') { |
|
283 dcc_trace_msg("%s", emsg); |
|
284 *emsg = '\0'; |
|
285 } |
|
286 } |
|
287 |
|
288 |
|
289 |
|
290 /* display or prepare a new, less interesting error message if we do not have |
|
291 * a buffer or if there is no old, presumably more important message. */ |
|
292 static void PATTRIB(3,4) |
|
293 extra_pemsg(int ex_code, DCC_EMSG emsg, const char *msg, ...) |
|
294 { |
|
295 va_list args; |
|
296 |
|
297 flush_emsg(emsg, dcc_clnt_debug); |
|
298 if (!emsg || *emsg == '\0') { |
|
299 va_start(args, msg); |
|
300 dcc_vpemsg(ex_code, emsg, msg, args); |
|
301 va_end(args); |
|
302 } |
|
303 } |
|
304 |
|
305 |
|
306 |
|
307 static void |
|
308 trace_perf(const char *msg, const DCC_SRVR_ADDR *ap) |
|
309 { |
|
310 DCC_SRVR_CLASS *class; |
|
311 char abuf[60]; |
|
312 char rbuf[30]; |
|
313 |
|
314 class = AP2CLASS(ap); |
|
315 if (!GOOD_NAM(ap->nam_inx) |
|
316 || class->nms[ap->nam_inx].rtt_adj == 0) { |
|
317 rbuf[0] = 0; |
|
318 } else if (ap->srvr_pkt_vers < DCC_PKT_VERSION |
|
319 && ap->srvr_id != DCC_ID_INVALID) { |
|
320 snprintf(rbuf, sizeof(rbuf), "%+d+%d", |
|
321 class->nms[ap->nam_inx].rtt_adj/1000, |
|
322 DCC_RTT_VERS_ADJ/1000); |
|
323 } else { |
|
324 snprintf(rbuf, sizeof(rbuf), "%+d", |
|
325 class->nms[ap->nam_inx].rtt_adj/1000); |
|
326 } |
|
327 |
|
328 if (ap->rtt == DCC_RTT_BAD) { |
|
329 dcc_trace_msg("%s %s server %s with unknown RTT", |
|
330 msg, DCC_IS_GREY_STR(class), |
|
331 addr2str(abuf, sizeof(abuf), class, |
|
332 class->gen, ap, 0)); |
|
333 } else if (ap->total_xmits == 0) { |
|
334 dcc_trace_msg("%s %s server %s with %.2f%s ms RTT," |
|
335 " %d ms queue wait", |
|
336 msg, DCC_IS_GREY_STR(class), |
|
337 addr2str(abuf, sizeof(abuf), class, |
|
338 class->gen, ap, 0), |
|
339 ap->rtt/1000.0, rbuf, |
|
340 ap->srvr_wait/1000); |
|
341 } else { |
|
342 dcc_trace_msg("%s %s server %s with %.0f%%" |
|
343 " of %d requests answered," |
|
344 " %.2f%s ms RTT, %d ms queue wait", |
|
345 msg, DCC_IS_GREY_STR(class), |
|
346 addr2str(abuf, sizeof(abuf), class, |
|
347 class->gen, ap, 0), |
|
348 (ap->total_resps*100.0)/ap->total_xmits, |
|
349 ap->total_xmits, |
|
350 ap->rtt/1000.0, rbuf, |
|
351 ap->srvr_wait/1000); |
|
352 } |
|
353 } |
|
354 |
|
355 |
|
356 |
|
357 /* If the socket isn't always connected, it can receive |
|
358 * datagrams from almost everywhere (for example, a DNS |
|
359 * datagram could leak-in if the local port range is small |
|
360 * and the local port has been recently doing DNS queries |
|
361 * in its previous life). |
|
362 * |
|
363 * If the socket is connected, it can still receive |
|
364 * datagrams not belonging to the connection per se. This |
|
365 * will happen if it has been disconnected recently and there |
|
366 * was pending data in the socket's queue. |
|
367 * |
|
368 * Before complaining, check that this datagram seems to be a response |
|
369 * to something we sent */ |
|
370 static void PATTRIB(5,6) |
|
371 trace_bad_packet(const DCC_XLOG *xlog, const DCC_SOCKU *su, |
|
372 const DCC_OP_RESP *resp, int resp_len, const char *p, ...) |
|
373 { |
|
374 const DCC_XLOG_ENTRY *xloge; |
|
375 va_list args; |
|
376 char msgbuf[80]; |
|
377 char pktbuf[9*10]; |
|
378 int i, j, l; |
|
379 |
|
380 if (!dcc_clnt_debug && xlog && su) { |
|
381 for (xloge = xlog->base; ; ++xloge) { |
|
382 /* forget the error message if not from a DCC server */ |
|
383 if (xloge >= xlog->next) |
|
384 return; |
|
385 |
|
386 /* Don't check this server entry if we haven't |
|
387 * transmitted anything to this host. */ |
|
388 if (xloge->op_nums.t == DCC_OP_NUMS_NULL) |
|
389 continue; |
|
390 |
|
391 /* is the packet from this server? */ |
|
392 if (!memcmp(su, &xloge->su, sizeof(*su))) |
|
393 break; |
|
394 } |
|
395 } |
|
396 |
|
397 va_start(args, p); |
|
398 vsnprintf(msgbuf, sizeof(msgbuf), p, args); |
|
399 va_end(args); |
|
400 for (i = 0, j = 0; (i+1)*ISZ(resp->w[0]) <= resp_len; ++i) { |
|
401 l = snprintf(&pktbuf[j], sizeof(pktbuf)-j, " %08x", resp->w[i]); |
|
402 if (l < 9) |
|
403 break; |
|
404 j += l; |
|
405 } |
|
406 dcc_error_msg("%s;%s", msgbuf, pktbuf); |
|
407 } |
|
408 |
|
409 |
|
410 |
|
411 /* Compute the delay before the next retransmission |
|
412 * It always should be long enough for the DCC server to do some disk |
|
413 * operations even if the server and network have usually been faster. */ |
|
414 static int |
|
415 retrans_time(int rtt, u_int xmit_num) |
|
416 { |
|
417 u_int backoff; |
|
418 |
|
419 if (rtt < DCC_MIN_RTT) |
|
420 rtt = DCC_MIN_RTT; |
|
421 backoff = rtt << xmit_num; /* exponential backoff */ |
|
422 backoff += DCC_DCCD_DELAY; /* varying server & network load */ |
|
423 if (backoff > DCC_MAX_RTT) |
|
424 backoff = DCC_MAX_RTT; |
|
425 return backoff; |
|
426 } |
|
427 |
|
428 |
|
429 |
|
430 static void |
|
431 get_start_time(DCC_CLNT_CTXT *ctxt) |
|
432 { |
|
433 gettimeofday(&ctxt->start, 0); |
|
434 ctxt->now = ctxt->start; |
|
435 ctxt->now_us = 0; |
|
436 } |
|
437 |
|
438 |
|
439 |
|
440 static u_char /* 1=ok, 0=time jumped */ |
|
441 get_now(DCC_EMSG emsg, DCC_CLNT_CTXT *ctxt) |
|
442 { |
|
443 gettimeofday(&ctxt->now, 0); |
|
444 ctxt->now_us = tv_diff2us(&ctxt->now, &ctxt->start); |
|
445 if (ctxt->now_us >= 0 && ctxt->now_us < FOREVER_US) |
|
446 return 1; |
|
447 |
|
448 /* ignore tiny reverse time jumps on some systems such as BSD/OS 4.1 */ |
|
449 if (ctxt->now_us < 0 |
|
450 && ctxt->now_us > -1000) { |
|
451 ctxt->now = ctxt->start; |
|
452 ctxt->now_us = 0; |
|
453 return 1; |
|
454 } |
|
455 |
|
456 dcc_pemsg(EX_OSERR, emsg, |
|
457 "clock changed an impossible %.6f seconds", |
|
458 (ctxt->now.tv_sec - ctxt->start.tv_sec) * 1.0 |
|
459 + ((ctxt->now.tv_usec - ctxt->start.tv_usec)*1.0)/FOREVER_US); |
|
460 ctxt->now = ctxt->start; |
|
461 ctxt->now_us = 0; |
|
462 return 0; |
|
463 } |
|
464 |
|
465 |
|
466 |
|
467 static double |
|
468 get_age(const DCC_CLNT_CTXT *ctxt) |
|
469 { |
|
470 struct timeval now; |
|
471 |
|
472 gettimeofday(&now, 0); |
|
473 return tv_diff2us(&now, &ctxt->start)/(DCC_US*1.0); |
|
474 } |
|
475 |
|
476 |
|
477 |
|
478 #ifdef DCC_DEBUG_CLNT_LOCK |
|
479 void |
|
480 assert_info_locked(void) |
|
481 { |
|
482 assert_ctxts_locked(); |
|
483 if (!info_locked) |
|
484 dcc_logbad(EX_SOFTWARE, "don't have info locked"); |
|
485 } |
|
486 |
|
487 |
|
488 |
|
489 void |
|
490 assert_info_unlocked(void) |
|
491 { |
|
492 if (info_locked) |
|
493 dcc_logbad(EX_SOFTWARE, "have info locked"); |
|
494 } |
|
495 #endif |
|
496 |
|
497 |
|
498 /* Unlock the shared memory for other processes. |
|
499 * The contexts must be locked */ |
|
500 u_char /* 0=failed 1=ok */ |
|
501 dcc_info_unlock(DCC_EMSG emsg) |
|
502 { |
|
503 assert_ctxts_locked(); |
|
504 #ifdef DCC_DEBUG_CLNT_LOCK |
|
505 assert_info_locked(); |
|
506 #else |
|
507 if (!info_locked) |
|
508 return 1; |
|
509 #endif |
|
510 |
|
511 info_locked = 0; |
|
512 return dcc_unlock_fd(emsg, info_fd, DCC_LOCK_ALL_FILE, |
|
513 "info ", dcc_info_nm); |
|
514 } |
|
515 |
|
516 |
|
517 |
|
518 /* Lock the shared memory so we can read and perhaps change it |
|
519 * The contexts must be locked */ |
|
520 u_char /* 0=failed, 1=ok */ |
|
521 dcc_info_lock(DCC_EMSG emsg) |
|
522 { |
|
523 assert_ctxts_locked(); |
|
524 |
|
525 if (info_locked) { |
|
526 #ifdef DCC_DEBUG_CLNT_LOCK |
|
527 dcc_logbad(EX_SOFTWARE, "info already locked"); |
|
528 #endif |
|
529 return 1; |
|
530 } |
|
531 |
|
532 if (!dcc_exlock_fd(emsg, info_fd, DCC_LOCK_ALL_FILE, 60, |
|
533 "info ", dcc_info_nm)) |
|
534 return 0; |
|
535 |
|
536 info_locked = 1; |
|
537 return 1; |
|
538 } |
|
539 |
|
540 |
|
541 |
|
542 static u_char |
|
543 unmap_info(DCC_EMSG emsg) |
|
544 { |
|
545 #ifdef DCC_WIN32 |
|
546 win32_unmap(&info_map, dcc_clnt_info, dcc_info_nm); |
|
547 #else |
|
548 if (0 > munmap((void *)dcc_clnt_info, sizeof(*dcc_clnt_info))) { |
|
549 dcc_pemsg(EX_OSERR, emsg, "munmap(%s): %s", |
|
550 dcc_info_nm, ERROR_STR()); |
|
551 dcc_clnt_info = 0; |
|
552 return 0; |
|
553 } |
|
554 #endif |
|
555 dcc_clnt_info = 0; |
|
556 return 1; |
|
557 } |
|
558 |
|
559 |
|
560 |
|
561 /* Unmap and close the shared info |
|
562 * The contexts must be locked but not the info */ |
|
563 u_char /* 0=something wrong, 1=all over */ |
|
564 dcc_unmap_close_info(DCC_EMSG emsg) /* cleared of stale messages */ |
|
565 { |
|
566 u_char result = 1; |
|
567 |
|
568 assert_ctxts_locked(); |
|
569 assert_info_unlocked(); |
|
570 |
|
571 if (!dcc_clnt_info) |
|
572 return result; |
|
573 |
|
574 if (!unmap_info(emsg)) |
|
575 result = 0; |
|
576 |
|
577 if (0 > close(info_fd)) { |
|
578 extra_pemsg(EX_IOERR, emsg, "close(%s): %s", |
|
579 dcc_info_nm, ERROR_STR()); |
|
580 result = 0; |
|
581 } |
|
582 info_fd = -1; |
|
583 |
|
584 return result; |
|
585 } |
|
586 |
|
587 |
|
588 |
|
589 /* discover our host ID if we do not already know it */ |
|
590 static u_char |
|
591 get_clnt_hid(DCC_EMSG emsg) |
|
592 { |
|
593 struct timeval now; |
|
594 int i; |
|
595 u_char result; |
|
596 |
|
597 if (dcc_clnt_hid != 0) |
|
598 return 1; |
|
599 |
|
600 #ifdef HAVE_GETHOSTID |
|
601 dcc_clnt_hid = gethostid(); |
|
602 #endif |
|
603 /* add the host name even if we have a hostid in case the hostid |
|
604 * is a commonl used RFC 1918 IP address */ |
|
605 if (0 > gethostname(dcc_clnt_hostname, sizeof(dcc_clnt_hostname)-1)) { |
|
606 dcc_pemsg(EX_NOHOST, emsg, "gethostname(): %s", ERROR_STR()); |
|
607 /* do the best we can without a hostname */ |
|
608 gettimeofday(&now, 0); |
|
609 dcc_clnt_hid = now.tv_sec + now.tv_usec; |
|
610 result = 0; |
|
611 } else if (dcc_clnt_hostname[0] == '\0') { |
|
612 dcc_pemsg(EX_NOHOST, emsg, "null hostname from gethostname()"); |
|
613 /* do the best we can without a hostname */ |
|
614 gettimeofday(&now, 0); |
|
615 dcc_clnt_hid = now.tv_sec + now.tv_usec; |
|
616 result = 0; |
|
617 } else { |
|
618 for (i = 0; i < ISZ(dcc_clnt_hostname); ++i) { |
|
619 if (!dcc_clnt_hostname[i]) |
|
620 break; |
|
621 dcc_clnt_hid += dcc_clnt_hostname[i]*i; |
|
622 } |
|
623 result = 1; |
|
624 } |
|
625 |
|
626 /* this should almost never happen, but it could */ |
|
627 if (dcc_clnt_hid == 0) |
|
628 dcc_clnt_hid = 1; |
|
629 return result; |
|
630 } |
|
631 |
|
632 |
|
633 |
|
634 /* write a new DCC map file */ |
|
635 u_char |
|
636 dcc_create_map(DCC_EMSG emsg, |
|
637 const DCC_PATH map_nm0, |
|
638 int *pfd, /* leave open & unlocked FD here */ |
|
639 const DCC_SRVR_NM *dcc_nms, int dcc_nms_len, |
|
640 const DCC_SRVR_NM *grey_nms, int grey_nms_len, |
|
641 const DCC_IP *src, |
|
642 u_char info_flags) /* DCC_INFO_FG_* */ |
|
643 { |
|
644 static int op_nums_r; |
|
645 DCC_CLNT_INFO info_clear; |
|
646 int fd; |
|
647 u_char created; |
|
648 DCC_PATH map_nm; |
|
649 int i; |
|
650 |
|
651 if (pfd && (fd = *pfd) >= 0) { |
|
652 created = 0; |
|
653 } else { |
|
654 if (!fnm2rel(map_nm, map_nm0, 0)) { |
|
655 dcc_pemsg(EX_IOERR, emsg, "long map name \"%s\"", |
|
656 map_nm); |
|
657 return 0; |
|
658 } |
|
659 fd = open(map_nm, O_RDWR|O_CREAT|O_EXCL, 0600); |
|
660 if (fd < 0) { |
|
661 dcc_pemsg(EX_IOERR, emsg, "open(%s): %s", |
|
662 map_nm, ERROR_STR()); |
|
663 return 0; |
|
664 } |
|
665 created = 1; |
|
666 } |
|
667 |
|
668 memset(&info_clear, 0, sizeof(info_clear)); |
|
669 strcpy(info_clear.version, DCC_MAP_INFO_VERSION); |
|
670 |
|
671 if (dcc_nms_len != 0) { |
|
672 if (dcc_nms_len > DCC_MAX_SRVR_NMS) |
|
673 dcc_nms_len = DCC_MAX_SRVR_NMS; |
|
674 memcpy(info_clear.dcc.nms, dcc_nms, |
|
675 sizeof(info_clear.dcc.nms[0])*dcc_nms_len); |
|
676 } |
|
677 info_clear.dcc.srvr_inx = NO_SRVR; |
|
678 |
|
679 if (grey_nms_len != 0) { |
|
680 if (grey_nms_len > DCC_MAX_SRVR_NMS) |
|
681 grey_nms_len = DCC_MAX_SRVR_NMS; |
|
682 memcpy(info_clear.grey.nms, grey_nms, |
|
683 sizeof(info_clear.grey.nms[0])*grey_nms_len); |
|
684 } |
|
685 info_clear.grey.srvr_inx = NO_SRVR; |
|
686 |
|
687 if (src != 0) |
|
688 info_clear.src = *src; |
|
689 |
|
690 info_clear.flags = info_flags; |
|
691 if (!get_clnt_hid(emsg)) { |
|
692 close(fd); |
|
693 if (pfd) |
|
694 *pfd = -1; |
|
695 if (created) |
|
696 unlink(map_nm); |
|
697 return 0; |
|
698 } |
|
699 |
|
700 /* ensure that we have a new report ID even if we |
|
701 * are repeatedly recreating a temporary map file */ |
|
702 if (dcc_clnt_info) |
|
703 op_nums_r += dcc_clnt_info->proto_hdr.op_nums.r; |
|
704 info_clear.proto_hdr.op_nums.r = ++op_nums_r; |
|
705 |
|
706 i = write(fd, &info_clear, sizeof(info_clear)); |
|
707 if (i != ISZ(info_clear)) { |
|
708 if (i < 0) |
|
709 dcc_pemsg(EX_SOFTWARE, emsg, "write(%s): %s", |
|
710 map_nm, ERROR_STR()); |
|
711 else |
|
712 dcc_pemsg(EX_IOERR, emsg, |
|
713 "write(%s)=%d instead of %d", |
|
714 map_nm, i, ISZ(info_clear)); |
|
715 close(fd); |
|
716 if (pfd) |
|
717 *pfd = -1; |
|
718 if (created) |
|
719 unlink(map_nm); |
|
720 return 0; |
|
721 } |
|
722 |
|
723 if (created) { |
|
724 if (pfd) |
|
725 *pfd = fd; |
|
726 else |
|
727 close(fd); |
|
728 } |
|
729 return 1; |
|
730 } |
|
731 |
|
732 |
|
733 |
|
734 #ifdef DCC_MAP_INFO_VERSION_10 |
|
735 /* lock and read the contents of the old info file */ |
|
736 static int /* -1=error, 0=wrong version, 1=done */ |
|
737 map_convert_start(DCC_EMSG emsg, |
|
738 void *old_info, int old_info_size, |
|
739 const char *old_magic, int old_magic_size, |
|
740 DCC_PATH new_info_nm) |
|
741 { |
|
742 int i; |
|
743 |
|
744 assert_ctxts_locked(); |
|
745 assert_info_unlocked(); |
|
746 |
|
747 /* only one process or thread can fix the file so wait for |
|
748 * exclusive access to the old file */ |
|
749 if (!dcc_info_lock(emsg)) |
|
750 return -1; |
|
751 |
|
752 i = read(info_fd, old_info, old_info_size); |
|
753 if (i != old_info_size) { |
|
754 if (i < 0) { |
|
755 dcc_pemsg(EX_IOERR, emsg, "read(%s): %s", |
|
756 dcc_info_nm, ERROR_STR()); |
|
757 } else { |
|
758 dcc_pemsg(EX_IOERR, emsg, "read(%s)=%d instead of %d", |
|
759 dcc_info_nm, i, old_info_size); |
|
760 } |
|
761 dcc_info_unlock(0); |
|
762 return -1; |
|
763 } |
|
764 |
|
765 if (-1 == lseek(info_fd, SEEK_SET, 0)) { |
|
766 dcc_pemsg(EX_IOERR, emsg, "lseek(%s): %s", |
|
767 dcc_info_nm, ERROR_STR()); |
|
768 dcc_info_unlock(0); |
|
769 return -1; |
|
770 } |
|
771 |
|
772 if (strncmp(old_info, old_magic, old_magic_size)) { |
|
773 if (!dcc_info_unlock(emsg)) |
|
774 return -1; |
|
775 return 0; |
|
776 } |
|
777 |
|
778 if (!fnm2rel(new_info_nm, dcc_info_nm, "-new")) { |
|
779 dcc_pemsg(EX_IOERR, emsg, "long map name \"%s\"", |
|
780 dcc_info_nm); |
|
781 dcc_info_unlock(0); |
|
782 return -1; |
|
783 } |
|
784 unlink(new_info_nm); |
|
785 return 1; |
|
786 } |
|
787 |
|
788 |
|
789 |
|
790 /* the old file must be locked */ |
|
791 static int /* -1=error, 1=done */ |
|
792 map_convert_fin(DCC_EMSG emsg, |
|
793 const DCC_PATH new_info_nm, |
|
794 const struct stat *old_sb, |
|
795 const DCC_SRVR_NM *dcc_nms, int dcc_nms_len, |
|
796 const DCC_SRVR_NM *grey_nms, int grey_nms_len, |
|
797 const DCC_IP *src, |
|
798 u_char info_flags) /* DCC_INFO_FG_* */ |
|
799 { |
|
800 int new_fd; |
|
801 #ifdef DCC_WIN32 |
|
802 DCC_PATH old_info_nm; |
|
803 #endif |
|
804 |
|
805 new_fd = -1; |
|
806 if (!dcc_create_map(emsg, new_info_nm, &new_fd, |
|
807 dcc_nms, dcc_nms_len, grey_nms, grey_nms_len, |
|
808 src, info_flags)) { |
|
809 dcc_info_unlock(0); |
|
810 return -1; |
|
811 } |
|
812 |
|
813 #ifdef DCC_WIN32 |
|
814 /* there are at least two races here, |
|
815 * but Windows does not allow renaming or unlinking (e.g. by |
|
816 * rename()) open files */ |
|
817 if (!fnm2rel(old_info_nm, dcc_info_nm, "-old")) { |
|
818 dcc_pemsg(EX_IOERR, emsg, "long map name \"%s\"", |
|
819 dcc_info_nm); |
|
820 return -1; |
|
821 } |
|
822 unlink(old_info_nm); |
|
823 |
|
824 if (!dcc_info_unlock(emsg)) { |
|
825 close(new_fd); |
|
826 unlink(new_info_nm); |
|
827 return -1; |
|
828 } |
|
829 if (0 > close(info_fd)) { |
|
830 dcc_pemsg(EX_IOERR, emsg, "close(%s): %s", |
|
831 dcc_info_nm, ERROR_STR()); |
|
832 close(new_fd); |
|
833 unlink(new_info_nm); |
|
834 return -1; |
|
835 } |
|
836 info_fd = -1; |
|
837 |
|
838 if (0 > rename(dcc_info_nm, old_info_nm)) { |
|
839 dcc_pemsg(EX_IOERR, emsg, "rename(%s, %s): %s", |
|
840 dcc_info_nm, old_info_nm, ERROR_STR()); |
|
841 close(new_fd); |
|
842 unlink(new_info_nm); |
|
843 return -1; |
|
844 } |
|
845 |
|
846 close(new_fd); |
|
847 if (0 > rename(new_info_nm, dcc_info_nm)) { |
|
848 dcc_pemsg(EX_IOERR, emsg, "rename(%s, %s): %s", |
|
849 new_info_nm, dcc_info_nm, ERROR_STR()); |
|
850 unlink(new_info_nm); |
|
851 return -1; |
|
852 } |
|
853 return 1; |
|
854 #else /* !DCC_WIN32 */ |
|
855 /* if we are running as root, |
|
856 * don't change the owner of the file */ |
|
857 if (getuid() == 0 |
|
858 && 0 > fchown(new_fd, old_sb->st_uid, old_sb->st_gid)) { |
|
859 dcc_pemsg(EX_IOERR, emsg, "chown(%s,%d,%d): %s", |
|
860 new_info_nm, (int)old_sb->st_uid, (int)old_sb->st_gid, |
|
861 ERROR_STR()); |
|
862 unlink(new_info_nm); |
|
863 close(new_fd); |
|
864 return -1; |
|
865 } |
|
866 |
|
867 if (0 > rename(new_info_nm, dcc_info_nm)) { |
|
868 dcc_pemsg(EX_IOERR, emsg, "rename(%s, %s): %s", |
|
869 new_info_nm, dcc_info_nm, ERROR_STR()); |
|
870 unlink(new_info_nm); |
|
871 close(new_fd); |
|
872 return -1; |
|
873 } |
|
874 |
|
875 if (!dcc_info_unlock(emsg)) { |
|
876 close(new_fd); |
|
877 unlink(new_info_nm); |
|
878 return -1; |
|
879 } |
|
880 |
|
881 close(new_fd); |
|
882 return 1; |
|
883 #endif /* DCC_WIN32 */ |
|
884 } |
|
885 |
|
886 |
|
887 #endif /* DCC_MAP_INFO_VERSION_10 */ |
|
888 #ifdef DCC_MAP_INFO_VERSION_10 |
|
889 static void |
|
890 map_convert_v10_nms(DCC_SRVR_NM new_nms[DCC_MAX_SRVR_NMS], |
|
891 const DCC_V10_SRVR_NM old_nms[DCC_MAX_SRVR_NMS]) |
|
892 { |
|
893 int i; |
|
894 |
|
895 memset(new_nms, 0, sizeof(DCC_SRVR_NM)*DCC_MAX_SRVR_NMS); |
|
896 for (i = 0; i < DCC_MAX_SRVR_NMS; ++i) { |
|
897 new_nms[i].clnt_id = old_nms[i].clnt_id; |
|
898 new_nms[i].port = old_nms[i].port; |
|
899 strcpy(new_nms[i].hostname, old_nms[i].hostname); |
|
900 memcpy(new_nms[i].passwd, old_nms[i].passwd, |
|
901 sizeof(new_nms[i].passwd)); |
|
902 new_nms[i].rtt_adj = old_nms[i].rtt_adj; |
|
903 } |
|
904 } |
|
905 #endif /* DCC_MAP_INFO_VERSION_10 */ |
|
906 |
|
907 |
|
908 #ifdef DCC_MAP_INFO_VERSION_5 |
|
909 static int /* -1=error, 0=wrong version, 1=done */ |
|
910 map_convert_v5(DCC_EMSG emsg, const struct stat *old_sb) |
|
911 { |
|
912 DCC_PATH new_info_nm; |
|
913 DCC_SRVR_NM new_nms[DCC_MAX_SRVR_NMS]; |
|
914 DCC_V5_CLNT_INFO old_info; |
|
915 int i; |
|
916 |
|
917 if ((int)old_sb->st_size < ISZ(DCC_V5_CLNT_INFO)) |
|
918 return 0; |
|
919 |
|
920 i = map_convert_start(emsg, &old_info, sizeof(DCC_V5_CLNT_INFO), |
|
921 DCC_MAP_INFO_VERSION_5, sizeof(old_info.version), |
|
922 new_info_nm); |
|
923 if (i <= 0) |
|
924 return i; |
|
925 |
|
926 memset(&new_nms, 0, sizeof(new_nms)); |
|
927 for (i = 0; i < DIM(new_nms); ++i) { |
|
928 new_nms[i].clnt_id = old_info.nms[i].clnt_id; |
|
929 new_nms[i].port = old_info.nms[i].port; |
|
930 strcpy(new_nms[i].hostname, old_info.nms[i].hostname); |
|
931 memcpy(new_nms[i].passwd, old_info.nms[i].passwd, |
|
932 sizeof(new_nms[i].passwd)); |
|
933 new_nms[i].rtt_adj = old_info.nms[i].rtt_adj*10*1000; |
|
934 } |
|
935 |
|
936 return map_convert_fin(emsg, new_info_nm, old_sb, |
|
937 new_nms, DIM(new_nms), 0, 0, |
|
938 0, old_info.flags); |
|
939 } |
|
940 #endif /* DCC_MAP_INFO_VERSION_5 */ |
|
941 |
|
942 |
|
943 |
|
944 #ifdef DCC_MAP_INFO_VERSION_6 |
|
945 static int /* -1=error, 0=wrong version, 1=done */ |
|
946 map_convert_v6(DCC_EMSG emsg, const struct stat *old_sb) |
|
947 { |
|
948 DCC_PATH new_info_nm; |
|
949 DCC_SRVR_NM new_nms[DCC_MAX_SRVR_NMS]; |
|
950 DCC_V6_CLNT_INFO old_info; |
|
951 int i; |
|
952 |
|
953 if ((int)old_sb->st_size < ISZ(DCC_V6_CLNT_INFO)) |
|
954 return 0; |
|
955 |
|
956 i = map_convert_start(emsg, &old_info, sizeof(DCC_V6_CLNT_INFO), |
|
957 DCC_MAP_INFO_VERSION_6, sizeof(old_info.version), |
|
958 new_info_nm); |
|
959 if (i <= 0) |
|
960 return i; |
|
961 |
|
962 memset(&new_nms, 0, sizeof(new_nms)); |
|
963 for (i = 0; i < DIM(new_nms); ++i) { |
|
964 new_nms[i].clnt_id = old_info.nms[i].clnt_id; |
|
965 new_nms[i].port = old_info.nms[i].port; |
|
966 strcpy(new_nms[i].hostname, old_info.nms[i].hostname); |
|
967 memcpy(new_nms[i].passwd, old_info.nms[i].passwd, |
|
968 sizeof(new_nms[i].passwd)); |
|
969 new_nms[i].rtt_adj = old_info.nms[i].rtt_adj; |
|
970 } |
|
971 |
|
972 return map_convert_fin(emsg, new_info_nm, old_sb, |
|
973 new_nms, DIM(new_nms), 0, 0, |
|
974 0, old_info.flags); |
|
975 } |
|
976 #endif /* DCC_MAP_INFO_VERSION_6 */ |
|
977 |
|
978 |
|
979 |
|
980 #ifdef DCC_MAP_INFO_VERSION_7 |
|
981 static int /* -1=error, 0=wrong version, 1=done */ |
|
982 map_convert_v7(DCC_EMSG emsg, const struct stat *old_sb) |
|
983 { |
|
984 DCC_PATH new_info_nm; |
|
985 union { |
|
986 DCC_V7_IPV6_CLNT_INFO ipv6; |
|
987 DCC_V7_NOIPV6_CLNT_INFO noipv6; |
|
988 } old; |
|
989 DCC_SRVR_NM new_nms[DCC_MAX_SRVR_NMS]; |
|
990 DCC_SRVR_NM grey_nms[DCC_MAX_SRVR_NMS]; |
|
991 int flags, i; |
|
992 |
|
993 if (old_sb->st_size == sizeof(old.ipv6)) { |
|
994 i = map_convert_start(emsg, &old.ipv6, sizeof(old.ipv6), |
|
995 DCC_MAP_INFO_VERSION_7, |
|
996 sizeof(old.ipv6.version), |
|
997 new_info_nm); |
|
998 if (i <= 0) |
|
999 return i; |
|
1000 |
|
1001 map_convert_v10_nms(new_nms, old.ipv6.dcc.nms); |
|
1002 map_convert_v10_nms(grey_nms, old.ipv6.grey.nms); |
|
1003 flags = old.ipv6.flags; |
|
1004 |
|
1005 } else if (old_sb->st_size == sizeof(old.noipv6)) { |
|
1006 i = map_convert_start(emsg, &old.noipv6, sizeof(old.noipv6), |
|
1007 DCC_MAP_INFO_VERSION_7, |
|
1008 sizeof(old.noipv6.version), |
|
1009 new_info_nm); |
|
1010 if (i <= 0) |
|
1011 return i; |
|
1012 |
|
1013 map_convert_v10_nms(new_nms, old.noipv6.dcc.nms); |
|
1014 map_convert_v10_nms(grey_nms, old.noipv6.grey.nms); |
|
1015 flags = old.noipv6.flags; |
|
1016 |
|
1017 } else { |
|
1018 return 0; |
|
1019 } |
|
1020 |
|
1021 return map_convert_fin(emsg, new_info_nm, old_sb, |
|
1022 new_nms, DIM(new_nms), grey_nms, DIM(grey_nms), |
|
1023 0, flags); |
|
1024 } |
|
1025 |
|
1026 |
|
1027 |
|
1028 #endif /* DCC_MAP_INFO_VERSION_7 */ |
|
1029 #ifdef DCC_MAP_INFO_VERSION_8 |
|
1030 /* Convert an old map file. |
|
1031 * The contexts must be locked on entry. |
|
1032 * The old file may be locked on exit */ |
|
1033 static int /* -1=error, 0=wrong version, 1=done */ |
|
1034 map_convert_v8(DCC_EMSG emsg, const struct stat *old_sb) |
|
1035 { |
|
1036 DCC_PATH new_info_nm; |
|
1037 DCC_V8_CLNT_INFO old; |
|
1038 DCC_SRVR_NM new_nms[DCC_MAX_SRVR_NMS]; |
|
1039 DCC_SRVR_NM grey_nms[DCC_MAX_SRVR_NMS]; |
|
1040 int i; |
|
1041 |
|
1042 if ((int)old_sb->st_size != ISZ(old)) |
|
1043 return 0; |
|
1044 |
|
1045 i = map_convert_start(emsg, &old, sizeof(old), |
|
1046 DCC_MAP_INFO_VERSION_8, sizeof(old.version), |
|
1047 new_info_nm); |
|
1048 if (i <= 0) |
|
1049 return i; |
|
1050 |
|
1051 map_convert_v10_nms(new_nms, old.dcc.nms); |
|
1052 map_convert_v10_nms(grey_nms, old.grey.nms); |
|
1053 |
|
1054 return map_convert_fin(emsg, new_info_nm, old_sb, |
|
1055 new_nms, DIM(new_nms), grey_nms, DIM(grey_nms), |
|
1056 0, old.flags); |
|
1057 } |
|
1058 |
|
1059 |
|
1060 |
|
1061 #endif /* DCC_MAP_INFO_VERSION_8 */ |
|
1062 #ifdef DCC_MAP_INFO_VERSION_9 |
|
1063 /* Convert an old map file. |
|
1064 * The contexts must be locked on entry. |
|
1065 * The old file may be locked on exit */ |
|
1066 static int /* -1=error, 0=wrong version, 1=done */ |
|
1067 map_convert_v9(DCC_EMSG emsg, const struct stat *old_sb) |
|
1068 { |
|
1069 DCC_PATH new_info_nm; |
|
1070 DCC_V9_CLNT_INFO old; |
|
1071 DCC_SRVR_NM nms[DCC_MAX_SRVR_NMS]; |
|
1072 DCC_SRVR_NM grey_nms[DCC_MAX_SRVR_NMS]; |
|
1073 int i; |
|
1074 |
|
1075 if ((int)old_sb->st_size != ISZ(old)) |
|
1076 return 0; |
|
1077 |
|
1078 i = map_convert_start(emsg, &old, sizeof(old), |
|
1079 DCC_MAP_INFO_VERSION_9, sizeof(old.version), |
|
1080 new_info_nm); |
|
1081 if (i <= 0) |
|
1082 return i; |
|
1083 |
|
1084 map_convert_v10_nms(nms, old.dcc.nms); |
|
1085 map_convert_v10_nms(grey_nms, old.grey.nms); |
|
1086 |
|
1087 return map_convert_fin(emsg, new_info_nm, old_sb, |
|
1088 nms, DIM(nms), grey_nms, DIM(grey_nms), |
|
1089 &old.src, old.flags); |
|
1090 } |
|
1091 |
|
1092 |
|
1093 |
|
1094 #endif /* DCC_MAP_INFO_VERSION_9 */ |
|
1095 #ifdef DCC_MAP_INFO_VERSION_10 |
|
1096 /* Convert an old map file. |
|
1097 * The contexts must be locked on entry. |
|
1098 * The old file may be locked on exit */ |
|
1099 static int /* -1=error, 0=wrong version, 1=done */ |
|
1100 map_convert_v10(DCC_EMSG emsg, const struct stat *old_sb) |
|
1101 { |
|
1102 DCC_PATH new_info_nm; |
|
1103 DCC_V10_CLNT_INFO old; |
|
1104 DCC_SRVR_NM new_nms[DCC_MAX_SRVR_NMS]; |
|
1105 DCC_SRVR_NM grey_nms[DCC_MAX_SRVR_NMS]; |
|
1106 int i; |
|
1107 |
|
1108 if ((int)old_sb->st_size != ISZ(old)) |
|
1109 return 0; |
|
1110 |
|
1111 i = map_convert_start(emsg, &old, sizeof(old), |
|
1112 DCC_MAP_INFO_VERSION_10, sizeof(old.version), |
|
1113 new_info_nm); |
|
1114 if (i <= 0) |
|
1115 return i; |
|
1116 |
|
1117 map_convert_v10_nms(new_nms, old.dcc.nms); |
|
1118 map_convert_v10_nms(grey_nms, old.grey.nms); |
|
1119 |
|
1120 return map_convert_fin(emsg, new_info_nm, old_sb, |
|
1121 new_nms, DIM(new_nms), grey_nms, DIM(grey_nms), |
|
1122 &old.src, old.flags); |
|
1123 } |
|
1124 |
|
1125 |
|
1126 |
|
1127 #endif /* DCC_MAP_INFO_VERSION_10 */ |
|
1128 /* convert from a previous version |
|
1129 * The contexts must be locked. The old file must be open and unlocked */ |
|
1130 static u_char |
|
1131 map_convert(DCC_EMSG emsg, |
|
1132 const struct stat *old_sb) |
|
1133 { |
|
1134 int i; |
|
1135 |
|
1136 assert_ctxts_locked(); |
|
1137 assert_info_unlocked(); |
|
1138 |
|
1139 #ifdef DCC_MAP_INFO_VERSION_6 |
|
1140 i = map_convert_v5(emsg, old_sb); |
|
1141 if (i < 0) { |
|
1142 dcc_unmap_close_info(0); |
|
1143 return 0; |
|
1144 } |
|
1145 /* unlock old file and open & lock new file */ |
|
1146 if (i > 0) |
|
1147 return 1; |
|
1148 |
|
1149 i = map_convert_v6(emsg, old_sb); |
|
1150 if (i < 0) { |
|
1151 dcc_unmap_close_info(0); |
|
1152 return 0; |
|
1153 } |
|
1154 /* unlock old file and open & lock new file */ |
|
1155 if (i > 0) |
|
1156 return 1; |
|
1157 #endif /* DCC_MAP_INFO_VERSION_6 */ |
|
1158 #ifdef DCC_MAP_INFO_VERSION_7 |
|
1159 i = map_convert_v7(emsg, old_sb); |
|
1160 if (i < 0) { |
|
1161 dcc_unmap_close_info(0); |
|
1162 return 0; |
|
1163 } |
|
1164 /* unlock old file and open & lock new file */ |
|
1165 if (i > 0) |
|
1166 return 1; |
|
1167 #endif /* DCC_MAP_INFO_VERSION_7 */ |
|
1168 #ifdef DCC_MAP_INFO_VERSION_8 |
|
1169 i = map_convert_v8(emsg, old_sb); |
|
1170 if (i < 0) { |
|
1171 dcc_unmap_close_info(0); |
|
1172 return 0; |
|
1173 } |
|
1174 /* unlock old file and open & lock new file */ |
|
1175 if (i > 0) |
|
1176 return 1; |
|
1177 #endif /* DCC_MAP_INFO_VERSION_8 */ |
|
1178 #ifdef DCC_MAP_INFO_VERSION_9 |
|
1179 i = map_convert_v9(emsg, old_sb); |
|
1180 if (i < 0) { |
|
1181 dcc_unmap_close_info(0); |
|
1182 return 0; |
|
1183 } |
|
1184 /* unlock old file and open & lock new file */ |
|
1185 if (i > 0) |
|
1186 return 1; |
|
1187 #endif /* DCC_MAP_INFO_VERSION_9 */ |
|
1188 #ifdef DCC_MAP_INFO_VERSION_10 |
|
1189 i = map_convert_v10(emsg, old_sb); |
|
1190 if (i < 0) { |
|
1191 dcc_unmap_close_info(0); |
|
1192 return 0; |
|
1193 } |
|
1194 /* unlock old file and open & lock new file */ |
|
1195 if (i > 0) |
|
1196 return 1; |
|
1197 #endif /* DCC_MAP_INFO_VERSION_10 */ |
|
1198 dcc_pemsg(EX_DATAERR, emsg, "%s is not a DCC map file", |
|
1199 dcc_info_nm); |
|
1200 close(info_fd); |
|
1201 info_fd = -1; |
|
1202 return 0; |
|
1203 } |
|
1204 |
|
1205 |
|
1206 |
|
1207 /* Ensure the shared information is available, but do not lock it. |
|
1208 * The contexts must be locked |
|
1209 * SUID privileges are often released */ |
|
1210 u_char |
|
1211 dcc_map_info(DCC_EMSG emsg, /* cleared of stale messages */ |
|
1212 const char *new_info_nm, int new_info_fd) |
|
1213 { |
|
1214 struct stat sb; |
|
1215 #ifndef DCC_WIN32 |
|
1216 void *p; |
|
1217 #endif |
|
1218 |
|
1219 for (;;) { |
|
1220 assert_ctxts_locked(); |
|
1221 assert_info_unlocked(); |
|
1222 |
|
1223 /* work only if needed, |
|
1224 * but always check for a version changed */ |
|
1225 if (!(new_info_nm && strcmp(new_info_nm, dcc_info_nm)) |
|
1226 && new_info_fd < 0 |
|
1227 && dcc_clnt_info) |
|
1228 return 1; |
|
1229 |
|
1230 if (!dcc_unmap_close_info(emsg)) { |
|
1231 if (new_info_fd >= 0) |
|
1232 close(new_info_fd); |
|
1233 return 0; |
|
1234 } |
|
1235 |
|
1236 if (new_info_nm) { |
|
1237 if (!fnm2rel(dcc_info_nm, new_info_nm, 0)) { |
|
1238 dcc_pemsg(EX_IOERR, emsg, "bad map name \"%s\"", |
|
1239 new_info_nm); |
|
1240 return 0; |
|
1241 } |
|
1242 /* don't change name if we convert the file |
|
1243 * and so come back here */ |
|
1244 new_info_nm = 0; |
|
1245 } |
|
1246 if (dcc_info_nm[0] == '\0') { |
|
1247 dcc_pemsg(EX_USAGE, emsg, "missing map file name"); |
|
1248 return 0; |
|
1249 } |
|
1250 |
|
1251 if (new_info_fd >= 0) { |
|
1252 info_fd = new_info_fd; |
|
1253 new_info_fd = -1; |
|
1254 } else { |
|
1255 info_fd = open(dcc_info_nm, O_RDWR, 0600); |
|
1256 #ifndef DCC_WIN32 |
|
1257 if (info_fd < 0 |
|
1258 && dcc_get_priv_home(dcc_info_nm)) { |
|
1259 info_fd = open(dcc_info_nm, O_RDWR, 0600); |
|
1260 dcc_rel_priv(); |
|
1261 } |
|
1262 #endif |
|
1263 if (info_fd < 0) { |
|
1264 dcc_pemsg(EX_NOINPUT, emsg, "open(%s): %s", |
|
1265 dcc_info_nm, ERROR_STR()); |
|
1266 return 0; |
|
1267 } |
|
1268 } |
|
1269 |
|
1270 /* refuse to use the file if it is not private */ |
|
1271 if (!dcc_ck_private(emsg, &sb, dcc_info_nm, info_fd)) { |
|
1272 dcc_unmap_close_info(0); |
|
1273 return 0; |
|
1274 } |
|
1275 |
|
1276 if ((int)sb.st_size != ISZ(*dcc_clnt_info)) { |
|
1277 if (map_convert(emsg, &sb)) |
|
1278 continue; |
|
1279 return 0; |
|
1280 } |
|
1281 |
|
1282 #ifdef DCC_WIN32 |
|
1283 dcc_clnt_info = win32_map(emsg, &info_map, dcc_info_nm, |
|
1284 info_fd, sizeof(*dcc_clnt_info)); |
|
1285 if (!dcc_clnt_info) { |
|
1286 close(info_fd); |
|
1287 info_fd = -1; |
|
1288 return 0; |
|
1289 } |
|
1290 #else |
|
1291 |
|
1292 /* don't give it to children */ |
|
1293 if (0 > fcntl(info_fd, F_SETFD, FD_CLOEXEC)) { |
|
1294 dcc_pemsg(EX_IOERR, emsg, |
|
1295 "fcntl(F_SETFD FD_CLOEXEC %s): %s", |
|
1296 dcc_info_nm, ERROR_STR()); |
|
1297 close(info_fd); |
|
1298 info_fd = -1; |
|
1299 return 0; |
|
1300 } |
|
1301 |
|
1302 p = mmap(0, sizeof(*dcc_clnt_info), |
|
1303 PROT_READ|PROT_WRITE, MAP_SHARED, info_fd, 0); |
|
1304 if (p == MAP_FAILED) { |
|
1305 dcc_pemsg(EX_IOERR, emsg, "mmap(%s): %s", |
|
1306 dcc_info_nm, ERROR_STR()); |
|
1307 close(info_fd); |
|
1308 info_fd = -1; |
|
1309 return 0; |
|
1310 } |
|
1311 dcc_clnt_info = p; |
|
1312 #endif /* DCC_WIN32 */ |
|
1313 |
|
1314 if (!strncmp(dcc_clnt_info->version, DCC_MAP_INFO_VERSION, |
|
1315 sizeof(dcc_clnt_info->version))) { |
|
1316 /* The file is the right version. Set our ID in case |
|
1317 * it has been copied from another system */ |
|
1318 if (!get_clnt_hid(emsg)) |
|
1319 return 0; |
|
1320 dcc_clnt_info->proto_hdr.op_nums.h = dcc_clnt_hid; |
|
1321 |
|
1322 return 1; |
|
1323 } |
|
1324 |
|
1325 unmap_info(0); |
|
1326 if (!map_convert(emsg, &sb)) |
|
1327 return 0; |
|
1328 } |
|
1329 } |
|
1330 |
|
1331 |
|
1332 |
|
1333 /* SUID privileges are often released */ |
|
1334 u_char /* 0=something wrong, 1=mapped */ |
|
1335 dcc_map_lock_info(DCC_EMSG emsg, /* cleared of stale messages */ |
|
1336 const char *new_info_nm, |
|
1337 int new_info_fd) |
|
1338 { |
|
1339 if (!dcc_map_info(emsg, new_info_nm, new_info_fd)) |
|
1340 return 0; |
|
1341 |
|
1342 if (!dcc_info_lock(emsg)) |
|
1343 return 0; |
|
1344 |
|
1345 return 1; |
|
1346 } |
|
1347 |
|
1348 |
|
1349 |
|
1350 /* All servers are broken, so make a note to not try for a while. |
|
1351 * The contexts and the mapped information must be locked */ |
|
1352 static void |
|
1353 fail_more(const DCC_CLNT_CTXT *ctxt, DCC_SRVR_CLASS *class) |
|
1354 { |
|
1355 assert_info_locked(); |
|
1356 |
|
1357 /* do not inflate the delay if we are already delaying */ |
|
1358 if (class->fail_exp != 0 |
|
1359 && class->fail_time >= ctxt->now.tv_sec) |
|
1360 return; |
|
1361 |
|
1362 /* reset the backoff after a long quiet time */ |
|
1363 if (ctxt->now.tv_sec >= (class->fail_time |
|
1364 + (DCC_INIT_FAIL_SECS << class->fail_exp))) |
|
1365 class->fail_exp = 0; |
|
1366 |
|
1367 if (++class->fail_exp > DCC_MAX_FAIL_EXP) |
|
1368 class->fail_exp = DCC_MAX_FAIL_EXP; |
|
1369 class->fail_time = (ctxt->now.tv_sec |
|
1370 + (DCC_INIT_FAIL_SECS << class->fail_exp)); |
|
1371 } |
|
1372 |
|
1373 |
|
1374 |
|
1375 static u_char /* 0=failing */ |
|
1376 ck_fail_time(DCC_EMSG emsg, DCC_CLNT_CTXT *ctxt, DCC_SRVR_CLASS *class) |
|
1377 { |
|
1378 int dt; |
|
1379 |
|
1380 assert_info_locked(); |
|
1381 |
|
1382 if (class->fail_exp == 0) |
|
1383 return 1; |
|
1384 |
|
1385 dt = class->fail_time - ctxt->now.tv_sec; |
|
1386 if (dt > 0 && dt <= DCC_MAX_FAIL_SECS) { |
|
1387 dcc_pemsg(EX_IOERR, emsg, |
|
1388 "continue not asking %s %d seconds after failure", |
|
1389 DCC_IS_GREY_STR(class), dt); |
|
1390 return 0; |
|
1391 } |
|
1392 |
|
1393 return 1; |
|
1394 } |
|
1395 |
|
1396 |
|
1397 |
|
1398 void |
|
1399 dcc_force_measure_rtt(DCC_SRVR_CLASS *class) |
|
1400 { |
|
1401 assert_info_locked(); |
|
1402 |
|
1403 class->fail_exp = 0; /* stop giving up */ |
|
1404 |
|
1405 class->resolve = 0; /* force name resolution */ |
|
1406 |
|
1407 class->srvr_inx = NO_SRVR; |
|
1408 |
|
1409 class->measure = 0; /* force RTT measurement */ |
|
1410 } |
|
1411 |
|
1412 |
|
1413 |
|
1414 /* pick the best server |
|
1415 * The client information and the contexts must be exclusively locked. |
|
1416 * Assume there is at least one hostname. */ |
|
1417 static u_char /* 0=have none, 1=found one */ |
|
1418 pick_srvr(DCC_EMSG emsg, DCC_SRVR_CLASS *class) |
|
1419 { |
|
1420 const DCC_SRVR_ADDR *ap, *min_ap; |
|
1421 int rtt; |
|
1422 int min_rtt; /* smallest RTT */ |
|
1423 int min2_rtt; /* second smallest RTT */ |
|
1424 SRVR_INX old_srvr_inx; |
|
1425 |
|
1426 assert_info_locked(); |
|
1427 |
|
1428 if (class->num_srvrs == 0) { |
|
1429 class->srvr_inx = NO_SRVR; |
|
1430 extra_pemsg(EX_USAGE, emsg, "no valid %s server IP addresses", |
|
1431 DCC_IS_GREY_STR(class)); |
|
1432 return 0; |
|
1433 } |
|
1434 |
|
1435 old_srvr_inx = class->srvr_inx; |
|
1436 min2_rtt = min_rtt = DCC_RTT_BAD; |
|
1437 min_ap = 0; |
|
1438 ap = &class->addrs[class->num_srvrs]; |
|
1439 while (ap > class->addrs) { |
|
1440 --ap; |
|
1441 rtt = effective_rtt(class, ap); |
|
1442 if (rtt == DCC_RTT_BAD) |
|
1443 continue; |
|
1444 |
|
1445 if (min_rtt > rtt) { |
|
1446 if (min2_rtt > min_rtt) |
|
1447 min2_rtt = min_rtt; |
|
1448 min_rtt = rtt; |
|
1449 min_ap = ap; |
|
1450 } else if (min2_rtt > rtt) { |
|
1451 min2_rtt = rtt; |
|
1452 } |
|
1453 } |
|
1454 |
|
1455 /* we found a usable server */ |
|
1456 if (min_ap) { |
|
1457 /* Compute the basic RTT to the server including a variance */ |
|
1458 class->base_rtt = min_rtt + DCC_DCCD_DELAY; |
|
1459 if (class->base_rtt > DCC_MAX_RTT) |
|
1460 class->base_rtt = DCC_MAX_RTT; |
|
1461 /* Decide how bad the server must get before we check for |
|
1462 * an alternative. |
|
1463 * If there is no good second choice, there is no point in a |
|
1464 * threshold for switching to it */ |
|
1465 class->thold_rtt = min2_rtt + DCC_DCCD_DELAY; |
|
1466 if (class->thold_rtt >= DCC_MAX_RTT) |
|
1467 class->thold_rtt = DCC_RTT_BAD; |
|
1468 |
|
1469 class->srvr_inx = (min_ap - class->addrs); |
|
1470 if (class->srvr_inx != old_srvr_inx) { |
|
1471 if (dcc_clnt_debug > 1 && |
|
1472 GOOD_SRVR(class, old_srvr_inx)) { |
|
1473 trace_perf("replacing", |
|
1474 &class->addrs[old_srvr_inx]); |
|
1475 trace_perf("pick", min_ap); |
|
1476 } |
|
1477 } |
|
1478 return 1; |
|
1479 } |
|
1480 |
|
1481 /* we failed to find a working server */ |
|
1482 class->srvr_inx = NO_SRVR; |
|
1483 |
|
1484 flush_emsg(emsg, dcc_clnt_debug); |
|
1485 if (!emsg || *emsg == '\0') { |
|
1486 char astr[(DCC_SU2STR_SIZE+1+5+1)*3]; |
|
1487 const char *s, *h0; |
|
1488 int l; |
|
1489 |
|
1490 l = dcc_ap2str_opt(astr, sizeof(astr), |
|
1491 class, 0, '\0'); |
|
1492 if (!strcmp(class->nms[0].hostname, astr)) { |
|
1493 h0 = ""; |
|
1494 s = ""; |
|
1495 } else { |
|
1496 h0 = class->nms[0].hostname; |
|
1497 s = class->nms[1].hostname[0] ? "s" : " "; |
|
1498 } |
|
1499 |
|
1500 if (class->num_srvrs > 1 && l < ISZ(astr)-2) { |
|
1501 astr[l++] = ' '; |
|
1502 l += dcc_ap2str_opt(&astr[l], sizeof(astr)-l, |
|
1503 class, 1, '\0'); |
|
1504 } |
|
1505 if (class->num_srvrs > 2 && l < ISZ(astr)-2) { |
|
1506 astr[l++] = ' '; |
|
1507 dcc_ap2str_opt(&astr[l], sizeof(astr)-l, |
|
1508 class, 1, '\0'); |
|
1509 } |
|
1510 dcc_pemsg(EX_IOERR, emsg, |
|
1511 "no working %s server%s%s%s%s%s%s%s" |
|
1512 " at %s%s", |
|
1513 DCC_IS_GREY_STR(class), |
|
1514 s, h0, |
|
1515 class->nms[1].hostname[0] ? " " : "", |
|
1516 class->nms[1].hostname, |
|
1517 class->nms[2].hostname[0] ? " " : "", |
|
1518 class->nms[2].hostname, |
|
1519 class->nms[3].hostname[0] ? " ..." : "", |
|
1520 |
|
1521 astr, |
|
1522 class->num_srvrs > 3 ? " ..." : ""); |
|
1523 } |
|
1524 return 0; |
|
1525 } |
|
1526 |
|
1527 |
|
1528 |
|
1529 /* count IP addresses per host name and per second level domain name */ |
|
1530 typedef struct name_addrs { |
|
1531 const char *sld; /* domain name */ |
|
1532 u_char sld_addrs; /* # of addresses for domain name */ |
|
1533 u_char host_addrs; /* # of addresses for a host name */ |
|
1534 u_char sld_addrs_inx; |
|
1535 } NAME_ADDRS[DCC_MAX_SRVR_NMS]; |
|
1536 |
|
1537 |
|
1538 /* delete an address from a growing list of addresses */ |
|
1539 static void |
|
1540 del_new_addr(DCC_SRVR_CLASS *class, |
|
1541 NAME_ADDRS name_addrs, /* addresses per server name */ |
|
1542 int tgt) /* delete this address */ |
|
1543 { |
|
1544 NAM_INX nam_inx; |
|
1545 int i; |
|
1546 |
|
1547 /* adjust that host's and domain's numbers of addresses and our |
|
1548 * total number of addresses */ |
|
1549 nam_inx = class->addrs[tgt].nam_inx; |
|
1550 --name_addrs[nam_inx].host_addrs; |
|
1551 --name_addrs[name_addrs[nam_inx].sld_addrs_inx].sld_addrs; |
|
1552 --class->num_srvrs; |
|
1553 |
|
1554 /* slide the array of addresses to get rid of the discarded address */ |
|
1555 i = class->num_srvrs - tgt; |
|
1556 if (i > 0) |
|
1557 memmove(&class->addrs[tgt], &class->addrs[tgt+1], |
|
1558 i * sizeof(class->addrs[0])); |
|
1559 memset(&class->addrs[class->num_srvrs], 0, sizeof(class->addrs[0])); |
|
1560 } |
|
1561 |
|
1562 |
|
1563 |
|
1564 /* impose arbitrary local order on IP addresses */ |
|
1565 #define DCC_SRVRS_MOD 16381 |
|
1566 |
|
1567 static inline u_int |
|
1568 su_srvrs_mod(const DCC_SOCKU *sup, |
|
1569 DCC_SOCKU *sup2) |
|
1570 { |
|
1571 u_int su_res; |
|
1572 |
|
1573 if (dcc_ipv6sutoipv4(sup2, sup)) { |
|
1574 su_res = sup2->ipv4.sin_addr.s_addr % DCC_SRVRS_MOD; |
|
1575 su_res *= dcc_clnt_info->residue; |
|
1576 su_res %= DCC_SRVRS_MOD; |
|
1577 su_res += DCC_SRVRS_MOD; /* distinguish IPv4 from IPv6 */ |
|
1578 } else { |
|
1579 *sup2 = *sup; |
|
1580 su_res = (sup->ipv6.sin6_addr.s6_addr32[0] % DCC_SRVRS_MOD |
|
1581 + sup->ipv6.sin6_addr.s6_addr32[1] % DCC_SRVRS_MOD |
|
1582 + sup->ipv6.sin6_addr.s6_addr32[2] % DCC_SRVRS_MOD |
|
1583 + sup->ipv6.sin6_addr.s6_addr32[3] % DCC_SRVRS_MOD); |
|
1584 su_res *= dcc_clnt_info->residue; |
|
1585 su_res %= DCC_SRVRS_MOD; |
|
1586 } |
|
1587 return su_res; |
|
1588 } |
|
1589 |
|
1590 |
|
1591 |
|
1592 /* partially order a pair of IP addresses with a reasonably unique ordering */ |
|
1593 static int |
|
1594 sucmp(const DCC_SOCKU *sup1, const DCC_SOCKU *sup2) |
|
1595 { |
|
1596 DCC_SOCKU su1, su2; |
|
1597 u_int su1_res, su2_res; |
|
1598 int i; |
|
1599 |
|
1600 su1_res = su_srvrs_mod(sup1, &su1); |
|
1601 su2_res = su_srvrs_mod(sup2, &su2); |
|
1602 |
|
1603 i = (int)su1_res - (int)su2_res; |
|
1604 if (i) |
|
1605 return i; |
|
1606 return memcmp(&su1, &su2, sizeof(DCC_SOCKU)); |
|
1607 } |
|
1608 |
|
1609 |
|
1610 |
|
1611 /* Deal with a list of IP addresses or aliases for one DCC server hostname. |
|
1612 * the contexts and the mmap()'ed info must be locked */ |
|
1613 static void |
|
1614 copy_addrs(DCC_SRVR_CLASS *class, |
|
1615 const DCC_SRVR_NM *nmp, /* server name being resolved */ |
|
1616 const int nam_inx, |
|
1617 NAME_ADDRS name_addrs) /* addresses per server name */ |
|
1618 { |
|
1619 DCC_SRVR_ADDR *ap; |
|
1620 const DCC_SRVR_NM *nmp2; |
|
1621 DCC_SOCKU *np, su, nxt, prev; |
|
1622 u_int16_t port; |
|
1623 int i, j, k; |
|
1624 |
|
1625 /* Keep as many IP addresses as we have room, but for as many |
|
1626 * named servers as possible |
|
1627 * Sort the addresses to keep our list stable when we re-check. |
|
1628 * Otherwise, we would start from scratch when nothing changes |
|
1629 * but the order of responses from a DNS server. |
|
1630 * Sort by residue class to pick a random subset when there |
|
1631 * are too many servers to fit in our list. */ |
|
1632 |
|
1633 port = nmp->port; |
|
1634 |
|
1635 nxt.sa.sa_family = AF_UNSPEC; |
|
1636 for (;;) { |
|
1637 /* Pick the next address in the newly resolved list |
|
1638 * to consider. We want the smallest address larger |
|
1639 * than the previous address we considered. |
|
1640 * "Smallest" is defined using the local random ordering |
|
1641 * of addresses. */ |
|
1642 prev = nxt; |
|
1643 nxt.sa.sa_family = AF_UNSPEC; |
|
1644 for (np = dcc_hostaddrs; np < dcc_hostaddrs_end; ++np) { |
|
1645 if (np->sa.sa_family == AF_UNSPEC) |
|
1646 continue; |
|
1647 su = *np; |
|
1648 *DCC_SU_PORTP(&su) = port; |
|
1649 if ((prev.sa.sa_family == AF_UNSPEC |
|
1650 || sucmp(&su, &prev) > 0) |
|
1651 && (nxt.sa.sa_family == AF_UNSPEC |
|
1652 || sucmp(&nxt, &su) > 0)) |
|
1653 nxt = su; |
|
1654 } |
|
1655 /* quit if we've considered them all */ |
|
1656 if (nxt.sa.sa_family == AF_UNSPEC) |
|
1657 break; |
|
1658 |
|
1659 /* ignore duplicate IP addresses even for other hostnames, |
|
1660 * unless the port numbers differ */ |
|
1661 ap = &class->addrs[class->num_srvrs]; |
|
1662 while (--ap >= class->addrs) { |
|
1663 if (!dcc_cmp_ap2su(ap, &nxt)) { |
|
1664 /* they are the same, so keep the one with |
|
1665 * the non-anonymous ID |
|
1666 * or smallest RTT adjustment */ |
|
1667 nmp2 = &class->nms[ap->nam_inx]; |
|
1668 i = (nmp->clnt_id == DCC_ID_ANON); |
|
1669 j = (nmp2->clnt_id == DCC_ID_ANON); |
|
1670 if (i != j) { |
|
1671 /* one is anonymous & other is not */ |
|
1672 if (i) |
|
1673 goto next_addr; |
|
1674 } else { |
|
1675 /* pick smallest RTT adjustment */ |
|
1676 if (nmp->rtt_adj >= nmp2->rtt_adj) |
|
1677 goto next_addr; |
|
1678 } |
|
1679 /* delete the previous instance */ |
|
1680 del_new_addr(class, name_addrs, |
|
1681 ap - class->addrs); |
|
1682 break; |
|
1683 } |
|
1684 } |
|
1685 |
|
1686 /* If we already have as many addresses as we will use, |
|
1687 * then pick one to discard. Discard the last address of |
|
1688 * the host in the second level domain with the most |
|
1689 * addresses but without eliminating all addresses for any |
|
1690 * host name. Look for the domain with the most IP addresses |
|
1691 * and that has at least one host with at least two |
|
1692 * addersses. */ |
|
1693 if (class->num_srvrs == DCC_MAX_SRVR_ADDRS) { |
|
1694 int host_max, sld_max; |
|
1695 NAM_INX nam1_inx, sld1_inx, sld2_inx; |
|
1696 |
|
1697 host_max = -1; |
|
1698 sld_max = -1; |
|
1699 nam1_inx = NO_NAM; |
|
1700 sld1_inx = NO_NAM; |
|
1701 for (i = 0; i <= nam_inx; i++) { |
|
1702 /* ignore hosts with only 1 IP address */ |
|
1703 j = name_addrs[i].host_addrs; |
|
1704 if (j <= 1) |
|
1705 continue; |
|
1706 sld2_inx = name_addrs[i].sld_addrs_inx; |
|
1707 k = name_addrs[sld2_inx].sld_addrs; |
|
1708 if (sld_max <= k) { |
|
1709 if (sld1_inx != sld2_inx) { |
|
1710 sld_max = k; |
|
1711 sld1_inx = sld2_inx; |
|
1712 host_max = j; |
|
1713 nam1_inx = i; |
|
1714 } else if (host_max <= j) { |
|
1715 host_max = j; |
|
1716 nam1_inx = i; |
|
1717 } |
|
1718 } |
|
1719 } |
|
1720 /* no additional IP addresses for the target host if |
|
1721 * it has the most IP addresses */ |
|
1722 if (nam1_inx == nam_inx) |
|
1723 return; |
|
1724 |
|
1725 /* find the last address of the host with the most */ |
|
1726 for (i = 0, j = 0; i < class->num_srvrs; i++) { |
|
1727 if (class->addrs[i].nam_inx == nam1_inx) |
|
1728 j = i; |
|
1729 } |
|
1730 /* and delete it */ |
|
1731 del_new_addr(class, name_addrs, j); |
|
1732 } |
|
1733 |
|
1734 /* install the new address in the growing list */ |
|
1735 ap = &class->addrs[class->num_srvrs]; |
|
1736 ap->rtt = DCC_RTT_BAD; |
|
1737 if (nxt.sa.sa_family == AF_INET && DCC_INFO_IPV6()) |
|
1738 dcc_ipv4sutoipv6(&nxt, &nxt); |
|
1739 else if (nxt.sa.sa_family == AF_INET6 && !DCC_INFO_IPV6()) |
|
1740 dcc_ipv6sutoipv4(&nxt, &nxt); |
|
1741 dcc_su2ip(&ap->ip, &nxt); |
|
1742 |
|
1743 /* If this is a previously known address, |
|
1744 * preserve what we already knew about it |
|
1745 * Check the address family separately because dcc_cmp_ap2su() |
|
1746 * does not and DCC_INFO_IPV6() might have changed. */ |
|
1747 for (i = 0; i < class->num_srvrs; ++i) { |
|
1748 if (class->addrs[i].ip.family == nxt.sa.sa_family |
|
1749 && !dcc_cmp_ap2su(&class->addrs[i], &nxt)) { |
|
1750 *ap = class->addrs[i]; |
|
1751 break; |
|
1752 } |
|
1753 } |
|
1754 ap->nam_inx = nam_inx; |
|
1755 ++class->num_srvrs; |
|
1756 |
|
1757 ++name_addrs[nam_inx].host_addrs; |
|
1758 ++name_addrs[name_addrs[nam_inx].sld_addrs_inx].sld_addrs; |
|
1759 next_addr:; |
|
1760 } |
|
1761 } |
|
1762 |
|
1763 |
|
1764 |
|
1765 /* resolve one server name into a scratch array of addresses */ |
|
1766 static void |
|
1767 resolve_nm(DCC_EMSG emsg, |
|
1768 DCC_SRVR_CLASS *class, |
|
1769 int nm_inx, /* name being resolved */ |
|
1770 NAME_ADDRS name_addrs) /* addresses per server name */ |
|
1771 { |
|
1772 DCC_SRVR_NM *nmp; |
|
1773 const char *domain, *p1, *p2; |
|
1774 int error; |
|
1775 u_char result; |
|
1776 int i; |
|
1777 |
|
1778 nmp = &class->nms[nm_inx]; |
|
1779 nmp->defined = 0; |
|
1780 if (nmp->hostname[0] == '\0') |
|
1781 return; |
|
1782 |
|
1783 if (nmp->rtt_adj > DCC_RTT_ADJ_MAX) |
|
1784 nmp->rtt_adj = DCC_RTT_ADJ_MAX; |
|
1785 else if (nmp->rtt_adj < -DCC_RTT_ADJ_MAX) |
|
1786 nmp->rtt_adj = -DCC_RTT_ADJ_MAX; |
|
1787 |
|
1788 /* find the total number of addresses for this domain name */ |
|
1789 domain = nmp->hostname; |
|
1790 p1 = strchr(domain, '.'); |
|
1791 if (p1) { |
|
1792 for (;;) { |
|
1793 p2 = strchr(++p1, '.'); |
|
1794 if (!p2) |
|
1795 break; |
|
1796 domain = p1; |
|
1797 p1 = p2; |
|
1798 } |
|
1799 } |
|
1800 name_addrs[nm_inx].sld = domain; |
|
1801 for (i = 0; i < nm_inx; ++i) { |
|
1802 if (name_addrs[i].sld != 0 |
|
1803 && !strcmp(domain, name_addrs[i].sld)) |
|
1804 break; |
|
1805 } |
|
1806 name_addrs[nm_inx].sld_addrs_inx = i; |
|
1807 |
|
1808 dcc_host_lock(); |
|
1809 if (dcc_clnt_info->flags & DCC_INFO_FG_SOCKS) |
|
1810 result = dcc_get_host_SOCKS(nmp->hostname, |
|
1811 DCC_INFO_IPV6() ? 2 : 0, &error); |
|
1812 else |
|
1813 result = dcc_get_host(nmp->hostname, |
|
1814 DCC_INFO_IPV6() ? 2 : 0, &error); |
|
1815 if (!result) { |
|
1816 dcc_pemsg(EX_NOHOST, emsg, "%s: %s", |
|
1817 nmp->hostname, DCC_HSTRERROR(error)); |
|
1818 dcc_host_unlock(); |
|
1819 return; |
|
1820 } |
|
1821 nmp->defined = 1; |
|
1822 copy_addrs(class, nmp, nm_inx, name_addrs); |
|
1823 dcc_host_unlock(); |
|
1824 } |
|
1825 |
|
1826 |
|
1827 |
|
1828 /* resolve server hostnames again |
|
1829 * both locks must be held on entry |
|
1830 * both will be released while working |
|
1831 * on success, both are held |
|
1832 * on failure only the contexts are locked |
|
1833 */ |
|
1834 static u_char /* 0=no good addresses, 1=at least 1 */ |
|
1835 resolve_nms(DCC_EMSG emsg, DCC_CLNT_CTXT *ctxt, DCC_SRVR_CLASS *cur) |
|
1836 { |
|
1837 DCC_SRVR_CLASS new; |
|
1838 int nm_inx, a_inx; |
|
1839 NAME_ADDRS name_addrs; |
|
1840 DCC_SRVR_ADDR *new_ap, *cur_ap; |
|
1841 |
|
1842 assert_info_locked(); |
|
1843 |
|
1844 if (dcc_clnt_debug > 1) |
|
1845 dcc_trace_msg("resolve %s server host names", |
|
1846 DCC_IS_GREY_STR(cur)); |
|
1847 |
|
1848 /* try not to resolve names too often |
|
1849 * and discourage other processes and threads from resolving |
|
1850 * or measuring RTTs until we finish */ |
|
1851 cur->resolve = ctxt->now.tv_sec+DCC_MAP_RESOLVE; |
|
1852 cur->measure = ctxt->now.tv_sec+FAST_RTT_SECS; |
|
1853 |
|
1854 if (cur->nms[0].hostname[0] == '\0') { |
|
1855 if (HAVE_SRVR(cur)) { |
|
1856 ++cur->gen; |
|
1857 cur->avg_thold_rtt = DCC_RTT_BAD; |
|
1858 cur->srvr_inx = NO_SRVR; |
|
1859 } |
|
1860 cur->num_srvrs = 0; |
|
1861 memset(cur->addrs, 0, sizeof(cur->addrs)); |
|
1862 extra_pemsg(EX_USAGE, emsg, "no %s server hostnames", |
|
1863 DCC_IS_GREY_STR(cur)); |
|
1864 dcc_info_unlock(0); |
|
1865 return 0; |
|
1866 } |
|
1867 |
|
1868 new = *cur; |
|
1869 memset(new.addrs, 0, sizeof(new.addrs)); |
|
1870 new.num_srvrs = 0; |
|
1871 memset(&name_addrs, 0, sizeof(name_addrs)); |
|
1872 |
|
1873 if (dcc_clnt_info->residue == 0) { |
|
1874 dcc_clnt_info->residue = dcc_clnt_hid % DCC_SRVRS_MOD; |
|
1875 if (dcc_clnt_info->residue == 0) |
|
1876 dcc_clnt_info->residue = 1; |
|
1877 } |
|
1878 |
|
1879 /* unlock everything while we wait for DNS */ |
|
1880 if (!dcc_info_unlock(emsg)) { |
|
1881 cur->resolve = 0; |
|
1882 return 0; |
|
1883 } |
|
1884 dcc_ctxts_unlock(); |
|
1885 if (emsg) |
|
1886 *emsg = '\0'; |
|
1887 for (nm_inx = 0; nm_inx < DIM(cur->nms); ++nm_inx) |
|
1888 resolve_nm(emsg, &new, nm_inx, name_addrs); |
|
1889 dcc_ctxts_lock(); |
|
1890 if (!dcc_info_lock(emsg)) { |
|
1891 cur->resolve = 0; |
|
1892 return 0; |
|
1893 } |
|
1894 |
|
1895 /* measure all RTTs at least as often as we resolve names */ |
|
1896 cur->measure = 0; |
|
1897 |
|
1898 /* if we fail to resolve even one server host names, |
|
1899 * complain but try to continue using the old IP addresses */ |
|
1900 a_inx = new.num_srvrs; |
|
1901 if (a_inx == 0) { |
|
1902 extra_pemsg(EX_USAGE, emsg, "no valid %s server hostnames", |
|
1903 DCC_IS_GREY_STR(cur)); |
|
1904 dcc_info_unlock(0); |
|
1905 return 0; |
|
1906 } |
|
1907 |
|
1908 /* see if anything changed */ |
|
1909 for (nm_inx = 0; nm_inx < DIM(cur->nms); ++nm_inx) { |
|
1910 if (cur->nms[nm_inx].defined != new.nms[nm_inx].defined) |
|
1911 break; |
|
1912 } |
|
1913 if (nm_inx >= DIM(cur->nms) |
|
1914 && a_inx == cur->num_srvrs) { |
|
1915 /* we have the same number of old and new names and addresses, |
|
1916 * so compare the old and new addresses */ |
|
1917 new_ap = new.addrs; |
|
1918 cur_ap = cur->addrs; |
|
1919 for (;;) { |
|
1920 if (new_ap->nam_inx != cur_ap->nam_inx |
|
1921 || memcmp(&new_ap->ip, &cur_ap->ip, |
|
1922 sizeof(new_ap->ip))) { |
|
1923 break; |
|
1924 } |
|
1925 ++new_ap; |
|
1926 ++cur_ap; |
|
1927 if (!--a_inx) |
|
1928 return 1; /* nothing changed */ |
|
1929 } |
|
1930 } |
|
1931 |
|
1932 /* Something changed, so we must compute RTTs */ |
|
1933 ++cur->gen; |
|
1934 cur->srvr_inx = NO_SRVR; |
|
1935 cur->avg_thold_rtt = -DCC_RTT_BAD; |
|
1936 memcpy(&cur->addrs, &new.addrs, sizeof(cur->addrs)); |
|
1937 cur->num_srvrs = new.num_srvrs; |
|
1938 for (nm_inx = 0; nm_inx < DIM(cur->nms); ++nm_inx) |
|
1939 cur->nms[nm_inx].defined = new.nms[nm_inx].defined; |
|
1940 |
|
1941 return 1; |
|
1942 } |
|
1943 |
|
1944 |
|
1945 |
|
1946 void |
|
1947 dcc_clnt_soc_close(DCC_CLNT_CTXT *ctxt) |
|
1948 { |
|
1949 if (ctxt->soc == INVALID_SOCKET) |
|
1950 return; |
|
1951 if (SOCKET_ERROR == closesocket(ctxt->soc) |
|
1952 && dcc_clnt_debug) |
|
1953 dcc_trace_msg("closesocket(ctxt): %s", ERROR_STR()); |
|
1954 ctxt->soc = INVALID_SOCKET; |
|
1955 ctxt->conn_su.sa.sa_family = AF_UNSPEC; |
|
1956 } |
|
1957 |
|
1958 |
|
1959 |
|
1960 /* disconnect (or close) and (re)open the client |
|
1961 * The contexts and shared information must be locked on entry |
|
1962 * and both are locked on exit */ |
|
1963 u_char /* 0=failed to open the socket */ |
|
1964 dcc_clnt_soc_reopen(DCC_EMSG emsg, DCC_CLNT_CTXT *ctxt) |
|
1965 { |
|
1966 DCC_SOCKU su; |
|
1967 DCC_SOCKLEN_T soc_len; |
|
1968 int retries; |
|
1969 |
|
1970 assert_info_locked(); |
|
1971 |
|
1972 if (ctxt->soc != INVALID_SOCKET) |
|
1973 dcc_clnt_soc_close(ctxt); |
|
1974 |
|
1975 /* try to bind to the specified local interface address |
|
1976 * if it has changed |
|
1977 * or if it has been some time since we last tried and failed. */ |
|
1978 if (dcc_clnt_info->src.family == AF_UNSPEC) { |
|
1979 ctxt->flags &= ~DCC_CTXT_SRCBAD; |
|
1980 } else if (!(ctxt->flags & DCC_CTXT_SRCBAD) |
|
1981 || DCC_IS_TIME(ctxt->start.tv_sec, ctxt->bind_time, |
|
1982 DCC_CTXT_REBIND_SECS)) { |
|
1983 dcc_mk_su(&su, dcc_clnt_info->src.family, |
|
1984 &dcc_clnt_info->src.u, 0); |
|
1985 *DCC_SU_PORTP(&su) = DCC_SU_PORT(&ctxt->bind_su); |
|
1986 retries = -1; |
|
1987 if (0 >= dcc_udp_bind(emsg, &ctxt->soc, &su, &retries)) { |
|
1988 ctxt->flags |= DCC_CTXT_SRCBAD; |
|
1989 ctxt->bind_time = (ctxt->start.tv_sec |
|
1990 + DCC_CTXT_REBIND_SECS); |
|
1991 return 0; |
|
1992 } |
|
1993 ctxt->flags &= ~DCC_CTXT_SRCBAD; |
|
1994 ctxt->bind_time = 0; |
|
1995 |
|
1996 /* we have a bound socket */ |
|
1997 } |
|
1998 |
|
1999 /* If we do not have a bound socket, |
|
2000 * try to bind a new socket with IPv6 first if allowed */ |
|
2001 if (ctxt->soc == INVALID_SOCKET && DCC_INFO_IPV6()) { |
|
2002 dcc_mk_su(&su, AF_INET6, 0, DCC_SU_PORT(&ctxt->bind_su)); |
|
2003 retries = -1; |
|
2004 if (!dcc_udp_bind(emsg, &ctxt->soc, &su, &retries)) |
|
2005 return 0; |
|
2006 } |
|
2007 |
|
2008 /* if we still do not have a socket, try IPv4 */ |
|
2009 if (ctxt->soc == INVALID_SOCKET) { |
|
2010 dcc_clnt_info->flags &= ~DCC_INFO_FG_IPV6; |
|
2011 dcc_mk_su(&su, AF_INET, 0, DCC_SU_PORT(&ctxt->bind_su)); |
|
2012 retries = -1; |
|
2013 if (!dcc_udp_bind(emsg, &ctxt->soc, &su, &retries)) |
|
2014 return 0; |
|
2015 } |
|
2016 |
|
2017 #if !defined(USE_POLL) && !defined(DCC_WIN32) |
|
2018 if (ctxt->soc >= FD_SETSIZE) { |
|
2019 dcc_info_unlock(0); |
|
2020 dcc_pemsg(EX_IOERR, emsg, "socket FD %d > FD_SETSIZE %d", |
|
2021 ctxt->soc, FD_SETSIZE); |
|
2022 dcc_clnt_soc_close(ctxt); |
|
2023 return 0; |
|
2024 } |
|
2025 #endif |
|
2026 |
|
2027 #if defined(IPPROTO_IP) && defined(IP_TTL) |
|
2028 if (dcc_debug_ttl != 0 |
|
2029 && 0 > setsockopt(ctxt->soc, IPPROTO_IP, IP_TTL, |
|
2030 (void *)&dcc_debug_ttl, sizeof(dcc_debug_ttl))) { |
|
2031 dcc_pemsg(EX_IOERR, emsg, "setsockopt(TTL=%d):%s", |
|
2032 dcc_debug_ttl, ERROR_STR()); |
|
2033 dcc_clnt_soc_close(ctxt); |
|
2034 return 0; |
|
2035 } |
|
2036 #endif |
|
2037 |
|
2038 soc_len = sizeof(ctxt->bind_su); |
|
2039 if (0 > getsockname(ctxt->soc, &ctxt->bind_su.sa, &soc_len)) { |
|
2040 dcc_pemsg(EX_IOERR, emsg, "getsockname(): %s", ERROR_STR()); |
|
2041 dcc_clnt_soc_close(ctxt); |
|
2042 return 0; |
|
2043 } |
|
2044 if (su.sa.sa_family == AF_INET) |
|
2045 ctxt->flags |= DCC_CTXT_USING_IPV4; |
|
2046 else |
|
2047 ctxt->flags &= ~DCC_CTXT_USING_IPV4; |
|
2048 return 1; |
|
2049 } |
|
2050 |
|
2051 |
|
2052 |
|
2053 static int |
|
2054 do_recv(DCC_CLNT_CTXT *ctxt, DCC_OP_RESP *resp, int resp_len, DCC_SOCKU *sup) |
|
2055 { |
|
2056 DCC_SOCKLEN_T su_len; |
|
2057 |
|
2058 su_len = sizeof(*sup); |
|
2059 memset(sup, 0, sizeof(*sup)); |
|
2060 if (dcc_clnt_info->flags & DCC_INFO_FG_SOCKS) |
|
2061 return Rrecvfrom(ctxt->soc, WIN32_SOC_CAST resp, resp_len, 0, |
|
2062 &sup->sa, &su_len); |
|
2063 else |
|
2064 return recvfrom(ctxt->soc, WIN32_SOC_CAST resp, resp_len, 0, |
|
2065 &sup->sa, &su_len); |
|
2066 } |
|
2067 |
|
2068 |
|
2069 |
|
2070 static void |
|
2071 clear_error(DCC_CLNT_CTXT *ctxt, const char *which) |
|
2072 { |
|
2073 int err; |
|
2074 DCC_SOCKLEN_T errlen; |
|
2075 |
|
2076 errlen = sizeof(err); |
|
2077 if (0 > getsockopt(ctxt->soc, SOL_SOCKET, SO_ERROR, |
|
2078 WIN32_SOC_CAST &err, &errlen)) { |
|
2079 dcc_trace_msg("getsockopt(SO_ERROR): %s", ERROR_STR()); |
|
2080 } else if (dcc_clnt_debug > 3 && err) { |
|
2081 dcc_trace_msg("%s SO_ERROR: %s", which, ERROR_STR1(err)); |
|
2082 } |
|
2083 } |
|
2084 |
|
2085 |
|
2086 |
|
2087 /* clear the socket buffer */ |
|
2088 static u_char |
|
2089 dcc_clnt_soc_flush(DCC_CLNT_CTXT *ctxt) |
|
2090 { |
|
2091 DCC_OP_RESP pkt; |
|
2092 DCC_SOCKU su; |
|
2093 char sbuf[DCC_SU2STR_SIZE]; |
|
2094 char rbuf[30]; |
|
2095 char ob[DCC_OPBUF]; |
|
2096 int pkt_len, pkt_num; |
|
2097 |
|
2098 for (pkt_num = 1; pkt_num <= 50; ++pkt_num) { |
|
2099 pkt_len = do_recv(ctxt, &pkt, sizeof(pkt), &su); |
|
2100 if (0 <= pkt_len) { |
|
2101 if (dcc_clnt_debug == 0 && pkt_num < 10) |
|
2102 continue; |
|
2103 dcc_su2str(sbuf, sizeof(sbuf), &su); |
|
2104 if (pkt_num > 1) |
|
2105 snprintf(rbuf, sizeof(rbuf), " #%d", pkt_num); |
|
2106 else |
|
2107 rbuf[0] = '\0'; |
|
2108 if (pkt_len < ISZ(DCC_HDR)+ISZ(DCC_SIGNATURE) |
|
2109 || pkt_len != ntohs(pkt.hdr.len) |
|
2110 || pkt.hdr.pkt_vers < DCC_PKT_VERSION_MIN |
|
2111 || pkt.hdr.pkt_vers > DCC_PKT_VERSION_MAX) { |
|
2112 trace_bad_packet(0, &su, &pkt, pkt_len, |
|
2113 "flush%s %d stray bytes from" |
|
2114 " %s", |
|
2115 rbuf, pkt_len, sbuf); |
|
2116 } else { |
|
2117 dcc_trace_msg("flush%s %s from %s" |
|
2118 " ID=%d h=%#x p=%#x r=%#x t=%#x", |
|
2119 rbuf, |
|
2120 dcc_hdr_op2str(ob, sizeof(ob), |
|
2121 &pkt.hdr), |
|
2122 sbuf, |
|
2123 ntohl(pkt.hdr.sender), |
|
2124 pkt.hdr.op_nums.h, |
|
2125 pkt.hdr.op_nums.p, |
|
2126 pkt.hdr.op_nums.r, |
|
2127 pkt.hdr.op_nums.t); |
|
2128 |
|
2129 } |
|
2130 continue; |
|
2131 } |
|
2132 if (DCC_BLOCK_ERROR()) |
|
2133 return 1; |
|
2134 if (UNREACHABLE_ERRORS()) { |
|
2135 if (dcc_clnt_debug > 1 || pkt_num > 10) |
|
2136 dcc_trace_msg("ignore flushed error: %s", |
|
2137 ERROR_STR()); |
|
2138 continue; |
|
2139 } |
|
2140 dcc_trace_msg("flush recvfrom(%s): %s", |
|
2141 su.sa.sa_family |
|
2142 ? dcc_su2str(sbuf, sizeof(sbuf), &su) : "", |
|
2143 ERROR_STR()); |
|
2144 return 0; |
|
2145 } |
|
2146 |
|
2147 dcc_trace_msg("too many flushed packets or errors"); |
|
2148 return 0; |
|
2149 } |
|
2150 |
|
2151 |
|
2152 |
|
2153 /* connect() to the server |
|
2154 * The contexts and shared information must be locked on entry |
|
2155 * They are locked on exit */ |
|
2156 u_char |
|
2157 dcc_clnt_connect(DCC_EMSG emsg, DCC_CLNT_CTXT *ctxt, |
|
2158 const DCC_SOCKU *su) /* 0=disconnect */ |
|
2159 { |
|
2160 u_char was_connected; |
|
2161 |
|
2162 assert_info_locked(); |
|
2163 |
|
2164 /* disconnect if asked |
|
2165 * In theory you can use connect() with a "null address." |
|
2166 * In practice on some systems there is more than one or even |
|
2167 * no notion of an effective "null" address. */ |
|
2168 if (!su) { |
|
2169 if (ctxt->conn_su.sa.sa_family == AF_UNSPEC) { |
|
2170 #ifdef linux |
|
2171 /* some flavors of Linux say "Connection refused" on |
|
2172 * sendto() on a not-connected socket when a previous |
|
2173 * use of sendto() hit a closed port, particularly |
|
2174 * via loopback */ |
|
2175 clear_error(ctxt, "Linux dcc_clnt_connect(0)"); |
|
2176 #endif |
|
2177 return 1; |
|
2178 } |
|
2179 return dcc_clnt_soc_reopen(emsg, ctxt); |
|
2180 } |
|
2181 |
|
2182 /* already properly connected */ |
|
2183 if (!memcmp(&ctxt->conn_su, su, sizeof(ctxt->conn_su))) |
|
2184 return 1; |
|
2185 |
|
2186 was_connected = (ctxt->conn_su.sa.sa_family != AF_UNSPEC); |
|
2187 |
|
2188 /* At least some versions of Linux do not allow connsecutive valid |
|
2189 * calls to connect(). So for Linux, always close and reopen |
|
2190 * the socket. |
|
2191 * At least some versions of FreeBSD unbind a socket while |
|
2192 * reconnecting it. So if the socket was bound to local address |
|
2193 * or if it is time to try to bind it again, close and reopen it. |
|
2194 */ |
|
2195 if ((was_connected |
|
2196 #ifndef linux |
|
2197 && (dcc_clnt_info->src.family != AF_UNSPEC |
|
2198 && (!(ctxt->flags & DCC_CTXT_SRCBAD) |
|
2199 || DCC_IS_TIME(ctxt->start.tv_sec, ctxt->bind_time, |
|
2200 DCC_CTXT_REBIND_SECS))) |
|
2201 #endif /* linux */ |
|
2202 ) || !dcc_clnt_soc_flush(ctxt)) { |
|
2203 if (!dcc_clnt_soc_reopen(emsg, ctxt)) |
|
2204 return 0; |
|
2205 } |
|
2206 |
|
2207 if (SOCKET_ERROR == connect(ctxt->soc, &su->sa, DCC_SU_LEN(su))) { |
|
2208 char sustr[DCC_SU2STR_SIZE]; |
|
2209 |
|
2210 dcc_pemsg(EX_IOERR, emsg, "connect(%s): %s", |
|
2211 dcc_su2str(sustr, sizeof(sustr), su), |
|
2212 ERROR_STR()); |
|
2213 dcc_clnt_soc_close(ctxt); |
|
2214 return 0; |
|
2215 } |
|
2216 ctxt->conn_su = *su; |
|
2217 |
|
2218 /* clear ICMP Unreachable errors from previous connections */ |
|
2219 if (was_connected) |
|
2220 clear_error(ctxt, "dcc_clnt_connect"); |
|
2221 |
|
2222 return 1; |
|
2223 } |
|
2224 |
|
2225 |
|
2226 |
|
2227 /* send a single DCC message |
|
2228 * the contexts and the shared information must be locked on entry |
|
2229 * nothing is unlocked */ |
|
2230 static int /* 0=failed this target, -1=all stop */ |
|
2231 clnt_xmit(DCC_CLNT_CTXT *ctxt, |
|
2232 DCC_SRVR_CLASS *class, const DCC_SRVR_ADDR *ap, |
|
2233 DCC_HDR *msg, int msg_len, u_char connect_ok) |
|
2234 { |
|
2235 DCC_XLOG_ENTRY *xloge; |
|
2236 # define FSTR " from " |
|
2237 char tgt_abuf[80], src_abuf[LITZ(FSTR)+INET6_ADDRSTRLEN+1]; |
|
2238 char ob[DCC_OPBUF]; |
|
2239 DCC_XLOG_ENTRY *xloge1; |
|
2240 int i, result; |
|
2241 |
|
2242 msg->len = htons(msg_len); |
|
2243 |
|
2244 xloge = ctxt->xlog.next; |
|
2245 if (xloge > ctxt->xlog.last) |
|
2246 dcc_logbad(EX_SOFTWARE, "xloge > ctxt->xlog.last"); |
|
2247 ++msg->op_nums.t; |
|
2248 xloge->op_nums = msg->op_nums; |
|
2249 xloge->addr_inx = ap - class->addrs; |
|
2250 dcc_mk_su(&xloge->su, ap->ip.family, &ap->ip.u, ap->ip.port); |
|
2251 xloge->addrs_gen = class->gen; |
|
2252 xloge->sent_us = ctxt->now_us; |
|
2253 xloge->op = msg->op; |
|
2254 if (!GOOD_NAM(ap->nam_inx)) |
|
2255 dcc_logbad(EX_SOFTWARE, "clnt_xmit: bad nam_inx"); |
|
2256 xloge->id = class->nms[ap->nam_inx].clnt_id; |
|
2257 msg->sender = htonl(xloge->id); |
|
2258 if (xloge->id == DCC_ID_ANON) { |
|
2259 xloge->passwd[0] = '\0'; |
|
2260 memset((char *)msg + (msg_len-sizeof(DCC_SIGNATURE)), 0, |
|
2261 sizeof(DCC_SIGNATURE)); |
|
2262 } else { |
|
2263 if (xloge->id == 0) { |
|
2264 if (dcc_clnt_debug) |
|
2265 dcc_logbad(EX_SOFTWARE, "zero client-ID for %s", |
|
2266 class->nms[ap->nam_inx].hostname); |
|
2267 else |
|
2268 dcc_trace_msg("zero client-ID for %s", |
|
2269 class->nms[ap->nam_inx].hostname); |
|
2270 class->nms[ap->nam_inx].clnt_id = DCC_ID_ANON; |
|
2271 } else if (class->nms[ap->nam_inx].passwd[0] == '\0') { |
|
2272 if (dcc_clnt_debug) |
|
2273 dcc_logbad(EX_SOFTWARE, "null password for %s", |
|
2274 class->nms[ap->nam_inx].hostname); |
|
2275 else |
|
2276 dcc_trace_msg("null password for %s", |
|
2277 class->nms[ap->nam_inx].hostname); |
|
2278 class->nms[ap->nam_inx].clnt_id = DCC_ID_ANON; |
|
2279 } |
|
2280 strncpy(xloge->passwd, class->nms[ap->nam_inx].passwd, |
|
2281 sizeof(xloge->passwd)); |
|
2282 dcc_sign(xloge->passwd, sizeof(xloge->passwd), msg, msg_len); |
|
2283 } |
|
2284 |
|
2285 /* Use connect() when possible to get ICMP Unreachable messages. |
|
2286 * It is impossible when talking to more than one server. */ |
|
2287 for (xloge1 = ctxt->xlog.base; connect_ok && xloge1 < xloge; ++xloge1) { |
|
2288 if (xloge1->op_nums.t == DCC_OP_NUMS_NULL) |
|
2289 continue; |
|
2290 if (xloge->addr_inx != xloge1->addr_inx) { |
|
2291 connect_ok = 0; |
|
2292 break; |
|
2293 } |
|
2294 } |
|
2295 if (!dcc_clnt_connect(0, ctxt, connect_ok ? &xloge->su : 0)) |
|
2296 return -1; |
|
2297 |
|
2298 if (ctxt->conn_su.sa.sa_family != AF_UNSPEC) { |
|
2299 if (dcc_clnt_info->flags & DCC_INFO_FG_SOCKS) |
|
2300 i = Rsend(ctxt->soc, WIN32_SOC_CAST msg, msg_len, 0); |
|
2301 else |
|
2302 i = send(ctxt->soc, WIN32_SOC_CAST msg, msg_len, 0); |
|
2303 |
|
2304 } else { |
|
2305 if (dcc_clnt_info->flags & DCC_INFO_FG_SOCKS) |
|
2306 i = Rsendto(ctxt->soc, WIN32_SOC_CAST msg, msg_len, 0, |
|
2307 &xloge->su.sa, DCC_SU_LEN(&xloge->su)); |
|
2308 else |
|
2309 i = sendto(ctxt->soc, WIN32_SOC_CAST msg, msg_len, 0, |
|
2310 &xloge->su.sa, DCC_SU_LEN(&xloge->su)); |
|
2311 } |
|
2312 ++ctxt->xlog.cur[ap - class->addrs].xmits; |
|
2313 if (i == msg_len) { |
|
2314 if (dcc_clnt_debug > 3) |
|
2315 dcc_trace_msg("%8.6f sent %s t=%#x to %s", |
|
2316 get_age(ctxt), |
|
2317 dcc_hdr_op2str(ob, sizeof(ob), msg), |
|
2318 xloge->op_nums.t, |
|
2319 addr2str(tgt_abuf, sizeof(tgt_abuf), |
|
2320 class, class->gen, ap, 0)); |
|
2321 ++ctxt->xlog.next; |
|
2322 ++ctxt->xlog.outstanding; |
|
2323 return 1; |
|
2324 } |
|
2325 |
|
2326 /* stop output only for this target after ICMP Unreachable |
|
2327 * otherwise stop all output */ |
|
2328 if (i >= 0) { |
|
2329 result = -1; /* bad length is fatal */ |
|
2330 } else { |
|
2331 result = UNREACHABLE_ERRORS() ? 0 : -1; |
|
2332 } |
|
2333 |
|
2334 if (result < 0 || dcc_clnt_debug) { |
|
2335 if (ctxt->bind_su.sa.sa_family == AF_UNSPEC) { |
|
2336 src_abuf[0] = '\0'; |
|
2337 } else { |
|
2338 memcpy(src_abuf, FSTR, LITZ(FSTR)); |
|
2339 dcc_su2str(&src_abuf[LITZ(FSTR)], |
|
2340 sizeof(src_abuf)-LITZ(FSTR), |
|
2341 &ctxt->bind_su); |
|
2342 } |
|
2343 if (i < 0) { |
|
2344 dcc_trace_msg("%s(%s)%s: %s", |
|
2345 connect_ok ? "send" : "sendto", |
|
2346 addr2str(tgt_abuf, sizeof(tgt_abuf), |
|
2347 class, |
|
2348 class->gen, ap, 0), |
|
2349 src_abuf, ERROR_STR()); |
|
2350 } else { |
|
2351 dcc_trace_msg("%s(%s%s)=%d instead of %d", |
|
2352 connect_ok ? "send" : "sendto", |
|
2353 addr2str(tgt_abuf, sizeof(tgt_abuf), |
|
2354 class, |
|
2355 class->gen, ap, 0), |
|
2356 src_abuf, i, msg_len); |
|
2357 } |
|
2358 } |
|
2359 return result; |
|
2360 |
|
2361 #undef FSTR |
|
2362 } |
|
2363 |
|
2364 |
|
2365 |
|
2366 static void |
|
2367 update_rtt(DCC_CLNT_CTXT *ctxt, DCC_SRVR_CLASS *class, DCC_XLOG_ENTRY *xloge, |
|
2368 int us) |
|
2369 { |
|
2370 DCC_SRVR_ADDR *ap; |
|
2371 |
|
2372 /* compute new RTT only if the map data structure is locked, |
|
2373 * the clock did not jump, |
|
2374 * and we're talking about the same hosts */ |
|
2375 if (!info_locked |
|
2376 || xloge->addrs_gen != class->gen) |
|
2377 return; |
|
2378 |
|
2379 ap = &class->addrs[xloge->addr_inx]; |
|
2380 |
|
2381 if (us < 0) |
|
2382 us = 0; |
|
2383 if (us > DCC_RTT_BAD) |
|
2384 us = DCC_RTT_BAD; |
|
2385 |
|
2386 if (ap->rtt == DCC_RTT_BAD) { |
|
2387 /* just set the RTT if this is a newly working server */ |
|
2388 ap->rtt = us; |
|
2389 ap->total_xmits = 0; |
|
2390 ap->total_resps = 0; |
|
2391 ap->resp_mem = 0; |
|
2392 ap->rtt_updated = 0; |
|
2393 |
|
2394 } else if (ctxt->now.tv_sec < ap->rtt_updated + FAST_RTT_SECS) { |
|
2395 /* adjust the RTT quickly if this is the first |
|
2396 * measurement in a long time */ |
|
2397 AGE_AVG(ap->rtt, us, 2, 1); |
|
2398 ap->rtt_updated = ctxt->now.tv_sec; |
|
2399 |
|
2400 } else { |
|
2401 AGE_AVG(ap->rtt, us, 9, 1); |
|
2402 ap->rtt_updated = ctxt->now.tv_sec; |
|
2403 } |
|
2404 |
|
2405 if (ap->rtt > DCC_MAX_RTT) |
|
2406 ap->rtt = DCC_MAX_RTT; |
|
2407 } |
|
2408 |
|
2409 |
|
2410 |
|
2411 /* Update response rate and penalize the RTT of servers that failed to respond. |
|
2412 * the data must be locked */ |
|
2413 static void |
|
2414 resp_rates(DCC_CLNT_CTXT *ctxt, DCC_SRVR_CLASS *class, |
|
2415 u_char measuring) |
|
2416 { |
|
2417 DCC_SRVR_ADDR *ap; |
|
2418 DCC_XLOG_ENTRY *xloge; |
|
2419 const DCC_XLOG_ENTRY *xloge2; |
|
2420 int us, us2; |
|
2421 u_char seen; |
|
2422 int i; |
|
2423 |
|
2424 for (xloge = ctxt->xlog.base; xloge < ctxt->xlog.next; ++xloge) { |
|
2425 /* ignore responses we've already handled */ |
|
2426 if (xloge->op_nums.t == DCC_OP_NUMS_NULL) |
|
2427 continue; |
|
2428 |
|
2429 ap = &class->addrs[xloge->addr_inx]; |
|
2430 |
|
2431 /* Update the RTT of this server as if we would have received |
|
2432 * ia response if we had waited a little longer, unless we |
|
2433 * would be assuming a faster RTT than its current average. |
|
2434 * |
|
2435 * Use the longest of the time spent waiting for this request |
|
2436 * and the delays of any requests that were answered by the |
|
2437 * server. */ |
|
2438 us = ctxt->now_us - xloge->sent_us; |
|
2439 seen = 0; |
|
2440 for (xloge2=ctxt->xlog.base; xloge2<ctxt->xlog.next; ++xloge2) { |
|
2441 if (xloge2->addr_inx != xloge->addr_inx |
|
2442 || xloge2 == xloge) |
|
2443 continue; |
|
2444 if (xloge2->op_nums.t != DCC_OP_NUMS_NULL) { |
|
2445 seen = 1; |
|
2446 continue; |
|
2447 } |
|
2448 us2 = ctxt->now_us - xloge2->sent_us; |
|
2449 if (us < us2) |
|
2450 us = us2; |
|
2451 } |
|
2452 /* update the RTT |
|
2453 * if we waited at least as long as the current RTT |
|
2454 * or we received at least one response */ |
|
2455 if (ctxt->now_us >= ap->rtt && seen) |
|
2456 update_rtt(ctxt, class, xloge, us + DCC_DCCD_DELAY); |
|
2457 |
|
2458 /* having received its answer, forget this transmission */ |
|
2459 xloge->op_nums.t = DCC_OP_NUMS_NULL; |
|
2460 } |
|
2461 |
|
2462 /* maintain the response rate */ |
|
2463 for (i = 0, ap = class->addrs; i < DIM(ctxt->xlog.cur); ++i, ++ap) { |
|
2464 if (ap->rtt == DCC_RTT_BAD |
|
2465 || ctxt->xlog.cur[i].xmits == 0) |
|
2466 continue; |
|
2467 if (measuring) { |
|
2468 if (ctxt->xlog.cur[i].resps != 0) { |
|
2469 ++ctxt->xlog.working_addrs; |
|
2470 } else if (!(ap->resp_mem & ((1<<DCC_MAX_XMITS)-1))) { |
|
2471 /* this server is bad if there were no answers |
|
2472 * at all for this mesurement cycle */ |
|
2473 ap->rtt = DCC_RTT_BAD; |
|
2474 continue; |
|
2475 } |
|
2476 } |
|
2477 ap->total_xmits += ctxt->xlog.cur[i].xmits; |
|
2478 if (ap->total_xmits > DCC_TOTAL_XMITS_MAX) |
|
2479 ap->total_xmits = DCC_TOTAL_XMITS_MAX; |
|
2480 do { |
|
2481 ap->total_resps -= (ap->resp_mem |
|
2482 >> (DCC_TOTAL_XMITS_MAX-1)); |
|
2483 ap->resp_mem <<= 1; |
|
2484 if (ctxt->xlog.cur[i].resps != 0) { |
|
2485 ap->resp_mem |= 1; |
|
2486 ++ap->total_resps; |
|
2487 --ctxt->xlog.cur[i].resps; |
|
2488 } |
|
2489 } while (--ctxt->xlog.cur[i].xmits != 0); |
|
2490 } |
|
2491 } |
|
2492 |
|
2493 |
|
2494 |
|
2495 /* receive a single DCC response |
|
2496 * The contexts must be locked. |
|
2497 * The mapped or common info ought to be locked, but reception |
|
2498 * works if it is not. */ |
|
2499 static int /* -1=fatal error, 0=no data, 1=unreachable, 2=ok */ |
|
2500 clnt_recv(DCC_CLNT_CTXT *ctxt, DCC_SRVR_CLASS *class, |
|
2501 DCC_OP_RESP *resp, /* the response */ |
|
2502 int resp_len, |
|
2503 const DCC_HDR *msg, /* the original request */ |
|
2504 DCC_XLOG_ENTRY **xlogep) |
|
2505 { |
|
2506 DCC_SOCKU su; |
|
2507 DCC_XLOG_ENTRY *xloge, *xloge1; |
|
2508 DCC_SRVR_ADDR *ap; |
|
2509 char str[DCC_SU2STR_SIZE+50]; |
|
2510 char ob[DCC_OPBUF]; |
|
2511 char ob2[DCC_OPBUF]; |
|
2512 int pkt_len; |
|
2513 |
|
2514 *xlogep = 0; |
|
2515 for (;;) { |
|
2516 next_pkt:; |
|
2517 pkt_len = do_recv(ctxt, resp, resp_len, &su); |
|
2518 if (pkt_len < 0) { |
|
2519 /* Stop looking when there are no more packets */ |
|
2520 if (DCC_BLOCK_ERROR()) |
|
2521 return 0; |
|
2522 |
|
2523 /* ignore ICMP Unreachables unless we have connected |
|
2524 * to a server. |
|
2525 * If so, forget all outstanding requests */ |
|
2526 if (ctxt->conn_su.sa.sa_family != AF_UNSPEC |
|
2527 && UNREACHABLE_ERRORS()) { |
|
2528 /* find one relevant request |
|
2529 * and mark all of them finished */ |
|
2530 for (xloge1 = ctxt->xlog.base, xloge = 0; |
|
2531 xloge1 < ctxt->xlog.next; |
|
2532 ++xloge1) { |
|
2533 if (xloge1->op_nums.t==DCC_OP_NUMS_NULL) |
|
2534 continue; |
|
2535 xloge = xloge1; |
|
2536 xloge->op_nums.t = DCC_OP_NUMS_NULL; |
|
2537 } |
|
2538 if (!xloge) { |
|
2539 if (dcc_clnt_debug) |
|
2540 dcc_trace_msg("ignore unmatched:" |
|
2541 " %s", ERROR_STR()); |
|
2542 continue; |
|
2543 } |
|
2544 if (dcc_clnt_debug) |
|
2545 dcc_trace_msg("note recvfrom(%s): %s", |
|
2546 dcc_su2str(str, |
|
2547 sizeof(str), |
|
2548 &ctxt->conn_su), |
|
2549 ERROR_STR()); |
|
2550 ctxt->xlog.outstanding = 0; |
|
2551 ap = &class->addrs[xloge->addr_inx]; |
|
2552 ap->rtt = DCC_RTT_BAD; |
|
2553 ++ctxt->xlog.cur[xloge->addr_inx].resps; |
|
2554 *xlogep = xloge; |
|
2555 return 1; |
|
2556 } |
|
2557 dcc_trace_msg( "clnt_recv recvfrom(%s): %s", |
|
2558 su.sa.sa_family |
|
2559 ? dcc_su2str(str, sizeof(str), &su) : "", |
|
2560 ERROR_STR()); |
|
2561 return -1; |
|
2562 } |
|
2563 |
|
2564 if (pkt_len > resp_len) { |
|
2565 trace_bad_packet(&ctxt->xlog, &su, resp, pkt_len, |
|
2566 "recv(%s)=%d>%d", |
|
2567 dcc_su2str(str, sizeof(str), &su), |
|
2568 pkt_len, resp_len); |
|
2569 continue; |
|
2570 } |
|
2571 if (pkt_len < ISZ(DCC_HDR)+ISZ(DCC_SIGNATURE)) { |
|
2572 trace_bad_packet(&ctxt->xlog, &su, resp, pkt_len, |
|
2573 "recv(%s)=%d<%d", |
|
2574 dcc_su2str(str, sizeof(str), &su), |
|
2575 pkt_len, |
|
2576 ISZ(DCC_HDR)+ISZ(DCC_SIGNATURE)); |
|
2577 continue; |
|
2578 } |
|
2579 if (pkt_len != ntohs(resp->hdr.len)) { |
|
2580 trace_bad_packet(&ctxt->xlog, &su, resp, pkt_len, |
|
2581 "recv(%s)=%d but hdr len=%d", |
|
2582 dcc_su2str(str, sizeof(str), &su), |
|
2583 pkt_len, |
|
2584 ntohs(resp->hdr.len)); |
|
2585 continue; |
|
2586 } |
|
2587 |
|
2588 if (resp->hdr.pkt_vers < DCC_PKT_VERSION_MIN |
|
2589 || resp->hdr.pkt_vers > DCC_PKT_VERSION_MAX) { |
|
2590 trace_bad_packet(&ctxt->xlog, &su, resp, pkt_len, |
|
2591 "unrecognized version #%d from %s", |
|
2592 resp->hdr.pkt_vers, |
|
2593 dcc_su2str(str, sizeof(str), &su)); |
|
2594 continue; |
|
2595 } |
|
2596 |
|
2597 /* We cannot use the server's apparent IP address because it |
|
2598 * might be multi-homed and respond with an address other than |
|
2599 * the address to which we sent. So use our records of |
|
2600 * which OP_NUMS was sent to which server address. */ |
|
2601 if (resp->hdr.op_nums.r != msg->op_nums.r |
|
2602 || resp->hdr.op_nums.p != msg->op_nums.p |
|
2603 || resp->hdr.op_nums.h != msg->op_nums.h) { |
|
2604 if (dcc_clnt_debug) |
|
2605 dcc_trace_msg("unmatched response from %s" |
|
2606 " ID=%d h=%#x/%#x p=%#x/%#x" |
|
2607 " r=%#x/%#x t=%#x", |
|
2608 dcc_su2str(str, sizeof(str), &su), |
|
2609 ntohl(resp->hdr.sender), |
|
2610 resp->hdr.op_nums.h, |
|
2611 msg->op_nums.h, |
|
2612 resp->hdr.op_nums.p, |
|
2613 msg->op_nums.p, |
|
2614 resp->hdr.op_nums.r, |
|
2615 msg->op_nums.r, |
|
2616 resp->hdr.op_nums.t); |
|
2617 continue; |
|
2618 } |
|
2619 |
|
2620 /* everything matches except perhaps the transmission # */ |
|
2621 xloge = ctxt->xlog.base; |
|
2622 for (;;) { |
|
2623 if (xloge >= ctxt->xlog.next) { |
|
2624 if (dcc_clnt_debug) |
|
2625 dcc_trace_msg("stray response from %s" |
|
2626 " ID=%d h=%#x p=%#x" |
|
2627 " r=%#x t=%#x/%#x", |
|
2628 dcc_su2str(str, |
|
2629 sizeof(str), &su), |
|
2630 ntohl(resp->hdr.sender), |
|
2631 resp->hdr.op_nums.h, |
|
2632 resp->hdr.op_nums.p, |
|
2633 resp->hdr.op_nums.r, |
|
2634 msg->op_nums.r, |
|
2635 resp->hdr.op_nums.t); |
|
2636 goto next_pkt; |
|
2637 } |
|
2638 if (resp->hdr.op_nums.t == xloge->op_nums.t) |
|
2639 break; |
|
2640 ++xloge; |
|
2641 } |
|
2642 |
|
2643 ap = &class->addrs[xloge->addr_inx]; |
|
2644 |
|
2645 #ifdef CLNT_LOSSES |
|
2646 if ((++clnt_losses % 5) == 0) { |
|
2647 dcc_trace_msg("dropped answer from %s", |
|
2648 addr2str(str, sizeof(str), class, |
|
2649 xloge->addrs_gen, ap, &su)); |
|
2650 continue; |
|
2651 } |
|
2652 #endif |
|
2653 |
|
2654 if (xloge->passwd[0] != '\0' |
|
2655 && !dcc_ck_signature(xloge->passwd, sizeof(xloge->passwd), |
|
2656 resp, pkt_len)) { |
|
2657 dcc_error_msg("%s ID=%d rejected our password for ID %d" |
|
2658 " and %s with %s" |
|
2659 " h=%#x p=%#x r=%#x t=%#x", |
|
2660 addr2str(str, sizeof(str), |
|
2661 class, xloge->addrs_gen, |
|
2662 ap, &su), |
|
2663 ntohl(resp->hdr.sender), |
|
2664 xloge->id, |
|
2665 dcc_hdr_op2str(ob, sizeof(ob), |
|
2666 msg), |
|
2667 dcc_hdr_op2str(ob2, sizeof(ob2), |
|
2668 &resp->hdr), |
|
2669 resp->hdr.op_nums.h, |
|
2670 resp->hdr.op_nums.p, |
|
2671 resp->hdr.op_nums.r, |
|
2672 resp->hdr.op_nums.t); |
|
2673 continue; |
|
2674 } |
|
2675 |
|
2676 if (dcc_clnt_debug > 3) |
|
2677 dcc_trace_msg("%8.6f received response from %s ID=%d" |
|
2678 " h=%#x p=%#x r=%#x t=%#x", |
|
2679 get_age(ctxt), |
|
2680 dcc_su2str(str, sizeof(str), &su), |
|
2681 ntohl(resp->hdr.sender), |
|
2682 resp->hdr.op_nums.h, |
|
2683 resp->hdr.op_nums.p, |
|
2684 resp->hdr.op_nums.r, |
|
2685 resp->hdr.op_nums.t); |
|
2686 |
|
2687 /* don't find the record of this transmission again */ |
|
2688 xloge->op_nums.t = DCC_OP_NUMS_NULL; |
|
2689 if (ctxt->xlog.outstanding != 0) |
|
2690 --ctxt->xlog.outstanding; |
|
2691 ++ctxt->xlog.cur[xloge->addr_inx].resps; |
|
2692 *xlogep = xloge; |
|
2693 |
|
2694 /* Notice if multi-homing is involved |
|
2695 * That is true if the address from which the client answered |
|
2696 * differs from the address to which we sent */ |
|
2697 if (!(ap->flags & DCC_SRVR_ADDR_MHOME) |
|
2698 && dcc_cmp_ap2su(ap, &su)) { |
|
2699 if (dcc_clnt_debug) |
|
2700 dcc_trace_msg("%s multi-homed at %s", |
|
2701 addr2str(str, sizeof(str), |
|
2702 class, xloge->addrs_gen, |
|
2703 ap, 0), |
|
2704 dcc_su2str(str,sizeof(str), &su)); |
|
2705 ap->flags |= DCC_SRVR_ADDR_MHOME; |
|
2706 } |
|
2707 |
|
2708 return 2; |
|
2709 } |
|
2710 } |
|
2711 |
|
2712 |
|
2713 |
|
2714 /* wait for an answer */ |
|
2715 int /* -1=error, 0=timeout, 1=ready */ |
|
2716 dcc_select_poll(DCC_EMSG emsg, |
|
2717 SOCKET fd, |
|
2718 u_char rd, /* 1=read 0=write */ |
|
2719 int us) /* <0=forever until signal */ |
|
2720 { |
|
2721 #ifdef USE_POLL |
|
2722 struct pollfd fds; |
|
2723 int nfds; |
|
2724 int delay; |
|
2725 |
|
2726 if (us < 0) |
|
2727 delay = -1; |
|
2728 else |
|
2729 delay = (us+999)/1000; |
|
2730 |
|
2731 for (;;) { |
|
2732 fds.fd = fd; |
|
2733 /* At least some versions of Linux have POLLRDNORM etc. in |
|
2734 * asm/poll.h, but with definitions of POLLIN, POLLPRI, etc. |
|
2735 * that conflict with their definitions in sys/poll.h. |
|
2736 * Perhaps it is not necessary to check for high or |
|
2737 * low priority data, but the poll() documentation on |
|
2738 * some systems says that asking about POLLIN does not |
|
2739 * say anything about other data */ |
|
2740 #ifdef POLLRDNORM |
|
2741 if (rd) |
|
2742 fds.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; |
|
2743 else |
|
2744 fds.events = POLLOUT| POLLWRNORM | POLLWRBAND | POLLPRI; |
|
2745 #else |
|
2746 if (rd) |
|
2747 fds.events = POLLIN; |
|
2748 else |
|
2749 fds.events = POLLOUT; |
|
2750 #endif |
|
2751 fds.revents = 0; |
|
2752 nfds = poll(&fds, 1, delay); |
|
2753 if (nfds >= 0) |
|
2754 return nfds; |
|
2755 if (!DCC_SELECT_NERROR()) { |
|
2756 dcc_pemsg(EX_OSERR, emsg, "poll(): %s", ERROR_STR()); |
|
2757 return -1; |
|
2758 } |
|
2759 if (us < 0) /* stop forever on a signal */ |
|
2760 return 0; |
|
2761 } |
|
2762 #else |
|
2763 struct timeval delay, *delayp; |
|
2764 fd_set fds; |
|
2765 int nfds; |
|
2766 |
|
2767 if (us < 0) { |
|
2768 delayp = 0; |
|
2769 } else { |
|
2770 us2tv(&delay, us); |
|
2771 delayp = &delay; |
|
2772 } |
|
2773 |
|
2774 FD_ZERO(&fds); |
|
2775 for (;;) { |
|
2776 FD_SET(fd, &fds); |
|
2777 if (rd) |
|
2778 nfds = select(fd+1, &fds, 0, 0, delayp); |
|
2779 else |
|
2780 nfds = select(fd+1, 0, &fds, 0, delayp); |
|
2781 if (nfds >= 0) |
|
2782 return nfds; |
|
2783 if (!DCC_SELECT_NERROR()) { |
|
2784 dcc_pemsg(EX_OSERR, emsg, "select(): %s", ERROR_STR()); |
|
2785 return -1; |
|
2786 } |
|
2787 if (us < 0) /* stop forever on a signal */ |
|
2788 return 0; |
|
2789 } |
|
2790 #endif |
|
2791 } |
|
2792 |
|
2793 |
|
2794 |
|
2795 /* Make initial estimates of the RTT to all known servers |
|
2796 * The RTT's help the client pick a server that will respond quickly and |
|
2797 * reliably and to know when to retransmit a request that is lost due |
|
2798 * to network congestion or bit rot. |
|
2799 * Both locks must be held on entry. |
|
2800 * Both are released while working. |
|
2801 * Both locks are held on success. |
|
2802 * Only the contexts are locked on failure. */ |
|
2803 static u_char /* 0=failed, 1=at least 1 good server */ |
|
2804 measure_rtt(DCC_EMSG emsg, DCC_CLNT_CTXT *ctxt, |
|
2805 DCC_SRVR_CLASS *class, |
|
2806 DCC_CLNT_FGS clnt_fgs) /* DCC_CLNT_FG_* */ |
|
2807 { |
|
2808 DCC_SRVR_ADDR *ap; |
|
2809 DCC_NOP nop; |
|
2810 DCC_OP_RESP resp; |
|
2811 int delay_us, next_xmit; |
|
2812 int nfds, xmit_num; |
|
2813 int addrs_gen; |
|
2814 int tgt_addrs; |
|
2815 DCC_XLOG_ENTRY *xloge; |
|
2816 char ob[DCC_OPBUF], abuf[80]; |
|
2817 u_char vers; |
|
2818 u_char connect_ok; |
|
2819 int tgts, i; |
|
2820 |
|
2821 assert_info_locked(); |
|
2822 |
|
2823 /* Send NOP's to all addresses and wait for responses to |
|
2824 * measure each server's health and RTT. |
|
2825 * Treat all addresses as if they are of independent hosts */ |
|
2826 |
|
2827 if (class->nms[0].hostname[0] == '\0') { |
|
2828 class->srvr_inx = NO_SRVR; |
|
2829 dcc_pemsg(EX_NOHOST, emsg, "no %s server names", |
|
2830 DCC_IS_GREY_STR(class)); |
|
2831 dcc_info_unlock(0); |
|
2832 return 0; |
|
2833 } |
|
2834 |
|
2835 memcpy(&nop.hdr, &dcc_clnt_info->proto_hdr, sizeof(nop.hdr)); |
|
2836 /* servers ignore the version on NOPs except to guess the version |
|
2837 * we will accept */ |
|
2838 nop.hdr.pkt_vers = DCC_PKT_VERSION; |
|
2839 nop.hdr.op_nums.p = getpid(); |
|
2840 nop.hdr.op = DCC_OP_NOP; |
|
2841 /* Do not change the transaction ID so that dbclean can kludge it. |
|
2842 * Dccd does not care about the transaction ID on NOPs. */ |
|
2843 |
|
2844 if (!get_now(emsg, ctxt)) { |
|
2845 dcc_info_unlock(0); |
|
2846 return 0; |
|
2847 } |
|
2848 |
|
2849 /* discourage competition from other processes and threads */ |
|
2850 class->measure = ctxt->now.tv_sec+FAST_RTT_SECS; |
|
2851 |
|
2852 flush_emsg(emsg, 1); |
|
2853 |
|
2854 addrs_gen = class->gen; |
|
2855 |
|
2856 /* stop waiting for responses when we have enough working servers */ |
|
2857 tgt_addrs = class->num_srvrs; |
|
2858 if (!dcc_all_srvrs && tgt_addrs > 4) |
|
2859 tgt_addrs = 4; |
|
2860 |
|
2861 memset(&ctxt->xlog, 0, sizeof(ctxt->xlog)); |
|
2862 ctxt->xlog.base = ctxt->xlog.next = ctxt->xlog_entries; |
|
2863 ctxt->xlog.last = LAST(ctxt->xlog_entries); |
|
2864 delay_us = 0; |
|
2865 next_xmit = 0; |
|
2866 xmit_num = 0; |
|
2867 /* wait for the responses to the NOPs and retransmit as needed */ |
|
2868 for (;;) { |
|
2869 /* wait quietly until time to retransmit */ |
|
2870 if (delay_us <= 0) { |
|
2871 if (xmit_num >= DCC_MAX_XMITS) |
|
2872 break; |
|
2873 if (ctxt->xlog.working_addrs >= tgt_addrs) { |
|
2874 /* do not retransmit if we have heard from |
|
2875 * enough servers |
|
2876 * quit if we have waited at least one RTT */ |
|
2877 if (xmit_num > 0) |
|
2878 break; |
|
2879 delay_us = 0; |
|
2880 next_xmit = ctxt->now_us; |
|
2881 |
|
2882 } else { |
|
2883 /* get delay & time of next transmission */ |
|
2884 delay_us = retrans_time((clnt_fgs |
|
2885 & DCC_CLNT_FG_SLOW) |
|
2886 ? DCC_MAX_RTT |
|
2887 : DCC_MIN_RTT, |
|
2888 xmit_num++); |
|
2889 next_xmit = delay_us + ctxt->now_us; |
|
2890 |
|
2891 connect_ok = 1; |
|
2892 tgts = 0; |
|
2893 for (i = 0, ap = class->addrs; |
|
2894 ap <= LAST(class->addrs); |
|
2895 ++i, ++ap) { |
|
2896 if (ap->ip.family == 0 |
|
2897 || ctxt->xlog.cur[i].resps != 0) |
|
2898 continue; |
|
2899 if (ap->flags & DCC_SRVR_ADDR_MHOME) |
|
2900 connect_ok = 0; |
|
2901 ++tgts; |
|
2902 } |
|
2903 /* Use a connected socket early to get |
|
2904 * ICMP error messages from single server. |
|
2905 * no connection later to detect multi-homing |
|
2906 * that makes a server appear deaf */ |
|
2907 if (tgts > 1 |
|
2908 || xmit_num > DCC_MAX_XMITS/2) |
|
2909 connect_ok = 0; |
|
2910 for (i = 0, ap = class->addrs; |
|
2911 tgts > 0 && ap <= LAST(class->addrs); |
|
2912 ++i, ++ap) { |
|
2913 if (ap->ip.family == 0 |
|
2914 || !GOOD_NAM(ap->nam_inx) |
|
2915 || ctxt->xlog.cur[i].resps != 0) |
|
2916 continue; |
|
2917 --tgts; |
|
2918 if (0 > clnt_xmit(ctxt, class, ap, |
|
2919 &nop.hdr, sizeof(nop), |
|
2920 connect_ok)) |
|
2921 break; |
|
2922 } |
|
2923 } |
|
2924 |
|
2925 /* stop if nothing to wait for */ |
|
2926 if (!ctxt->xlog.outstanding) |
|
2927 break; |
|
2928 } |
|
2929 |
|
2930 if (!dcc_info_unlock(emsg)) |
|
2931 return 0; |
|
2932 dcc_ctxts_unlock(); |
|
2933 nfds = dcc_select_poll(emsg, ctxt->soc, 1, delay_us); |
|
2934 dcc_ctxts_lock(); |
|
2935 if (nfds < 0) |
|
2936 return 0; |
|
2937 if (!dcc_info_lock(emsg)) |
|
2938 return 0; |
|
2939 |
|
2940 i = get_now(emsg, ctxt); |
|
2941 if (!i) { /* give up if the clock jumped */ |
|
2942 class->measure = 0; |
|
2943 dcc_info_unlock(0); |
|
2944 return 0; |
|
2945 } |
|
2946 if (addrs_gen != class->gen) { |
|
2947 extra_pemsg(EX_IOERR, emsg, |
|
2948 "competition stopped RTT measurement"); |
|
2949 /* if we have at least one address, |
|
2950 * hope the other process will finish the job */ |
|
2951 if (HAVE_SRVR(class) |
|
2952 || pick_srvr(emsg, class)) |
|
2953 return 1; |
|
2954 |
|
2955 /* fail, but hope the other process will finish */ |
|
2956 dcc_info_unlock(0); |
|
2957 return 0; |
|
2958 } |
|
2959 |
|
2960 if (nfds > 0) { |
|
2961 for (;;) { |
|
2962 i = clnt_recv(ctxt, class, |
|
2963 &resp, sizeof(resp), |
|
2964 &nop.hdr, &xloge); |
|
2965 if (i <= 0) |
|
2966 break; |
|
2967 |
|
2968 if (i == 1) /* otherwise ignore Unreachable */ |
|
2969 continue; |
|
2970 |
|
2971 /* record the results of a probe, and notice |
|
2972 * if the server is the best so far */ |
|
2973 ap = &class->addrs[xloge->addr_inx]; |
|
2974 |
|
2975 if (resp.hdr.op != DCC_OP_OK) { |
|
2976 if (dcc_clnt_debug) |
|
2977 dcc_trace_msg("RTT NOP answered" |
|
2978 " with %s by %s", |
|
2979 dcc_hdr_op2str(ob, |
|
2980 sizeof(ob), |
|
2981 &resp.hdr), |
|
2982 addr2str(abuf, |
|
2983 sizeof(abuf), |
|
2984 class, |
|
2985 xloge->addrs_gen, |
|
2986 ap, 0)); |
|
2987 ap->rtt = DCC_RTT_BAD; |
|
2988 continue; |
|
2989 } |
|
2990 |
|
2991 vers = resp.ok.max_pkt_vers; |
|
2992 if (vers >= DCC_PKT_VERSION_MAX) |
|
2993 vers = DCC_PKT_VERSION_MAX; |
|
2994 else if (vers < DCC_PKT_VERSION_MIN) |
|
2995 vers = DCC_PKT_VERSION_MIN; |
|
2996 ap->srvr_pkt_vers = vers; |
|
2997 ap->srvr_id = ntohl(resp.hdr.sender); |
|
2998 memcpy(ap->brand, resp.ok.brand, |
|
2999 sizeof(ap->brand)); |
|
3000 ap->srvr_wait = ntohs(resp.ok.qdelay_ms)*1000; |
|
3001 |
|
3002 update_rtt(ctxt, class, xloge, |
|
3003 ctxt->now_us - xloge->sent_us |
|
3004 + ap->srvr_wait); |
|
3005 } |
|
3006 } |
|
3007 |
|
3008 if (ctxt->xlog.outstanding == 0 |
|
3009 || (ctxt->xlog.working_addrs >= tgt_addrs |
|
3010 && xmit_num > 1)) |
|
3011 next_xmit = ctxt->now_us; |
|
3012 delay_us = next_xmit - ctxt->now_us; |
|
3013 } |
|
3014 /* the contexts and the shared information are locked */ |
|
3015 resp_rates(ctxt, class, 1); |
|
3016 |
|
3017 if (!pick_srvr(emsg, class)) { |
|
3018 fail_more(ctxt, class); |
|
3019 dcc_info_unlock(0); |
|
3020 return 0; |
|
3021 } |
|
3022 |
|
3023 /* maintain long term average that is used to switch back to |
|
3024 * a good server that temporarily goes bad */ |
|
3025 if (class->thold_rtt == DCC_RTT_BAD) { |
|
3026 /* There is no point in trying to change servers |
|
3027 * Maybe we have only 1 */ |
|
3028 class->avg_thold_rtt = DCC_RTT_BAD; |
|
3029 } else if (class->avg_thold_rtt == -DCC_RTT_BAD) { |
|
3030 /* We are being forced to consider changing servers. |
|
3031 * The threshold for changing will be based on the RTT |
|
3032 * for the new server */ |
|
3033 class->avg_thold_rtt = class->base_rtt; |
|
3034 } else { |
|
3035 AGE_AVG(class->avg_thold_rtt, class->base_rtt, 9, 1); |
|
3036 } |
|
3037 |
|
3038 class->measure = ctxt->now.tv_sec+FAST_RTT_SECS; |
|
3039 |
|
3040 /* Several systems do not update the mtime of a file modified with |
|
3041 * mmap(). Some like BSD/OS delay changing the mtime until the file |
|
3042 * accessed with read(). Others including filesystems on some |
|
3043 * versions of Linux apparently never change the mtime. |
|
3044 * Do not bother temporary map files that have already been unlinked |
|
3045 * to avoid problems on systems that do not have futimes() */ |
|
3046 if (!(dcc_clnt_info->flags & DCC_INFO_FG_TMP)) |
|
3047 dcc_set_mtime(emsg, dcc_info_nm, info_fd, 0); |
|
3048 flush_emsg(emsg, 1); |
|
3049 |
|
3050 return 1; |
|
3051 } |
|
3052 |
|
3053 |
|
3054 |
|
3055 /* Get and write-lock common info |
|
3056 * The contexts but not the info must be locked. |
|
3057 * The contexts remain locked on failure. The shared information |
|
3058 * is locked only on success. */ |
|
3059 u_char /* 0=failed 1=ok */ |
|
3060 dcc_clnt_rdy(DCC_EMSG emsg, /* cleared of stale messages */ |
|
3061 DCC_CLNT_CTXT *ctxt, |
|
3062 DCC_CLNT_FGS clnt_fgs) /* DCC_CLNT_FG_* */ |
|
3063 { |
|
3064 DCC_SRVR_CLASS *class; |
|
3065 DCC_IP bind_ip, zero_ip, *src_ip; |
|
3066 |
|
3067 if (!dcc_info_lock(emsg)) |
|
3068 return 0; |
|
3069 |
|
3070 if (!(clnt_fgs & DCC_CLNT_FG_RETRY)) |
|
3071 get_start_time(ctxt); |
|
3072 |
|
3073 class = DCC_GREY2CLASS(clnt_fgs & DCC_CLNT_FG_GREY); |
|
3074 |
|
3075 /* just fail if things were broken and it's too soon to try again */ |
|
3076 if (!(clnt_fgs & DCC_CLNT_FG_NO_FAIL) |
|
3077 && !ck_fail_time(emsg, ctxt, class)) { |
|
3078 dcc_info_unlock(0); |
|
3079 return 0; |
|
3080 } |
|
3081 |
|
3082 /* Re-open the socket if it is closed, |
|
3083 * or we have switched between IPv4 and IPv6, |
|
3084 * or if the local address has changed |
|
3085 * or if the local address was broken a long time ago. |
|
3086 * Do not compare the source port numbers, because even when there |
|
3087 * is no explicit source address, the local port is cached in |
|
3088 * ctxt->bind_su. */ |
|
3089 dcc_su2ip(&bind_ip, &ctxt->bind_su); |
|
3090 bind_ip.port = 0; |
|
3091 if (dcc_clnt_info->src.family == AF_UNSPEC) { |
|
3092 memset(&zero_ip, 0, sizeof(zero_ip)); |
|
3093 zero_ip.family = bind_ip.family; |
|
3094 src_ip = &zero_ip; |
|
3095 } else { |
|
3096 src_ip = &dcc_clnt_info->src; |
|
3097 } |
|
3098 if (ctxt->soc == INVALID_SOCKET |
|
3099 || ((ctxt->flags & DCC_CTXT_USING_IPV4)!=0) != !DCC_INFO_IPV6() |
|
3100 || (memcmp(src_ip, &bind_ip, sizeof(*src_ip)) |
|
3101 && (!(ctxt->flags & DCC_CTXT_SRCBAD) |
|
3102 || DCC_IS_TIME(ctxt->start.tv_sec, ctxt->bind_time, |
|
3103 DCC_CTXT_REBIND_SECS)))) { |
|
3104 if (!dcc_clnt_soc_reopen(emsg, ctxt)) { |
|
3105 dcc_info_unlock(0); |
|
3106 return 0; |
|
3107 } |
|
3108 } |
|
3109 |
|
3110 /* Try to pick a new server if we do not have a server |
|
3111 * or if the current server has become slow or unreliable. */ |
|
3112 if (!good_rtt(class)) |
|
3113 pick_srvr(emsg, class); |
|
3114 |
|
3115 /* Check for new IP addresses occassionally or when we have none |
|
3116 * If we cannot awaken a separate thread, do it ourself */ |
|
3117 if ((!HAVE_SRVR(class) |
|
3118 || DCC_IS_TIME(ctxt->now.tv_sec, class->resolve, DCC_MAP_RESOLVE)) |
|
3119 && (class->num_srvrs == 0 |
|
3120 || !dcc_clnt_wake_resolve())) { |
|
3121 if (!resolve_nms(emsg, ctxt, class)) |
|
3122 return 0; |
|
3123 } |
|
3124 |
|
3125 /* We might have switched to the current server when our |
|
3126 * best server became slow. |
|
3127 * If it has been a while, see if our best server is back |
|
3128 * by sending NOPs to all servers. */ |
|
3129 if ((class->measure == 0 |
|
3130 || (DCC_IS_TIME(ctxt->now.tv_sec, class->measure, FAST_RTT_SECS) |
|
3131 && !good_rtt(class))) |
|
3132 && !(clnt_fgs & DCC_CLNT_FG_NO_PICK_SRVR)) { |
|
3133 if (!measure_rtt(emsg, ctxt, class, clnt_fgs)) |
|
3134 return 0; |
|
3135 } |
|
3136 |
|
3137 if (!HAVE_SRVR(class) && !(clnt_fgs & DCC_CLNT_FG_BAD_SRVR_OK)) { |
|
3138 dcc_info_unlock(0); |
|
3139 return 0; |
|
3140 } |
|
3141 |
|
3142 dcc_clnt_soc_flush(ctxt); |
|
3143 return 1; |
|
3144 } |
|
3145 |
|
3146 |
|
3147 |
|
3148 /* send an operation to the server and get a response |
|
3149 * The operation and response buffers must be distinct, because the |
|
3150 * response buffer is changed before the last use of the operation |
|
3151 * buffer */ |
|
3152 u_char /* 0=failed 1=ok */ |
|
3153 dcc_clnt_op(DCC_EMSG emsg, |
|
3154 DCC_CLNT_CTXT *ctxt, |
|
3155 DCC_CLNT_FGS clnt_fgs, /* DCC_CLNT_FG_* */ |
|
3156 const SRVR_INX *srvr_inxp, /* 0 or ptr to server index */ |
|
3157 DCC_SRVR_ID *srvr_idp, /* ID of server used */ |
|
3158 DCC_SOCKU *resp_su, /* IP address of server used */ |
|
3159 DCC_HDR *msg, int msg_len, DCC_OPS op, |
|
3160 DCC_OP_RESP *resp, int resp_max_len) |
|
3161 { |
|
3162 DCC_SRVR_CLASS *class; |
|
3163 DCC_SRVR_ADDR *cur_addr; |
|
3164 #ifdef DCC_PKT_VERSION7 |
|
3165 DCC_REPORT old_report; |
|
3166 #endif |
|
3167 char addr_buf[80]; |
|
3168 int addrs_gen; |
|
3169 DCC_OP_NUM op_num_r; |
|
3170 DCC_XLOG_ENTRY *xloge; |
|
3171 SRVR_INX srvr_inx; |
|
3172 int xmit_num; |
|
3173 int next_xmit, us, remaining, nfds; |
|
3174 u_char gotit; |
|
3175 int i; |
|
3176 |
|
3177 if (emsg) |
|
3178 *emsg = '\0'; |
|
3179 dcc_ctxts_lock(); |
|
3180 if (!dcc_clnt_info |
|
3181 && !dcc_map_info(emsg, 0, -1)) { |
|
3182 dcc_ctxts_unlock(); |
|
3183 if (srvr_idp) |
|
3184 *srvr_idp = DCC_ID_INVALID; |
|
3185 return 0; |
|
3186 } |
|
3187 /* Get & lock common info. |
|
3188 * insist on a server to talk to so that class->srvr_inx is sane */ |
|
3189 if (!dcc_clnt_rdy(emsg, ctxt, |
|
3190 clnt_fgs & ~(DCC_CLNT_FG_BAD_SRVR_OK |
|
3191 | DCC_CLNT_FG_NO_PICK_SRVR))) { |
|
3192 dcc_ctxts_unlock(); |
|
3193 if (srvr_idp) |
|
3194 *srvr_idp = DCC_ID_INVALID; |
|
3195 return 0; |
|
3196 } |
|
3197 class = DCC_GREY2CLASS(clnt_fgs & DCC_CLNT_FG_GREY); |
|
3198 |
|
3199 if (resp_max_len > ISZ(*resp)) |
|
3200 resp_max_len = ISZ(*resp); |
|
3201 else if (resp_max_len < ISZ(resp->hdr)) |
|
3202 dcc_logbad(EX_SOFTWARE, "dcc_clnt_op(resp_max_len=%d)", |
|
3203 resp_max_len); |
|
3204 |
|
3205 /* use server that the caller wants, |
|
3206 * if the caller specified the valid index of a server */ |
|
3207 if (!srvr_inxp |
|
3208 || !GOOD_SRVR(class, srvr_inx = *srvr_inxp)) |
|
3209 srvr_inx = class->srvr_inx; |
|
3210 |
|
3211 cur_addr = &class->addrs[srvr_inx]; |
|
3212 if (srvr_idp) |
|
3213 *srvr_idp = cur_addr->srvr_id; |
|
3214 if (resp_su) |
|
3215 dcc_mk_su(resp_su, cur_addr->ip.family, |
|
3216 &cur_addr->ip.u, cur_addr->ip.port); |
|
3217 addrs_gen = class->gen; |
|
3218 |
|
3219 ++dcc_clnt_info->proto_hdr.op_nums.r; |
|
3220 op_num_r = msg->op_nums.r; |
|
3221 memcpy(msg, &dcc_clnt_info->proto_hdr, sizeof(*msg)); |
|
3222 /* old transaction ID for retransmissions */ |
|
3223 if (clnt_fgs & DCC_CLNT_FG_RETRANS) |
|
3224 msg->op_nums.r = op_num_r; |
|
3225 if (cur_addr->srvr_pkt_vers > DCC_PKT_VERSION_MAX |
|
3226 || cur_addr->srvr_pkt_vers < DCC_PKT_VERSION_MIN) { |
|
3227 dcc_pemsg(EX_DATAERR, emsg, "impossible pkt_vers %d for %s", |
|
3228 cur_addr->srvr_pkt_vers, |
|
3229 addr2str(addr_buf, sizeof(addr_buf), class, |
|
3230 addrs_gen, cur_addr, 0)); |
|
3231 dcc_info_unlock(0); |
|
3232 dcc_ctxts_unlock(); |
|
3233 if (srvr_idp) |
|
3234 *srvr_idp = DCC_ID_INVALID; |
|
3235 return 0; |
|
3236 } |
|
3237 |
|
3238 #ifdef DCC_PKT_VERSION7 |
|
3239 /* convert new report to old */ |
|
3240 if (cur_addr->srvr_pkt_vers <= DCC_PKT_VERSION7 |
|
3241 && op == DCC_OP_REPORT) { |
|
3242 DCC_TGTS tgts; |
|
3243 |
|
3244 tgts = ntohl(((DCC_REPORT *)msg)->tgts); |
|
3245 #ifdef DCC_PKT_VERSION4 |
|
3246 if (cur_addr->srvr_pkt_vers == DCC_PKT_VERSION4 |
|
3247 && (tgts & DCC_TGTS_SPAM)) { |
|
3248 memcpy(&old_report, msg, msg_len); |
|
3249 old_report.tgts = htonl(DCC_TGTS_TOO_MANY); |
|
3250 msg = &old_report.hdr; |
|
3251 } |
|
3252 #endif |
|
3253 } |
|
3254 #endif /* DCC_PKT_VERSION7 */ |
|
3255 |
|
3256 msg->pkt_vers = cur_addr->srvr_pkt_vers; |
|
3257 msg->op_nums.p = getpid(); |
|
3258 msg->op = op; |
|
3259 gotit = 0; |
|
3260 |
|
3261 /* The measured RTTs to servers helps the client pick a server |
|
3262 * that will respond quickly and reliably and to know when to |
|
3263 * retransmit a request that is lost due to network congestion or |
|
3264 * bit rot. |
|
3265 * |
|
3266 * It is desirable for a client to concentrate its reports to |
|
3267 * a single server. That makes detecting spam by this and other |
|
3268 * clients quicker. |
|
3269 * |
|
3270 * A client should retransmit when its initial transmission is lost |
|
3271 * due to bit rot or congestion. In case the loss is due to |
|
3272 * congestion, it should retransmit only a limited number of |
|
3273 * times and with increasing delays between retransmissions. |
|
3274 * |
|
3275 * It is more important that some requests from clients reach |
|
3276 * a DCC server than others. Most DCC checksum reports are not about |
|
3277 * spam, and so it is best to not spend too much network bandwidth |
|
3278 * retransmitting checksum reports or to delay the processing of the |
|
3279 * messages. Administrative commands must be tried harder. |
|
3280 * Therefore, let the caller of this routine decide whether to retry. |
|
3281 * This routine merely increases the measured RTT after failures. */ |
|
3282 |
|
3283 memset(&ctxt->xlog, 0, sizeof(ctxt->xlog)); |
|
3284 ctxt->xlog.base = ctxt->xlog.next = ctxt->xlog_entries; |
|
3285 ctxt->xlog.last = LAST(ctxt->xlog_entries); |
|
3286 xmit_num = 0; |
|
3287 next_xmit = ctxt->now_us; |
|
3288 |
|
3289 /* Transmit, wait for a response, and repeat if needed. |
|
3290 * The initial transmission is done as if it were a retransmission. */ |
|
3291 for (;;) { |
|
3292 us = next_xmit - ctxt->now_us; |
|
3293 if (us <= 0) { |
|
3294 /* We have delayed long enough for each outstanding |
|
3295 * transmission. We are done if we have sent enough */ |
|
3296 if (xmit_num >= DCC_MAX_XMITS) |
|
3297 break; |
|
3298 |
|
3299 /* stop if we don't have enough time to wait */ |
|
3300 us = retrans_time(cur_addr->rtt, xmit_num); |
|
3301 remaining = DCC_MAX_DELAY - ctxt->now_us; |
|
3302 if (us > remaining) { |
|
3303 if (remaining < DCC_MIN_RTT) |
|
3304 break; |
|
3305 us = remaining; |
|
3306 } |
|
3307 |
|
3308 /* wait as long as possible on the last try */ |
|
3309 if (++xmit_num == DCC_MAX_XMITS |
|
3310 && us < DCC_MAX_RTT) { |
|
3311 if (remaining > DCC_MAX_RTT) |
|
3312 us = DCC_MAX_RTT; |
|
3313 else |
|
3314 us = remaining; |
|
3315 } |
|
3316 next_xmit = us + ctxt->now_us; |
|
3317 |
|
3318 /* Because of the flooding algorithm among DCC servers, |
|
3319 * it is important that only a single server receive |
|
3320 * reports of the checksums for a mail message. |
|
3321 * That implies that retransmissions of reports must |
|
3322 * go to the original server, even if some other local |
|
3323 * client has re-resolved hostnames or switched |
|
3324 * to a better server. |
|
3325 * Otherwise our retransmissions to different servers |
|
3326 * would not be recognized as retransmissions but |
|
3327 * reports about separate copies of the mail message. |
|
3328 * Sp we should not retransmit if the server |
|
3329 * address table changes. */ |
|
3330 if (addrs_gen != class->gen |
|
3331 && op == DCC_OP_REPORT |
|
3332 && !(clnt_fgs & DCC_CLNT_FG_GREY)) { |
|
3333 if (dcc_clnt_debug) |
|
3334 dcc_trace_msg("server address" |
|
3335 " generation changed"); |
|
3336 break; |
|
3337 } |
|
3338 |
|
3339 if (!GOOD_NAM(cur_addr->nam_inx)) { |
|
3340 if (dcc_clnt_debug) |
|
3341 dcc_trace_msg("server deleted"); |
|
3342 break; |
|
3343 } |
|
3344 |
|
3345 /* use a connected socket early to get port |
|
3346 * unreachable ICMP error messages, but do not |
|
3347 * connect later to detect multi-homing */ |
|
3348 if (0 >= clnt_xmit(ctxt, class, cur_addr, msg, msg_len, |
|
3349 (!(cur_addr->flags |
|
3350 & DCC_SRVR_ADDR_MHOME) |
|
3351 && xmit_num < DCC_MAX_XMITS/2 |
|
3352 && ctxt->now_us<=DCC_MAX_DELAY/2))) |
|
3353 break; |
|
3354 } |
|
3355 |
|
3356 /* release the mapped info while we wait for an answer */ |
|
3357 if (!dcc_info_unlock(emsg)) { |
|
3358 dcc_ctxts_unlock(); |
|
3359 if (srvr_idp) |
|
3360 *srvr_idp = DCC_ID_INVALID; |
|
3361 return 0; |
|
3362 } |
|
3363 dcc_ctxts_unlock(); |
|
3364 nfds = dcc_select_poll(emsg, ctxt->soc, 1, us); |
|
3365 if (nfds < 0) { |
|
3366 /* note error, but we may already have an answer */ |
|
3367 dcc_ctxts_lock(); |
|
3368 class = DCC_GREY2CLASS(clnt_fgs & DCC_CLNT_FG_GREY); |
|
3369 break; |
|
3370 } |
|
3371 if (!get_now(emsg, ctxt)) |
|
3372 return 0; /* simply give up if time jumped */ |
|
3373 |
|
3374 /* recover the lock so that we can record the result of the |
|
3375 * newly arrived answer in the shared and mapped file */ |
|
3376 dcc_ctxts_lock(); |
|
3377 class = DCC_GREY2CLASS(clnt_fgs & DCC_CLNT_FG_GREY); |
|
3378 if (!dcc_info_lock(emsg)) { |
|
3379 dcc_ctxts_unlock(); |
|
3380 if (srvr_idp) |
|
3381 *srvr_idp = DCC_ID_INVALID; |
|
3382 return 0; |
|
3383 } |
|
3384 |
|
3385 if (nfds > 0) { |
|
3386 u_char unreachable = 0; |
|
3387 for (;;) { |
|
3388 DCC_OP_RESP buf; |
|
3389 |
|
3390 i = clnt_recv(ctxt, class, &buf, |
|
3391 min(ISZ(buf), resp_max_len), |
|
3392 msg, &xloge); |
|
3393 if (i <= 0) |
|
3394 break; |
|
3395 if (i == 1) { |
|
3396 /* stop delaying after the first |
|
3397 * ICMP Unreachable message, |
|
3398 * but collect everything that has |
|
3399 * already arrived */ |
|
3400 unreachable = 1; |
|
3401 continue; |
|
3402 } |
|
3403 |
|
3404 update_rtt(ctxt, class, xloge, |
|
3405 ctxt->now_us - xloge->sent_us |
|
3406 + ((op != DCC_OP_REPORT |
|
3407 && op != DCC_OP_QUERY) |
|
3408 ? cur_addr->srvr_wait : 0)); |
|
3409 |
|
3410 /* save the last answer we get */ |
|
3411 memcpy(resp, &buf, ntohs(buf.hdr.len)); |
|
3412 gotit = 1; |
|
3413 } |
|
3414 if (i < 0 || unreachable || gotit) |
|
3415 break; |
|
3416 } |
|
3417 } |
|
3418 /* the contexts and the shared information are locked */ |
|
3419 |
|
3420 /* penalize server for lost packets */ |
|
3421 resp_rates(ctxt, class, 0); |
|
3422 |
|
3423 /* fail if the server did not answer at all */ |
|
3424 if (!gotit) { |
|
3425 #if 0 |
|
3426 system("./abort_dccd"); |
|
3427 #endif |
|
3428 flush_emsg(emsg, dcc_clnt_debug); |
|
3429 dcc_pemsg(EX_TEMPFAIL, emsg, "no %s answer from %s after %d ms", |
|
3430 DCC_IS_GREY_STR(class), |
|
3431 addr2str(addr_buf, sizeof(addr_buf), class, |
|
3432 addrs_gen, cur_addr, 0), |
|
3433 ctxt->now_us/1000); |
|
3434 /* Since we got no answer at all, look for a different server. |
|
3435 * If we can't find any server or a different server |
|
3436 * or if we have already spent too much time, |
|
3437 * then don't try again for a while to not delay the MTA. |
|
3438 * If we find another server, then return the valid server-ID |
|
3439 * of the non-responsive server to let the caller know that it |
|
3440 * can try again immediately. */ |
|
3441 if (srvr_inxp && srvr_inx == *srvr_inxp) { |
|
3442 /* but only if not using a caller specified server */ |
|
3443 if (srvr_idp) |
|
3444 *srvr_idp = DCC_ID_INVALID; |
|
3445 } else if (!pick_srvr(0, class) |
|
3446 || srvr_inx == class->srvr_inx) { |
|
3447 if (srvr_idp) { |
|
3448 if (dcc_clnt_debug) |
|
3449 dcc_trace_msg("no better alternate" |
|
3450 " for retry"); |
|
3451 *srvr_idp = DCC_ID_INVALID; |
|
3452 } |
|
3453 fail_more(ctxt, class); |
|
3454 } else if (srvr_idp |
|
3455 && (i = retrans_time(class->addrs[class ->srvr_inx |
|
3456 ].rtt, 0), |
|
3457 ctxt->now_us + i >= DCC_MAX_DELAY)) { |
|
3458 /* discourage the caller from trying the other server |
|
3459 * if the total delay after trying the other server |
|
3460 * would be excessive */ |
|
3461 if (dcc_clnt_debug) |
|
3462 dcc_trace_msg("alternate too slow for retry" |
|
3463 " with rtt %d ms after %d ms", |
|
3464 i/1000, |
|
3465 ctxt->now_us/1000); |
|
3466 *srvr_idp = DCC_ID_INVALID; |
|
3467 } |
|
3468 dcc_info_unlock(0); |
|
3469 dcc_ctxts_unlock(); |
|
3470 return 0; |
|
3471 } |
|
3472 |
|
3473 /* reset failure backoff */ |
|
3474 class->fail_exp = 0; |
|
3475 |
|
3476 if (!dcc_info_unlock(emsg)) { |
|
3477 dcc_ctxts_unlock(); |
|
3478 if (srvr_idp) |
|
3479 *srvr_idp = DCC_ID_INVALID; |
|
3480 return 0; |
|
3481 } |
|
3482 dcc_ctxts_unlock(); |
|
3483 |
|
3484 flush_emsg(emsg, dcc_clnt_debug); |
|
3485 return 1; |
|
3486 } |