1 /* $OpenBSD: misc.c,v 1.71 2009/02/21 19:32:04 tobias Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/ioctl.h> 29 #include <sys/socket.h> 30 #include <sys/param.h> 31 32 #include <net/if.h> 33 #include <netinet/in.h> 34 #include <netinet/tcp.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <netdb.h> 39 #include <paths.h> 40 #include <pwd.h> 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "xmalloc.h" 48 #include "misc.h" 49 #include "log.h" 50 #include "ssh.h" 51 52 /* remove newline at end of string */ 53 char * 54 chop(char *s) 55 { 56 char *t = s; 57 while (*t) { 58 if (*t == '\n' || *t == '\r') { 59 *t = '\0'; 60 return s; 61 } 62 t++; 63 } 64 return s; 65 66 } 67 68 /* set/unset filedescriptor to non-blocking */ 69 int 70 set_nonblock(int fd) 71 { 72 int val; 73 74 val = fcntl(fd, F_GETFL, 0); 75 if (val < 0) { 76 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 77 return (-1); 78 } 79 if (val & O_NONBLOCK) { 80 debug3("fd %d is O_NONBLOCK", fd); 81 return (0); 82 } 83 debug2("fd %d setting O_NONBLOCK", fd); 84 val |= O_NONBLOCK; 85 if (fcntl(fd, F_SETFL, val) == -1) { 86 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, 87 strerror(errno)); 88 return (-1); 89 } 90 return (0); 91 } 92 93 int 94 unset_nonblock(int fd) 95 { 96 int val; 97 98 val = fcntl(fd, F_GETFL, 0); 99 if (val < 0) { 100 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 101 return (-1); 102 } 103 if (!(val & O_NONBLOCK)) { 104 debug3("fd %d is not O_NONBLOCK", fd); 105 return (0); 106 } 107 debug("fd %d clearing O_NONBLOCK", fd); 108 val &= ~O_NONBLOCK; 109 if (fcntl(fd, F_SETFL, val) == -1) { 110 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", 111 fd, strerror(errno)); 112 return (-1); 113 } 114 return (0); 115 } 116 117 const char * 118 ssh_gai_strerror(int gaierr) 119 { 120 if (gaierr == EAI_SYSTEM) 121 return strerror(errno); 122 return gai_strerror(gaierr); 123 } 124 125 /* disable nagle on socket */ 126 void 127 set_nodelay(int fd) 128 { 129 int opt; 130 socklen_t optlen; 131 132 optlen = sizeof opt; 133 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 134 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 135 return; 136 } 137 if (opt == 1) { 138 debug2("fd %d is TCP_NODELAY", fd); 139 return; 140 } 141 opt = 1; 142 debug2("fd %d setting TCP_NODELAY", fd); 143 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 144 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 145 } 146 147 /* Characters considered whitespace in strsep calls. */ 148 #define WHITESPACE " \t\r\n" 149 #define QUOTE "\"" 150 151 /* return next token in configuration line */ 152 char * 153 strdelim(char **s) 154 { 155 char *old; 156 int wspace = 0; 157 158 if (*s == NULL) 159 return NULL; 160 161 old = *s; 162 163 *s = strpbrk(*s, WHITESPACE QUOTE "="); 164 if (*s == NULL) 165 return (old); 166 167 if (*s[0] == '\"') { 168 memmove(*s, *s + 1, strlen(*s)); /* move nul too */ 169 /* Find matching quote */ 170 if ((*s = strpbrk(*s, QUOTE)) == NULL) { 171 return (NULL); /* no matching quote */ 172 } else { 173 *s[0] = '\0'; 174 return (old); 175 } 176 } 177 178 /* Allow only one '=' to be skipped */ 179 if (*s[0] == '=') 180 wspace = 1; 181 *s[0] = '\0'; 182 183 /* Skip any extra whitespace after first token */ 184 *s += strspn(*s + 1, WHITESPACE) + 1; 185 if (*s[0] == '=' && !wspace) 186 *s += strspn(*s + 1, WHITESPACE) + 1; 187 188 return (old); 189 } 190 191 struct passwd * 192 pwcopy(struct passwd *pw) 193 { 194 struct passwd *copy = xcalloc(1, sizeof(*copy)); 195 196 copy->pw_name = xstrdup(pw->pw_name); 197 copy->pw_passwd = xstrdup(pw->pw_passwd); 198 copy->pw_gecos = xstrdup(pw->pw_gecos); 199 copy->pw_uid = pw->pw_uid; 200 copy->pw_gid = pw->pw_gid; 201 copy->pw_expire = pw->pw_expire; 202 copy->pw_change = pw->pw_change; 203 copy->pw_class = xstrdup(pw->pw_class); 204 copy->pw_dir = xstrdup(pw->pw_dir); 205 copy->pw_shell = xstrdup(pw->pw_shell); 206 return copy; 207 } 208 209 /* 210 * Convert ASCII string to TCP/IP port number. 211 * Port must be >=0 and <=65535. 212 * Return -1 if invalid. 213 */ 214 int 215 a2port(const char *s) 216 { 217 long long port; 218 const char *errstr; 219 220 port = strtonum(s, 0, 65535, &errstr); 221 if (errstr != NULL) 222 return -1; 223 return (int)port; 224 } 225 226 int 227 a2tun(const char *s, int *remote) 228 { 229 const char *errstr = NULL; 230 char *sp, *ep; 231 int tun; 232 233 if (remote != NULL) { 234 *remote = SSH_TUNID_ANY; 235 sp = xstrdup(s); 236 if ((ep = strchr(sp, ':')) == NULL) { 237 xfree(sp); 238 return (a2tun(s, NULL)); 239 } 240 ep[0] = '\0'; ep++; 241 *remote = a2tun(ep, NULL); 242 tun = a2tun(sp, NULL); 243 xfree(sp); 244 return (*remote == SSH_TUNID_ERR ? *remote : tun); 245 } 246 247 if (strcasecmp(s, "any") == 0) 248 return (SSH_TUNID_ANY); 249 250 tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); 251 if (errstr != NULL) 252 return (SSH_TUNID_ERR); 253 254 return (tun); 255 } 256 257 #define SECONDS 1 258 #define MINUTES (SECONDS * 60) 259 #define HOURS (MINUTES * 60) 260 #define DAYS (HOURS * 24) 261 #define WEEKS (DAYS * 7) 262 263 /* 264 * Convert a time string into seconds; format is 265 * a sequence of: 266 * time[qualifier] 267 * 268 * Valid time qualifiers are: 269 * <none> seconds 270 * s|S seconds 271 * m|M minutes 272 * h|H hours 273 * d|D days 274 * w|W weeks 275 * 276 * Examples: 277 * 90m 90 minutes 278 * 1h30m 90 minutes 279 * 2d 2 days 280 * 1w 1 week 281 * 282 * Return -1 if time string is invalid. 283 */ 284 long 285 convtime(const char *s) 286 { 287 long total, secs; 288 const char *p; 289 char *endp; 290 291 errno = 0; 292 total = 0; 293 p = s; 294 295 if (p == NULL || *p == '\0') 296 return -1; 297 298 while (*p) { 299 secs = strtol(p, &endp, 10); 300 if (p == endp || 301 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 302 secs < 0) 303 return -1; 304 305 switch (*endp++) { 306 case '\0': 307 endp--; 308 break; 309 case 's': 310 case 'S': 311 break; 312 case 'm': 313 case 'M': 314 secs *= MINUTES; 315 break; 316 case 'h': 317 case 'H': 318 secs *= HOURS; 319 break; 320 case 'd': 321 case 'D': 322 secs *= DAYS; 323 break; 324 case 'w': 325 case 'W': 326 secs *= WEEKS; 327 break; 328 default: 329 return -1; 330 } 331 total += secs; 332 if (total < 0) 333 return -1; 334 p = endp; 335 } 336 337 return total; 338 } 339 340 /* 341 * Returns a standardized host+port identifier string. 342 * Caller must free returned string. 343 */ 344 char * 345 put_host_port(const char *host, u_short port) 346 { 347 char *hoststr; 348 349 if (port == 0 || port == SSH_DEFAULT_PORT) 350 return(xstrdup(host)); 351 if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0) 352 fatal("put_host_port: asprintf: %s", strerror(errno)); 353 debug3("put_host_port: %s", hoststr); 354 return hoststr; 355 } 356 357 /* 358 * Search for next delimiter between hostnames/addresses and ports. 359 * Argument may be modified (for termination). 360 * Returns *cp if parsing succeeds. 361 * *cp is set to the start of the next delimiter, if one was found. 362 * If this is the last field, *cp is set to NULL. 363 */ 364 char * 365 hpdelim(char **cp) 366 { 367 char *s, *old; 368 369 if (cp == NULL || *cp == NULL) 370 return NULL; 371 372 old = s = *cp; 373 if (*s == '[') { 374 if ((s = strchr(s, ']')) == NULL) 375 return NULL; 376 else 377 s++; 378 } else if ((s = strpbrk(s, ":/")) == NULL) 379 s = *cp + strlen(*cp); /* skip to end (see first case below) */ 380 381 switch (*s) { 382 case '\0': 383 *cp = NULL; /* no more fields*/ 384 break; 385 386 case ':': 387 case '/': 388 *s = '\0'; /* terminate */ 389 *cp = s + 1; 390 break; 391 392 default: 393 return NULL; 394 } 395 396 return old; 397 } 398 399 char * 400 cleanhostname(char *host) 401 { 402 if (*host == '[' && host[strlen(host) - 1] == ']') { 403 host[strlen(host) - 1] = '\0'; 404 return (host + 1); 405 } else 406 return host; 407 } 408 409 char * 410 colon(char *cp) 411 { 412 int flag = 0; 413 414 if (*cp == ':') /* Leading colon is part of file name. */ 415 return (0); 416 if (*cp == '[') 417 flag = 1; 418 419 for (; *cp; ++cp) { 420 if (*cp == '@' && *(cp+1) == '[') 421 flag = 1; 422 if (*cp == ']' && *(cp+1) == ':' && flag) 423 return (cp+1); 424 if (*cp == ':' && !flag) 425 return (cp); 426 if (*cp == '/') 427 return (0); 428 } 429 return (0); 430 } 431 432 /* function to assist building execv() arguments */ 433 void 434 addargs(arglist *args, char *fmt, ...) 435 { 436 va_list ap; 437 char *cp; 438 u_int nalloc; 439 int r; 440 441 va_start(ap, fmt); 442 r = vasprintf(&cp, fmt, ap); 443 va_end(ap); 444 if (r == -1) 445 fatal("addargs: argument too long"); 446 447 nalloc = args->nalloc; 448 if (args->list == NULL) { 449 nalloc = 32; 450 args->num = 0; 451 } else if (args->num+2 >= nalloc) 452 nalloc *= 2; 453 454 args->list = xrealloc(args->list, nalloc, sizeof(char *)); 455 args->nalloc = nalloc; 456 args->list[args->num++] = cp; 457 args->list[args->num] = NULL; 458 } 459 460 void 461 replacearg(arglist *args, u_int which, char *fmt, ...) 462 { 463 va_list ap; 464 char *cp; 465 int r; 466 467 va_start(ap, fmt); 468 r = vasprintf(&cp, fmt, ap); 469 va_end(ap); 470 if (r == -1) 471 fatal("replacearg: argument too long"); 472 473 if (which >= args->num) 474 fatal("replacearg: tried to replace invalid arg %d >= %d", 475 which, args->num); 476 xfree(args->list[which]); 477 args->list[which] = cp; 478 } 479 480 void 481 freeargs(arglist *args) 482 { 483 u_int i; 484 485 if (args->list != NULL) { 486 for (i = 0; i < args->num; i++) 487 xfree(args->list[i]); 488 xfree(args->list); 489 args->nalloc = args->num = 0; 490 args->list = NULL; 491 } 492 } 493 494 /* 495 * Expands tildes in the file name. Returns data allocated by xmalloc. 496 * Warning: this calls getpw*. 497 */ 498 char * 499 tilde_expand_filename(const char *filename, uid_t uid) 500 { 501 const char *path; 502 char user[128], ret[MAXPATHLEN]; 503 struct passwd *pw; 504 u_int len, slash; 505 506 if (*filename != '~') 507 return (xstrdup(filename)); 508 filename++; 509 510 path = strchr(filename, '/'); 511 if (path != NULL && path > filename) { /* ~user/path */ 512 slash = path - filename; 513 if (slash > sizeof(user) - 1) 514 fatal("tilde_expand_filename: ~username too long"); 515 memcpy(user, filename, slash); 516 user[slash] = '\0'; 517 if ((pw = getpwnam(user)) == NULL) 518 fatal("tilde_expand_filename: No such user %s", user); 519 } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */ 520 fatal("tilde_expand_filename: No such uid %ld", (long)uid); 521 522 if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret)) 523 fatal("tilde_expand_filename: Path too long"); 524 525 /* Make sure directory has a trailing '/' */ 526 len = strlen(pw->pw_dir); 527 if ((len == 0 || pw->pw_dir[len - 1] != '/') && 528 strlcat(ret, "/", sizeof(ret)) >= sizeof(ret)) 529 fatal("tilde_expand_filename: Path too long"); 530 531 /* Skip leading '/' from specified path */ 532 if (path != NULL) 533 filename = path + 1; 534 if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret)) 535 fatal("tilde_expand_filename: Path too long"); 536 537 return (xstrdup(ret)); 538 } 539 540 /* 541 * Expand a string with a set of %[char] escapes. A number of escapes may be 542 * specified as (char *escape_chars, char *replacement) pairs. The list must 543 * be terminated by a NULL escape_char. Returns replaced string in memory 544 * allocated by xmalloc. 545 */ 546 char * 547 percent_expand(const char *string, ...) 548 { 549 #define EXPAND_MAX_KEYS 16 550 struct { 551 const char *key; 552 const char *repl; 553 } keys[EXPAND_MAX_KEYS]; 554 u_int num_keys, i, j; 555 char buf[4096]; 556 va_list ap; 557 558 /* Gather keys */ 559 va_start(ap, string); 560 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 561 keys[num_keys].key = va_arg(ap, char *); 562 if (keys[num_keys].key == NULL) 563 break; 564 keys[num_keys].repl = va_arg(ap, char *); 565 if (keys[num_keys].repl == NULL) 566 fatal("percent_expand: NULL replacement"); 567 } 568 va_end(ap); 569 570 if (num_keys >= EXPAND_MAX_KEYS) 571 fatal("percent_expand: too many keys"); 572 573 /* Expand string */ 574 *buf = '\0'; 575 for (i = 0; *string != '\0'; string++) { 576 if (*string != '%') { 577 append: 578 buf[i++] = *string; 579 if (i >= sizeof(buf)) 580 fatal("percent_expand: string too long"); 581 buf[i] = '\0'; 582 continue; 583 } 584 string++; 585 if (*string == '%') 586 goto append; 587 for (j = 0; j < num_keys; j++) { 588 if (strchr(keys[j].key, *string) != NULL) { 589 i = strlcat(buf, keys[j].repl, sizeof(buf)); 590 if (i >= sizeof(buf)) 591 fatal("percent_expand: string too long"); 592 break; 593 } 594 } 595 if (j >= num_keys) 596 fatal("percent_expand: unknown key %%%c", *string); 597 } 598 return (xstrdup(buf)); 599 #undef EXPAND_MAX_KEYS 600 } 601 602 /* 603 * Read an entire line from a public key file into a static buffer, discarding 604 * lines that exceed the buffer size. Returns 0 on success, -1 on failure. 605 */ 606 int 607 read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, 608 u_long *lineno) 609 { 610 while (fgets(buf, bufsz, f) != NULL) { 611 if (buf[0] == '\0') 612 continue; 613 (*lineno)++; 614 if (buf[strlen(buf) - 1] == '\n' || feof(f)) { 615 return 0; 616 } else { 617 debug("%s: %s line %lu exceeds size limit", __func__, 618 filename, *lineno); 619 /* discard remainder of line */ 620 while (fgetc(f) != '\n' && !feof(f)) 621 ; /* nothing */ 622 } 623 } 624 return -1; 625 } 626 627 int 628 tun_open(int tun, int mode) 629 { 630 struct ifreq ifr; 631 char name[100]; 632 int fd = -1, sock; 633 634 /* Open the tunnel device */ 635 if (tun <= SSH_TUNID_MAX) { 636 snprintf(name, sizeof(name), "/dev/tun%d", tun); 637 fd = open(name, O_RDWR); 638 } else if (tun == SSH_TUNID_ANY) { 639 for (tun = 100; tun >= 0; tun--) { 640 snprintf(name, sizeof(name), "/dev/tun%d", tun); 641 if ((fd = open(name, O_RDWR)) >= 0) 642 break; 643 } 644 } else { 645 debug("%s: invalid tunnel %u", __func__, tun); 646 return (-1); 647 } 648 649 if (fd < 0) { 650 debug("%s: %s open failed: %s", __func__, name, strerror(errno)); 651 return (-1); 652 } 653 654 debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 655 656 /* Set the tunnel device operation mode */ 657 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun); 658 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 659 goto failed; 660 661 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 662 goto failed; 663 664 /* Set interface mode */ 665 ifr.ifr_flags &= ~IFF_UP; 666 if (mode == SSH_TUNMODE_ETHERNET) 667 ifr.ifr_flags |= IFF_LINK0; 668 else 669 ifr.ifr_flags &= ~IFF_LINK0; 670 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 671 goto failed; 672 673 /* Bring interface up */ 674 ifr.ifr_flags |= IFF_UP; 675 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 676 goto failed; 677 678 close(sock); 679 return (fd); 680 681 failed: 682 if (fd >= 0) 683 close(fd); 684 if (sock >= 0) 685 close(sock); 686 debug("%s: failed to set %s mode %d: %s", __func__, name, 687 mode, strerror(errno)); 688 return (-1); 689 } 690 691 void 692 sanitise_stdfd(void) 693 { 694 int nullfd, dupfd; 695 696 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 697 fprintf(stderr, "Couldn't open /dev/null: %s\n", 698 strerror(errno)); 699 exit(1); 700 } 701 while (++dupfd <= 2) { 702 /* Only clobber closed fds */ 703 if (fcntl(dupfd, F_GETFL, 0) >= 0) 704 continue; 705 if (dup2(nullfd, dupfd) == -1) { 706 fprintf(stderr, "dup2: %s\n", strerror(errno)); 707 exit(1); 708 } 709 } 710 if (nullfd > 2) 711 close(nullfd); 712 } 713 714 char * 715 tohex(const void *vp, size_t l) 716 { 717 const u_char *p = (const u_char *)vp; 718 char b[3], *r; 719 size_t i, hl; 720 721 if (l > 65536) 722 return xstrdup("tohex: length > 65536"); 723 724 hl = l * 2 + 1; 725 r = xcalloc(1, hl); 726 for (i = 0; i < l; i++) { 727 snprintf(b, sizeof(b), "%02x", p[i]); 728 strlcat(r, b, hl); 729 } 730 return (r); 731 } 732 733 u_int64_t 734 get_u64(const void *vp) 735 { 736 const u_char *p = (const u_char *)vp; 737 u_int64_t v; 738 739 v = (u_int64_t)p[0] << 56; 740 v |= (u_int64_t)p[1] << 48; 741 v |= (u_int64_t)p[2] << 40; 742 v |= (u_int64_t)p[3] << 32; 743 v |= (u_int64_t)p[4] << 24; 744 v |= (u_int64_t)p[5] << 16; 745 v |= (u_int64_t)p[6] << 8; 746 v |= (u_int64_t)p[7]; 747 748 return (v); 749 } 750 751 u_int32_t 752 get_u32(const void *vp) 753 { 754 const u_char *p = (const u_char *)vp; 755 u_int32_t v; 756 757 v = (u_int32_t)p[0] << 24; 758 v |= (u_int32_t)p[1] << 16; 759 v |= (u_int32_t)p[2] << 8; 760 v |= (u_int32_t)p[3]; 761 762 return (v); 763 } 764 765 u_int16_t 766 get_u16(const void *vp) 767 { 768 const u_char *p = (const u_char *)vp; 769 u_int16_t v; 770 771 v = (u_int16_t)p[0] << 8; 772 v |= (u_int16_t)p[1]; 773 774 return (v); 775 } 776 777 void 778 put_u64(void *vp, u_int64_t v) 779 { 780 u_char *p = (u_char *)vp; 781 782 p[0] = (u_char)(v >> 56) & 0xff; 783 p[1] = (u_char)(v >> 48) & 0xff; 784 p[2] = (u_char)(v >> 40) & 0xff; 785 p[3] = (u_char)(v >> 32) & 0xff; 786 p[4] = (u_char)(v >> 24) & 0xff; 787 p[5] = (u_char)(v >> 16) & 0xff; 788 p[6] = (u_char)(v >> 8) & 0xff; 789 p[7] = (u_char)v & 0xff; 790 } 791 792 void 793 put_u32(void *vp, u_int32_t v) 794 { 795 u_char *p = (u_char *)vp; 796 797 p[0] = (u_char)(v >> 24) & 0xff; 798 p[1] = (u_char)(v >> 16) & 0xff; 799 p[2] = (u_char)(v >> 8) & 0xff; 800 p[3] = (u_char)v & 0xff; 801 } 802 803 804 void 805 put_u16(void *vp, u_int16_t v) 806 { 807 u_char *p = (u_char *)vp; 808 809 p[0] = (u_char)(v >> 8) & 0xff; 810 p[1] = (u_char)v & 0xff; 811 } 812 813 void 814 ms_subtract_diff(struct timeval *start, int *ms) 815 { 816 struct timeval diff, finish; 817 818 gettimeofday(&finish, NULL); 819 timersub(&finish, start, &diff); 820 *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); 821 } 822 823 void 824 ms_to_timeval(struct timeval *tv, int ms) 825 { 826 if (ms < 0) 827 ms = 0; 828 tv->tv_sec = ms / 1000; 829 tv->tv_usec = (ms % 1000) * 1000; 830 } 831 832