1 #include "compat.h" 2 3 #ifdef HAVE_SYS_SOCKET_H 4 #include <sys/socket.h> 5 #endif 6 #ifdef HAVE_SYS_TYPES_H 7 #include <sys/types.h> 8 #endif 9 #ifdef HAVE_SYS_STAT_H 10 #include <sys/stat.h> 11 #endif 12 #ifdef HAVE_STRING_H 13 #include <string.h> 14 #endif 15 #ifdef HAVE_STDLIB_H 16 #include <stdlib.h> 17 #endif 18 #ifdef HAVE_UNISTD_H 19 #include <unistd.h> 20 #endif 21 #ifdef HAVE_FCNTL_H 22 #include <fcntl.h> 23 #endif 24 #ifdef HAVE_STDIO_H 25 #include <stdio.h> 26 #endif 27 #ifdef HAVE_GETPEERNAME 28 #ifdef HAVE_SYS_SOCKET_H 29 #include <sys/socket.h> 30 #endif 31 #ifdef HAVE_NETINET_IN_H 32 #include <netinet/in.h> 33 #endif 34 #endif 35 36 #include "net.h" 37 #include "opennet.h" 38 39 #ifndef MSG_WAITALL 40 #define MSG_WAITALL 0 41 #endif 42 43 /* 44 * Legacy stub, please ignore. 45 */ 46 int opennet_init(void) { 47 return(0); 48 } 49 50 /* 51 Replace 52 @@OSNM@@ OS Name (linux, freebsd, sunos, etc) 53 @@OSVR@@ OS version (2.2.x, 4.2, 5.8, etc) 54 @@OSVS@@ OS version (short) (2.2, 4.2, 5.8, etc) 55 @@ARCH@@ Arch (i386, sparc64, sun4u, sun4m, etc) 56 */ 57 char *parse_url_subst(const char *src) { 58 char *retval = NULL; 59 60 if (!strstr(src, "@@")) { 61 return(strdup(src)); 62 } 63 64 return(retval); 65 } 66 67 /* 68 * Parse a URL into its components 69 */ 70 static int parse_url(char *url, char **scheme, char **user, char **pass, char **host, int *port, char **path) { 71 char *tmptr, *schemeptr, *pathptr, *userptr, *passptr, *hostptr, *portptr; 72 73 if (!url) { 74 return(-1); 75 } 76 77 tmptr = strstr(url, "://"); 78 if (!tmptr) { 79 return(-1); 80 } 81 82 if (strlen(tmptr) <= 3) { 83 return(-1); 84 } 85 86 *tmptr = '\0'; 87 schemeptr = url; 88 89 tmptr += 3; 90 91 pathptr = strchr(tmptr, '/'); 92 93 if (pathptr) { 94 *pathptr = '\0'; 95 pathptr++; 96 } else { 97 pathptr = ""; 98 } 99 100 hostptr = strchr(tmptr, '@'); 101 if (hostptr) { 102 *hostptr = '\0'; 103 hostptr++; 104 userptr = tmptr; 105 passptr = strchr(userptr, ':'); 106 if (passptr) { 107 *passptr = '\0'; 108 passptr++; 109 } 110 } else { 111 userptr = NULL; 112 passptr = NULL; 113 hostptr = tmptr; 114 } 115 116 portptr = strchr(hostptr, ':'); 117 if (portptr) { 118 *portptr = '\0'; 119 portptr++; 120 *port = strtoul(portptr, NULL, 10); 121 } else { 122 if (strcasecmp(schemeptr, "http") == 0) { 123 *port = 80; 124 } else if (strcasecmp(schemeptr, "ftp") == 0) { 125 *port = 21; 126 } else { 127 *port = 0; 128 } 129 } 130 131 *scheme = schemeptr; 132 *user = userptr; 133 *pass = passptr; 134 *host = hostptr; 135 *path = pathptr; 136 137 return(0); 138 } 139 140 static ssize_t read_net_internal(int fd, void *buf, size_t count, int socketStatus) { 141 ssize_t retval = 0; 142 ssize_t read_ret; 143 int socket = 0; 144 #ifdef HAVE_GETPEERNAME 145 int gpn_ret; 146 struct sockaddr_in tmp; 147 int tmplen; 148 149 if (socketStatus < 0) { 150 tmplen = sizeof(tmp); 151 152 gpn_ret = getpeername(fd, (struct sockaddr *) &tmp, &tmplen); 153 154 if (gpn_ret >= 0) { 155 socket = 1; 156 } else { 157 socket = 0; 158 } 159 } else { 160 socket = socketStatus; 161 } 162 #else 163 socket = socketStatus; 164 #endif 165 166 while (count) { 167 if (socket) { 168 read_ret = recv(fd, buf, count, 0); 169 } else { 170 read_ret = read(fd, buf, count); 171 } 172 173 if (read_ret == 0) { 174 break; 175 } 176 177 if (read_ret < 0) { 178 retval = read_ret; 179 break; 180 } 181 182 count -= read_ret; 183 buf += read_ret; 184 retval += read_ret; 185 } 186 187 return(retval); 188 } 189 190 static int open_net_http(char *user, char *pass, char *host, int port, char *path, int flags, off_t offset, off_t *length) { 191 unsigned long long content_length = 0; 192 ssize_t read_ret, sink_bytes = 0; 193 ssize_t send_ret, recv_ret; 194 char httpcmd[4096], charbuf, httpreply[1024], *http_response; 195 char garbage[4096]; 196 int bytes_to_read; 197 int fd; 198 int snprintf_ret; 199 int http_response_code = 0; 200 int newlinecount = 0, linenum = 0, i = 0; 201 202 fd = net_connect_tcp(host, port); 203 204 if (fd < 0) { 205 return(-1); 206 } 207 208 if (offset == 0) { 209 snprintf_ret = snprintf(httpcmd, sizeof(httpcmd), "GET /%s HTTP/1.0\015\012Host: %s\015\012\015\012", path, host); 210 } else { 211 snprintf_ret = snprintf(httpcmd, sizeof(httpcmd), "GET /%s HTTP/1.0\015\012Host: %s\015\012Range: bytes=%llu-\015\012\015\012", path, host, (unsigned long long) offset); 212 } 213 214 if (snprintf_ret >= sizeof(httpcmd)) { 215 return(-1); 216 } 217 218 send_ret = send(fd, httpcmd, snprintf_ret, 0); 219 if (send_ret != snprintf_ret) { 220 net_close(fd); 221 return(-1); 222 } 223 224 while (1) { 225 recv_ret = recv(fd, &charbuf, 1, MSG_WAITALL); 226 227 if (charbuf == '\015' || charbuf == '\012') { 228 if (i > 0) { 229 httpreply[i] = '\0'; 230 if (linenum == 0) { 231 232 if (strlen(httpreply) < 9) { 233 net_close(fd); 234 return(-1); 235 } 236 237 http_response = httpreply + 9; 238 http_response_code = strtoul(http_response, NULL, 10); 239 switch (http_response_code) { 240 case 206: 241 if (offset == 0) { 242 CHECKPOINT; 243 net_close(fd); 244 return(-1); 245 } 246 break; 247 case 200: 248 if (offset != 0) { 249 sink_bytes = offset; 250 } 251 break; 252 case 301: 253 case 302: 254 break; 255 case 404: 256 CHECKPOINT; 257 default: 258 net_close(fd); 259 return(-1); 260 } 261 } else { 262 if (strncasecmp(httpreply, "Content-Length:", 15) == 0) { 263 content_length = strtoull(httpreply + 16, NULL, 10); 264 if (offset != 0 && http_response_code == 206) { 265 content_length += (unsigned long long) offset; 266 } 267 if (length) { 268 *length = content_length; 269 } 270 } 271 if (http_response_code == 301 || http_response_code == 302) { 272 if (strncasecmp(httpreply, "Location:", 9) == 0) { 273 net_close(fd); 274 return(open_net(httpreply + 10, flags, 0)); 275 } 276 } 277 } 278 } 279 newlinecount++; 280 linenum++; 281 i = 0; 282 } else { 283 newlinecount = 0; 284 httpreply[i++] = charbuf; 285 } 286 287 if (newlinecount == 4) { 288 break; 289 } 290 291 if (recv_ret <= 0) { 292 net_close(fd); 293 return(-1); 294 } 295 } 296 297 if (sink_bytes) { 298 while (sink_bytes) { 299 bytes_to_read = sink_bytes; 300 if (bytes_to_read > sizeof(garbage)) { 301 bytes_to_read = sizeof(garbage); 302 } 303 304 read_ret = read_net_internal(fd, garbage, bytes_to_read, 1); 305 if (read_ret <= 0) { 306 SPOTVAR_I(read_ret); 307 net_close(fd); 308 return(-1); 309 } 310 311 sink_bytes -= read_ret; 312 } 313 } 314 315 return(fd); 316 } 317 318 static int open_net_ftp(char *user, char *pass, char *host, int port, char *path, int flags, off_t offset, off_t *length) { 319 return(-1); 320 } 321 322 static int open_net_internal(const char *pathname, int flags, mode_t mode, int *socket, off_t offset, off_t *length) { 323 char *pathname_dup; 324 char *scheme, *user, *pass, *host, *path; 325 off_t lseek_ret; 326 int port = 0; 327 int parse_ret; 328 int retval = -1; 329 330 if (socket) { 331 *socket = 0; 332 } 333 334 if (!pathname) { 335 retval = open(pathname, flags, mode); 336 if (offset && retval >= 0) { 337 lseek_ret = lseek(retval, offset, SEEK_SET); 338 if (lseek_ret != offset) { 339 close(retval); 340 return(-1); 341 } 342 } 343 return(retval); 344 } 345 346 pathname_dup = strdup(pathname); 347 348 if (!pathname_dup) { 349 retval = open(pathname, flags, mode); 350 if (offset && retval >= 0) { 351 lseek_ret = lseek(retval, offset, SEEK_SET); 352 if (lseek_ret != offset) { 353 close(retval); 354 return(-1); 355 } 356 } 357 return(retval); 358 } 359 360 parse_ret = parse_url(pathname_dup, &scheme, &user, &pass, &host, &port, &path); 361 362 if (parse_ret < 0 || port == 0 || !host || !scheme) { 363 free(pathname_dup); 364 retval = open(pathname, flags, mode); 365 if (offset && retval >= 0) { 366 lseek_ret = lseek(retval, offset, SEEK_SET); 367 if (lseek_ret != offset) { 368 close(retval); 369 return(-1); 370 } 371 } 372 return(retval); 373 374 } 375 376 if (length) { 377 *length = -1; 378 } 379 380 if (strcasecmp(scheme, "http") == 0) { 381 retval = open_net_http(user, pass, host, port, path, flags, offset, length); 382 } 383 384 if (strcasecmp(scheme, "ftp") == 0) { 385 retval = open_net_ftp(user, pass, host, port, path, flags, offset, length); 386 } 387 388 free(pathname_dup); 389 390 if (retval < 0) { 391 retval = open(pathname, flags, mode); 392 if (offset && retval >= 0) { 393 lseek_ret = lseek(retval, offset, SEEK_SET); 394 if (lseek_ret != offset) { 395 close(retval); 396 return(-1); 397 } 398 } 399 } else { 400 if (socket) { 401 *socket = 1; 402 } 403 } 404 405 return(retval); 406 } 407 408 NETFILE *fopen_net(const char *pathname, const char *mode) { 409 NETFILE *ret; 410 int is_sock; 411 off_t length; 412 413 ret = malloc(sizeof(*ret)); 414 415 if (!ret) { 416 return(NULL); 417 } 418 419 ret->fd = open_net_internal(pathname, O_RDONLY, 0666, &is_sock, 0, &length); 420 421 if (ret->fd < 0) { 422 free(ret); 423 return(NULL); 424 } 425 426 ret->free_buf = 1; 427 ret->bufsize_s = ret->bufsize = 32768; 428 ret->buf_s = ret->buf = malloc(ret->bufsize); 429 ret->bufused = 0; 430 ret->eof = 0; 431 ret->pos = 0; 432 ret->socket = is_sock; 433 ret->length = length; 434 ret->url = strdup(pathname); 435 436 return(ret); 437 } 438 439 int feof_net(NETFILE *stream) { 440 if (!stream) { 441 return(-1); 442 } 443 444 return(stream->eof); 445 } 446 447 size_t fread_net(void *ptr, size_t size, size_t nmemb, NETFILE *stream) { 448 ssize_t recv_ret; 449 size_t retval; 450 int bytes_to_copy; 451 452 if (!stream) { 453 return(0); 454 } 455 456 if (stream->fd >= 0) { 457 while (stream->bufused < (size * nmemb)) { 458 if (stream->socket) { 459 recv_ret = recv(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused, MSG_WAITALL); 460 } else { 461 recv_ret = read(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused); 462 } 463 464 if (recv_ret <= 0) { 465 net_close(stream->fd); 466 stream->fd = -1; 467 break; 468 } 469 470 stream->bufused += recv_ret; 471 472 if (stream->bufused >= (size * nmemb)) { 473 break; 474 } 475 476 /* 477 * If there is more data to be read, but the buffer is full 478 * try to make room, or quit trying to read data 479 */ 480 if (stream->bufused == stream->bufsize) { 481 if (stream->bufsize_s != stream->bufsize) { 482 CHECKPOINT; 483 memmove(stream->buf_s, stream->buf, stream->bufused); 484 stream->buf = stream->buf_s; 485 stream->bufsize = stream->bufsize_s; 486 } else { 487 break; 488 } 489 } 490 } 491 } 492 493 if (stream->bufused == 0) { 494 if (stream->fd < 0) { 495 stream->eof = 1; 496 } 497 return(0); 498 } 499 500 bytes_to_copy = (size * nmemb); 501 502 if (stream->bufused < bytes_to_copy) { 503 bytes_to_copy = stream->bufused; 504 505 /* Adjust bytes_to_copy to be a multiple of size */ 506 bytes_to_copy /= size; 507 bytes_to_copy *= size; 508 } 509 510 memcpy(ptr, stream->buf, bytes_to_copy); 511 stream->buf += bytes_to_copy; 512 stream->bufused -= bytes_to_copy; 513 stream->bufsize -= bytes_to_copy; 514 515 if (stream->bufused == 0) { 516 stream->buf = stream->buf_s; 517 stream->bufsize = stream->bufsize_s; 518 } 519 520 retval = bytes_to_copy / size; 521 stream->pos += retval; 522 523 return(retval); 524 } 525 526 char *fgets_net(char *s, int size, NETFILE *stream) { 527 ssize_t recv_ret; 528 int bytes_to_copy; 529 char *stopptr; 530 531 if (!stream) { 532 return(NULL); 533 } 534 535 if (stream->fd >= 0) { 536 while (stream->bufused < size) { 537 if (stream->socket) { 538 recv_ret = recv(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused, MSG_WAITALL); 539 } else { 540 recv_ret = read(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused); 541 } 542 543 if (recv_ret <= 0) { 544 net_close(stream->fd); 545 stream->fd = -1; 546 break; 547 } 548 549 stream->bufused += recv_ret; 550 551 if (memchr(stream->buf, '\n', stream->bufused)) { 552 break; 553 } 554 } 555 } 556 557 if (stream->bufused == 0) { 558 if (stream->fd < 0) { 559 stream->eof = 1; 560 } 561 return(NULL); 562 } 563 564 stopptr = memchr(stream->buf, '\n', stream->bufused); 565 566 if (!stopptr) { 567 stopptr = stream->buf + stream->bufused; 568 } else { 569 stopptr++; 570 } 571 572 bytes_to_copy = stopptr - stream->buf; 573 574 if (size < bytes_to_copy) { 575 bytes_to_copy = size; 576 } 577 578 memcpy(s, stream->buf, bytes_to_copy); 579 580 if (bytes_to_copy < size) { 581 s[bytes_to_copy] = '\0'; 582 } else { 583 s[size - 1] = '\0'; 584 } 585 586 stream->buf += bytes_to_copy; 587 stream->bufused -= bytes_to_copy; 588 stream->bufsize -= bytes_to_copy; 589 stream->pos += bytes_to_copy; 590 591 if (stream->bufused == 0) { 592 stream->buf = stream->buf_s; 593 stream->bufsize = stream->bufsize_s; 594 } 595 596 return(s); 597 } 598 599 int fclose_net(NETFILE *stream) { 600 int fd; 601 int retval; 602 int is_sock; 603 604 if (!stream) { 605 return(-1); 606 } 607 608 fd = stream->fd; 609 is_sock = stream->socket; 610 611 if (stream->buf_s && stream->free_buf) { 612 free(stream->buf_s); 613 } 614 if (stream->url) { 615 free(stream->url); 616 } 617 618 free(stream); 619 620 if (is_sock) { 621 retval = net_close(fd); 622 } else { 623 retval = close(fd); 624 } 625 626 return(retval); 627 } 628 629 int setvbuf_net(NETFILE *stream, char *buf, int mode, size_t size) { 630 if (!stream) { 631 return(-1); 632 } 633 634 if (size < stream->bufused) { 635 return(-1); 636 } 637 638 if (stream->buf_s && stream->free_buf) { 639 free(stream->buf_s); 640 } 641 642 memcpy(buf, stream->buf, stream->bufused); 643 644 stream->buf = buf; 645 stream->buf_s = buf; 646 stream->bufsize = size; 647 stream->bufsize_s = size; 648 stream->free_buf = 0; 649 650 return(0); 651 } 652 653 int open_net(const char *pathname, int flags, mode_t mode) { 654 int tmp; 655 656 return(open_net_internal(pathname, flags, mode, &tmp, 0, NULL)); 657 } 658 659 ssize_t read_net(int fd, void *buf, size_t count) { 660 return(read_net_internal(fd, buf, count, -1)); 661 } 662 663 off_t lseek_net(int filedes, off_t offset, int whence) { 664 return(-1); 665 } 666 667 int fseeko_net(NETFILE *stream, off_t offset, int whence) { 668 static char garbage[4096]; 669 size_t fread_ret, bytes_to_read; 670 off_t newoffset, lseek_ret; 671 off_t newlength; 672 int newfd; 673 674 if (!stream) { 675 return(-1); 676 } 677 if (stream->fd < 0) { 678 return(-1); 679 } 680 681 switch (whence) { 682 case SEEK_CUR: 683 newoffset = stream->pos + offset; 684 break; 685 case SEEK_END: 686 newoffset = stream->length + offset; 687 break; 688 case SEEK_SET: 689 newoffset = offset; 690 break; 691 default: 692 CHECKPOINT; 693 return(-1); 694 break; 695 } 696 697 if (newoffset < 0) { 698 return(-1); 699 } 700 701 lseek_ret = lseek(stream->fd, newoffset, SEEK_SET); 702 if (lseek_ret != ((off_t) -1)) { 703 stream->pos = lseek_ret; 704 stream->buf = stream->buf_s; 705 stream->bufused = 0; 706 stream->bufsize = stream->bufsize_s; 707 708 return(0); 709 } 710 711 /* 712 * Read up to 4K of data to avoid opening a new connection 713 */ 714 if (newoffset >= stream->pos && (newoffset - stream->pos < sizeof(garbage))) { 715 bytes_to_read = newoffset - stream->pos; 716 fread_ret = fread_net(garbage, sizeof(garbage[0]), bytes_to_read, stream); 717 718 if (fread_ret == bytes_to_read) { 719 return(0); 720 } 721 } 722 723 newfd = open_net_internal(stream->url, O_RDONLY, 0666, NULL, newoffset, &newlength); 724 725 if (newfd < 0) { 726 return(-1); 727 } 728 729 net_close(stream->fd); 730 stream->fd = newfd; 731 stream->pos = newoffset; 732 stream->buf = stream->buf_s; 733 stream->bufused = 0; 734 stream->bufsize = stream->bufsize_s; 735 stream->eof = 0; 736 737 return(0); 738 } 739 740 int fseek_net(NETFILE *stream, long offset, int whence) { 741 return(fseek_net(stream, offset, whence)); 742 } 743 744 off_t ftello_net(NETFILE *stream) { 745 if (!stream) { 746 return(-1); 747 } 748 if (stream->fd < 0) { 749 return(-1); 750 } 751 752 return(stream->pos); 753 } 754 755 long ftell_net(NETFILE *stream) { 756 return(ftello_net(stream)); 757 } 758 759 off_t flength_net(NETFILE *stream) { 760 if (!stream) { 761 return(-1); 762 } 763 if (stream->fd < 0) { 764 return(-1); 765 } 766 767 return(stream->length); 768 } |