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 }