Mercurial > notdcc
comparison dcclib/clnt_send.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c7f6b056b673 |
---|---|
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 } |