1 /* 2 * ntp_util.c - stuff I didn't have any other place for 3 */ 4 5 #ifdef HAVE_CONFIG_H 6 # include <config.h> 7 #endif 8 9 #include "ntpd.h" 10 #include "ntp_io.h" 11 #include "ntp_unixtime.h" 12 #include "ntp_filegen.h" 13 #include "ntp_if.h" 14 #include "ntp_stdlib.h" 15 16 #include <stdio.h> 17 #include <ctype.h> 18 #include <sys/types.h> 19 #ifdef HAVE_SYS_IOCTL_H 20 # include <sys/ioctl.h> 21 #endif 22 23 #ifdef HAVE_IEEEFP_H 24 # include <ieeefp.h> 25 #endif 26 #ifdef HAVE_MATH_H 27 # include <math.h> 28 #endif 29 30 #ifdef DOSYNCTODR 31 #if !defined(VMS) 32 #include <sys/resource.h> 33 #endif /* VMS */ 34 #endif 35 36 #if defined(VMS) 37 #include <descrip.h> 38 #endif /* VMS */ 39 40 /* 41 * This contains odds and ends. Right now the only thing you'll find 42 * in here is the hourly stats printer and some code to support 43 * rereading the keys file, but I may eventually put other things in 44 * here such as code to do something with the leap bits. 45 */ 46 /* 47 * Name of the keys file 48 */ 49 static char *key_file_name; 50 51 /* 52 * The name of the drift_comp file and the temporary. 53 */ 54 static char *stats_drift_file; 55 static char *stats_temp_file; 56 57 /* 58 * Statistics file stuff 59 */ 60 #ifndef NTP_VAR 61 #ifndef SYS_WINNT 62 #define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 63 #else 64 #define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 65 #endif /* SYS_WINNT */ 66 #endif 67 68 #ifndef MAXPATHLEN 69 #define MAXPATHLEN 256 70 #endif 71 72 static char statsdir[MAXPATHLEN] = NTP_VAR; 73 74 static FILEGEN peerstats; 75 static FILEGEN loopstats; 76 static FILEGEN clockstats; 77 static FILEGEN rawstats; 78 static FILEGEN sysstats; 79 #ifdef OPENSSL 80 static FILEGEN cryptostats; 81 #endif /* OPENSSL */ 82 83 /* 84 * This controls whether stats are written to the fileset. Provided 85 * so that ntpdc can turn off stats when the file system fills up. 86 */ 87 int stats_control; 88 89 /* 90 * init_util - initialize the utilities 91 */ 92 void 93 init_util(void) 94 { 95 stats_drift_file = 0; 96 stats_temp_file = 0; 97 key_file_name = 0; 98 99 #define PEERNAME "peerstats" 100 #define LOOPNAME "loopstats" 101 #define CLOCKNAME "clockstats" 102 #define RAWNAME "rawstats" 103 #define STANAME "systats" 104 #ifdef OPENSSL 105 #define CRYPTONAME "cryptostats" 106 #endif /* OPENSSL */ 107 108 peerstats.fp = NULL; 109 peerstats.prefix = &statsdir[0]; 110 peerstats.basename = (char*)emalloc(strlen(PEERNAME)+1); 111 strcpy(peerstats.basename, PEERNAME); 112 peerstats.id = 0; 113 peerstats.type = FILEGEN_DAY; 114 peerstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ 115 filegen_register("peerstats", &peerstats); 116 117 loopstats.fp = NULL; 118 loopstats.prefix = &statsdir[0]; 119 loopstats.basename = (char*)emalloc(strlen(LOOPNAME)+1); 120 strcpy(loopstats.basename, LOOPNAME); 121 loopstats.id = 0; 122 loopstats.type = FILEGEN_DAY; 123 loopstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ 124 filegen_register("loopstats", &loopstats); 125 126 clockstats.fp = NULL; 127 clockstats.prefix = &statsdir[0]; 128 clockstats.basename = (char*)emalloc(strlen(CLOCKNAME)+1); 129 strcpy(clockstats.basename, CLOCKNAME); 130 clockstats.id = 0; 131 clockstats.type = FILEGEN_DAY; 132 clockstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ 133 filegen_register("clockstats", &clockstats); 134 135 rawstats.fp = NULL; 136 rawstats.prefix = &statsdir[0]; 137 rawstats.basename = (char*)emalloc(strlen(RAWNAME)+1); 138 strcpy(rawstats.basename, RAWNAME); 139 rawstats.id = 0; 140 rawstats.type = FILEGEN_DAY; 141 rawstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ 142 filegen_register("rawstats", &rawstats); 143 144 sysstats.fp = NULL; 145 sysstats.prefix = &statsdir[0]; 146 sysstats.basename = (char*)emalloc(strlen(STANAME)+1); 147 strcpy(sysstats.basename, STANAME); 148 sysstats.id = 0; 149 sysstats.type = FILEGEN_DAY; 150 sysstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ 151 filegen_register("sysstats", &sysstats); 152 153 #ifdef OPENSSL 154 cryptostats.fp = NULL; 155 cryptostats.prefix = &statsdir[0]; 156 cryptostats.basename = (char*)emalloc(strlen(CRYPTONAME)+1); 157 strcpy(cryptostats.basename, CRYPTONAME); 158 cryptostats.id = 0; 159 cryptostats.type = FILEGEN_DAY; 160 cryptostats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ 161 filegen_register("cryptostats", &cryptostats); 162 #endif /* OPENSSL */ 163 164 #undef PEERNAME 165 #undef LOOPNAME 166 #undef CLOCKNAME 167 #undef RAWNAME 168 #undef STANAME 169 #ifdef OPENSSL 170 #undef CRYPTONAME 171 #endif /* OPENSSL */ 172 } 173 174 175 /* 176 * hourly_stats - print some interesting stats 177 */ 178 void 179 hourly_stats(void) 180 { 181 FILE *fp; 182 183 #ifdef DOSYNCTODR 184 struct timeval tv; 185 #if !defined(VMS) 186 int prio_set; 187 #endif 188 #ifdef HAVE_GETCLOCK 189 struct timespec ts; 190 #endif 191 int o_prio; 192 193 /* 194 * Sometimes having a Sun can be a drag. 195 * 196 * The kernel variable dosynctodr controls whether the system's 197 * soft clock is kept in sync with the battery clock. If it 198 * is zero, then the soft clock is not synced, and the battery 199 * clock is simply left to rot. That means that when the system 200 * reboots, the battery clock (which has probably gone wacky) 201 * sets the soft clock. That means ntpd starts off with a very 202 * confused idea of what time it is. It then takes a large 203 * amount of time to figure out just how wacky the battery clock 204 * has made things drift, etc, etc. The solution is to make the 205 * battery clock sync up to system time. The way to do THAT is 206 * to simply set the time of day to the current time of day, but 207 * as quickly as possible. This may, or may not be a sensible 208 * thing to do. 209 * 210 * CAVEAT: settimeofday() steps the sun clock by about 800 us, 211 * so setting DOSYNCTODR seems a bad idea in the 212 * case of us resolution 213 */ 214 215 #if !defined(VMS) 216 /* (prr) getpriority returns -1 on error, but -1 is also a valid 217 * return value (!), so instead we have to zero errno before the 218 * call and check it for non-zero afterwards. 219 */ 220 errno = 0; 221 prio_set = 0; 222 o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 223 224 /* 225 * (prr) if getpriority succeeded, call setpriority to raise 226 * scheduling priority as high as possible. If that succeeds 227 * as well, set the prio_set flag so we remember to reset 228 * priority to its previous value below. Note that on Solaris 229 * 2.6 (and beyond?), both getpriority and setpriority will fail 230 * with ESRCH, because sched_setscheduler (called from main) put 231 * us in the real-time scheduling class which setpriority 232 * doesn't know about. Being in the real-time class is better 233 * than anything setpriority can do, anyhow, so this error is 234 * silently ignored. 235 */ 236 if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 237 prio_set = 1; /* overdrive */ 238 #endif /* VMS */ 239 #ifdef HAVE_GETCLOCK 240 (void) getclock(TIMEOFDAY, &ts); 241 tv.tv_sec = ts.tv_sec; 242 tv.tv_usec = ts.tv_nsec / 1000; 243 #else /* not HAVE_GETCLOCK */ 244 GETTIMEOFDAY(&tv,(struct timezone *)NULL); 245 #endif /* not HAVE_GETCLOCK */ 246 if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) { 247 msyslog(LOG_ERR, "can't sync battery time: %m"); 248 } 249 #if !defined(VMS) 250 if (prio_set) 251 setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 252 #endif /* VMS */ 253 #endif /* DOSYNCTODR */ 254 255 NLOG(NLOG_SYSSTATIST) 256 msyslog(LOG_INFO, 257 "offset %.6f sec freq %.3f ppm error %.6f poll %d", 258 last_offset, drift_comp * 1e6, sys_jitter, 259 sys_poll); 260 261 262 record_sys_stats(); 263 if (stats_drift_file != 0) { 264 if ((fp = fopen(stats_temp_file, "w")) == NULL) { 265 msyslog(LOG_ERR, "can't open %s: %m", 266 stats_temp_file); 267 return; 268 } 269 fprintf(fp, "%.3f\n", drift_comp * 1e6); 270 (void)fclose(fp); 271 /* atomic */ 272 #ifdef SYS_WINNT 273 (void) _unlink(stats_drift_file); /* rename semantics differ under NT */ 274 #endif /* SYS_WINNT */ 275 276 #ifndef NO_RENAME 277 (void) rename(stats_temp_file, stats_drift_file); 278 #else 279 /* we have no rename NFS of ftp in use*/ 280 if ((fp = fopen(stats_drift_file, "w")) == NULL) { 281 msyslog(LOG_ERR, "can't open %s: %m", 282 stats_drift_file); 283 return; 284 } 285 286 #endif 287 288 #if defined(VMS) 289 /* PURGE */ 290 { 291 $DESCRIPTOR(oldvers,";-1"); 292 struct dsc$descriptor driftdsc = { 293 strlen(stats_drift_file),0,0,stats_drift_file }; 294 295 while(lib$delete_file(&oldvers,&driftdsc) & 1) ; 296 } 297 #endif 298 } 299 } 300 301 302 /* 303 * stats_config - configure the stats operation 304 */ 305 void 306 stats_config( 307 int item, 308 char *invalue /* only one type so far */ 309 ) 310 { 311 FILE *fp; 312 char *value; 313 double old_drift; 314 int len; 315 316 /* 317 * Expand environment strings under Windows NT, since the 318 * command interpreter doesn't do this, the program must. 319 */ 320 #ifdef SYS_WINNT 321 char newvalue[MAX_PATH], parameter[MAX_PATH]; 322 323 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 324 switch(item) { 325 case STATS_FREQ_FILE: 326 strcpy(parameter,"STATS_FREQ_FILE"); 327 break; 328 case STATS_STATSDIR: 329 strcpy(parameter,"STATS_STATSDIR"); 330 break; 331 case STATS_PID_FILE: 332 strcpy(parameter,"STATS_PID_FILE"); 333 break; 334 default: 335 strcpy(parameter,"UNKNOWN"); 336 break; 337 } 338 value = invalue; 339 340 msyslog(LOG_ERR, 341 "ExpandEnvironmentStrings(%s) failed: %m\n", parameter); 342 } else { 343 value = newvalue; 344 } 345 #else 346 value = invalue; 347 #endif /* SYS_WINNT */ 348 349 switch(item) { 350 case STATS_FREQ_FILE: 351 if (stats_drift_file != 0) { 352 (void) free(stats_drift_file); 353 (void) free(stats_temp_file); 354 stats_drift_file = 0; 355 stats_temp_file = 0; 356 } 357 358 if (value == 0 || (len = strlen(value)) == 0) 359 break; 360 361 stats_drift_file = (char*)emalloc((u_int)(len + 1)); 362 #if !defined(VMS) 363 stats_temp_file = (char*)emalloc((u_int)(len + 364 sizeof(".TEMP"))); 365 #else 366 stats_temp_file = (char*)emalloc((u_int)(len + 367 sizeof("-TEMP"))); 368 #endif /* VMS */ 369 memmove(stats_drift_file, value, (unsigned)(len+1)); 370 memmove(stats_temp_file, value, (unsigned)len); 371 #if !defined(VMS) 372 memmove(stats_temp_file + len, ".TEMP", 373 sizeof(".TEMP")); 374 #else 375 memmove(stats_temp_file + len, "-TEMP", 376 sizeof("-TEMP")); 377 #endif /* VMS */ 378 379 /* 380 * Open drift file and read frequency. If the file is 381 * missing or contains errors, tell the loop to reset. 382 */ 383 if ((fp = fopen(stats_drift_file, "r")) == NULL) { 384 loop_config(LOOP_DRIFTCOMP, 1e9); 385 break; 386 } 387 if (fscanf(fp, "%lf", &old_drift) != 1) { 388 msyslog(LOG_ERR, "Frequency format error in %s", 389 stats_drift_file); 390 loop_config(LOOP_DRIFTCOMP, 1e9); 391 fclose(fp); 392 break; 393 } 394 fclose(fp); 395 msyslog(LOG_INFO, 396 "frequency initialized %.3f PPM from %s", 397 old_drift, stats_drift_file); 398 loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); 399 break; 400 401 case STATS_STATSDIR: 402 if (strlen(value) >= sizeof(statsdir)) { 403 msyslog(LOG_ERR, 404 "value for statsdir too long (>%d, sigh)", 405 (int)sizeof(statsdir)-1); 406 } else { 407 l_fp now; 408 409 get_systime(&now); 410 strcpy(statsdir,value); 411 if(peerstats.prefix == &statsdir[0] && 412 peerstats.fp != NULL) { 413 fclose(peerstats.fp); 414 peerstats.fp = NULL; 415 filegen_setup(&peerstats, now.l_ui); 416 } 417 if(loopstats.prefix == &statsdir[0] && 418 loopstats.fp != NULL) { 419 fclose(loopstats.fp); 420 loopstats.fp = NULL; 421 filegen_setup(&loopstats, now.l_ui); 422 } 423 if(clockstats.prefix == &statsdir[0] && 424 clockstats.fp != NULL) { 425 fclose(clockstats.fp); 426 clockstats.fp = NULL; 427 filegen_setup(&clockstats, now.l_ui); 428 } 429 if(rawstats.prefix == &statsdir[0] && 430 rawstats.fp != NULL) { 431 fclose(rawstats.fp); 432 rawstats.fp = NULL; 433 filegen_setup(&rawstats, now.l_ui); 434 } 435 if(sysstats.prefix == &statsdir[0] && 436 sysstats.fp != NULL) { 437 fclose(sysstats.fp); 438 sysstats.fp = NULL; 439 filegen_setup(&sysstats, now.l_ui); 440 } 441 #ifdef OPENSSL 442 if(cryptostats.prefix == &statsdir[0] && 443 cryptostats.fp != NULL) { 444 fclose(cryptostats.fp); 445 cryptostats.fp = NULL; 446 filegen_setup(&cryptostats, now.l_ui); 447 } 448 #endif /* OPENSSL */ 449 } 450 break; 451 452 case STATS_PID_FILE: 453 if ((fp = fopen(value, "w")) == NULL) { 454 msyslog(LOG_ERR, "Can't open %s: %m", value); 455 break; 456 } 457 fprintf(fp, "%d", (int) getpid()); 458 fclose(fp);; 459 break; 460 461 default: 462 /* oh well */ 463 break; 464 } 465 } 466 467 /* 468 * record_peer_stats - write peer statistics to file 469 * 470 * file format: 471 * day (mjd) 472 * time (s past UTC midnight) 473 * peer (ip address) 474 * peer status word (hex) 475 * peer offset (s) 476 * peer delay (s) 477 * peer error bound (s) 478 * peer error (s) 479 */ 480 void 481 record_peer_stats( 482 struct sockaddr_storage *addr, 483 int status, 484 double offset, 485 double delay, 486 double dispersion, 487 double skew 488 ) 489 { 490 l_fp now; 491 u_long day; 492 493 if (!stats_control) 494 return; 495 496 get_systime(&now); 497 filegen_setup(&peerstats, now.l_ui); 498 day = now.l_ui / 86400 + MJD_1900; 499 now.l_ui %= 86400; 500 if (peerstats.fp != NULL) { 501 fprintf(peerstats.fp, 502 "%lu %s %s %x %.9f %.9f %.9f %.9f\n", 503 day, ulfptoa(&now, 3), stoa(addr), status, offset, 504 delay, dispersion, skew); 505 fflush(peerstats.fp); 506 } 507 } 508 /* 509 * record_loop_stats - write loop filter statistics to file 510 * 511 * file format: 512 * day (mjd) 513 * time (s past midnight) 514 * offset (s) 515 * frequency (approx ppm) 516 * time constant (log base 2) 517 */ 518 void 519 record_loop_stats( 520 double offset, 521 double freq, 522 double jitter, 523 double stability, 524 int spoll 525 ) 526 { 527 l_fp now; 528 u_long day; 529 530 if (!stats_control) 531 return; 532 533 get_systime(&now); 534 filegen_setup(&loopstats, now.l_ui); 535 day = now.l_ui / 86400 + MJD_1900; 536 now.l_ui %= 86400; 537 if (loopstats.fp != NULL) { 538 fprintf(loopstats.fp, "%lu %s %.9f %.6f %.9f %.6f %d\n", 539 day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 540 stability * 1e6, spoll); 541 fflush(loopstats.fp); 542 } 543 } 544 545 /* 546 * record_clock_stats - write clock statistics to file 547 * 548 * file format: 549 * day (mjd) 550 * time (s past midnight) 551 * peer (ip address) 552 * text message 553 */ 554 void 555 record_clock_stats( 556 struct sockaddr_storage *addr, 557 const char *text 558 ) 559 { 560 l_fp now; 561 u_long day; 562 563 if (!stats_control) 564 return; 565 566 get_systime(&now); 567 filegen_setup(&clockstats, now.l_ui); 568 day = now.l_ui / 86400 + MJD_1900; 569 now.l_ui %= 86400; 570 if (clockstats.fp != NULL) { 571 fprintf(clockstats.fp, "%lu %s %s %s\n", 572 day, ulfptoa(&now, 3), stoa(addr), text); 573 fflush(clockstats.fp); 574 } 575 } 576 577 /* 578 * record_raw_stats - write raw timestamps to file 579 * 580 * 581 * file format 582 * time (s past midnight) 583 * peer ip address 584 * local ip address 585 * t1 t2 t3 t4 timestamps 586 */ 587 void 588 record_raw_stats( 589 struct sockaddr_storage *srcadr, 590 struct sockaddr_storage *dstadr, 591 l_fp *t1, 592 l_fp *t2, 593 l_fp *t3, 594 l_fp *t4 595 ) 596 { 597 l_fp now; 598 u_long day; 599 600 if (!stats_control) 601 return; 602 603 get_systime(&now); 604 filegen_setup(&rawstats, now.l_ui); 605 day = now.l_ui / 86400 + MJD_1900; 606 now.l_ui %= 86400; 607 if (rawstats.fp != NULL) { 608 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n", 609 day, ulfptoa(&now, 3), stoa(srcadr), stoa(dstadr), 610 ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9), 611 ulfptoa(t4, 9)); 612 fflush(rawstats.fp); 613 } 614 } 615 616 617 /* 618 * record_sys_stats - write system statistics to file 619 * 620 * file format 621 * time (s past midnight) 622 * time since startup (hr) 623 * packets recieved 624 * packets processed 625 * current version 626 * previous version 627 * bad version 628 * access denied 629 * bad length or format 630 * bad authentication 631 * rate exceeded 632 */ 633 void 634 record_sys_stats(void) 635 { 636 l_fp now; 637 u_long day; 638 639 if (!stats_control) 640 return; 641 642 get_systime(&now); 643 filegen_setup(&sysstats, now.l_ui); 644 day = now.l_ui / 86400 + MJD_1900; 645 now.l_ui %= 86400; 646 if (sysstats.fp != NULL) { 647 fprintf(sysstats.fp, 648 "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 649 day, ulfptoa(&now, 3), sys_stattime / 3600, 650 sys_received, sys_processed, sys_newversionpkt, 651 sys_oldversionpkt, sys_unknownversion, 652 sys_restricted, sys_badlength, sys_badauth, 653 sys_limitrejected); 654 fflush(sysstats.fp); 655 proto_clr_stats(); 656 } 657 } 658 659 660 #ifdef OPENSSL 661 /* 662 * record_crypto_stats - write crypto statistics to file 663 * 664 * file format: 665 * day (mjd) 666 * time (s past midnight) 667 * peer (ip address) 668 * text message 669 */ 670 void 671 record_crypto_stats( 672 struct sockaddr_storage *addr, 673 const char *text 674 ) 675 { 676 l_fp now; 677 u_long day; 678 679 if (!stats_control) 680 return; 681 682 get_systime(&now); 683 filegen_setup(&cryptostats, now.l_ui); 684 day = now.l_ui / 86400 + MJD_1900; 685 now.l_ui %= 86400; 686 if (cryptostats.fp != NULL) { 687 if (addr == NULL) 688 fprintf(cryptostats.fp, "%lu %s %s\n", 689 day, ulfptoa(&now, 3), text); 690 else 691 fprintf(cryptostats.fp, "%lu %s %s %s\n", 692 day, ulfptoa(&now, 3), stoa(addr), text); 693 fflush(cryptostats.fp); 694 } 695 } 696 #endif /* OPENSSL */ 697 698 699 /* 700 * getauthkeys - read the authentication keys from the specified file 701 */ 702 void 703 getauthkeys( 704 char *keyfile 705 ) 706 { 707 int len; 708 709 len = strlen(keyfile); 710 if (len == 0) 711 return; 712 713 if (key_file_name != 0) { 714 if (len > (int)strlen(key_file_name)) { 715 (void) free(key_file_name); 716 key_file_name = 0; 717 } 718 } 719 720 if (key_file_name == 0) { 721 #ifndef SYS_WINNT 722 key_file_name = (char*)emalloc((u_int) (len + 1)); 723 #else 724 key_file_name = (char*)emalloc((u_int) (MAXPATHLEN)); 725 #endif 726 } 727 #ifndef SYS_WINNT 728 memmove(key_file_name, keyfile, (unsigned)(len+1)); 729 #else 730 if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN)) 731 { 732 msyslog(LOG_ERR, 733 "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n"); 734 } 735 #endif /* SYS_WINNT */ 736 737 authreadkeys(key_file_name); 738 } 739 740 741 /* 742 * rereadkeys - read the authentication key file over again. 743 */ 744 void 745 rereadkeys(void) 746 { 747 if (key_file_name != 0) 748 authreadkeys(key_file_name); 749 } 750 751 /* 752 * sock_hash - hash an sockaddr_storage structure 753 */ 754 int 755 sock_hash( 756 struct sockaddr_storage *addr 757 ) 758 { 759 int hashVal; 760 int i; 761 int len; 762 char *ch; 763 764 hashVal = 0; 765 len = 0; 766 /* 767 * We can't just hash the whole thing because there are hidden 768 * fields in sockaddr_in6 that might be filled in by recvfrom(), 769 * so just use the family, port and address. 770 */ 771 ch = (char *)&addr->ss_family; 772 hashVal = 37 * hashVal + (int)*ch; 773 if (sizeof(addr->ss_family) > 1) { 774 ch++; 775 hashVal = 37 * hashVal + (int)*ch; 776 } 777 switch(addr->ss_family) { 778 case AF_INET: 779 ch = (char *)&((struct sockaddr_in *)addr)->sin_addr; 780 len = sizeof(struct in_addr); 781 break; 782 case AF_INET6: 783 ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr; 784 len = sizeof(struct in6_addr); 785 break; 786 } 787 788 for (i = 0; i < len ; i++) 789 hashVal = 37 * hashVal + (int)*(ch + i); 790 791 hashVal = hashVal % 128; /* % MON_HASH_SIZE hardcoded */ 792 793 if (hashVal < 0) 794 hashVal += 128; 795 796 return hashVal; 797 } 798