libStatGen Software
1
|
00001 /* The MIT License 00002 00003 Copyright (c) 2008 by Genome Research Ltd (GRL). 00004 2010 by Attractive Chaos <attractor@live.co.uk> 00005 00006 Permission is hereby granted, free of charge, to any person obtaining 00007 a copy of this software and associated documentation files (the 00008 "Software"), to deal in the Software without restriction, including 00009 without limitation the rights to use, copy, modify, merge, publish, 00010 distribute, sublicense, and/or sell copies of the Software, and to 00011 permit persons to whom the Software is furnished to do so, subject to 00012 the following conditions: 00013 00014 The above copyright notice and this permission notice shall be 00015 included in all copies or substantial portions of the Software. 00016 00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00018 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00019 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00020 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00021 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00022 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00023 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00024 SOFTWARE. 00025 */ 00026 00027 /* Probably I will not do socket programming in the next few years and 00028 therefore I decide to heavily annotate this file, for Linux and 00029 Windows as well. -ac */ 00030 00031 /* 00032 * Updated 10/22/2013 by Mary Kate Wing 00033 * Upgraded to latest version from htslib: develop branch 00034 * 1) Fix compile warnings 00035 * 2) Add flag to silently fail socket logic 00036 */ 00037 00038 #include <time.h> 00039 #include <stdio.h> 00040 #include <ctype.h> 00041 #include <stdlib.h> 00042 #include <string.h> 00043 #include <errno.h> 00044 #include <sys/types.h> 00045 00046 #ifndef _WIN32 00047 #include <unistd.h> 00048 #include <netdb.h> 00049 #include <arpa/inet.h> 00050 #include <sys/socket.h> 00051 #else 00052 #include <BaseTsd.h> 00053 #endif 00054 00055 #include "knetfile.h" 00056 00057 00058 int knetsilent = 0; 00059 00060 00061 void knet_silent(int silent) 00062 { 00063 knetsilent = silent; 00064 } 00065 00066 00067 /* In winsock.h, the type of a socket is SOCKET, which is: "typedef 00068 * u_int SOCKET". An invalid SOCKET is: "(SOCKET)(~0)", or signed 00069 * integer -1. In knetfile.c, I use "int" for socket type 00070 * throughout. This should be improved to avoid confusion. 00071 * 00072 * In Linux/Mac, recv() and read() do almost the same thing. You can see 00073 * in the header file that netread() is simply an alias of read(). In 00074 * Windows, however, they are different and using recv() is mandatory. 00075 */ 00076 00077 /* This function tests if the file handler is ready for reading (or 00078 * writing if is_read==0). */ 00079 static int socket_wait(int fd, int is_read) 00080 { 00081 fd_set fds, *fdr = 0, *fdw = 0; 00082 struct timeval tv; 00083 int ret; 00084 tv.tv_sec = 5; tv.tv_usec = 0; // 5 seconds time out 00085 FD_ZERO(&fds); 00086 FD_SET(fd, &fds); 00087 if (is_read) fdr = &fds; 00088 else fdw = &fds; 00089 ret = select(fd+1, fdr, fdw, 0, &tv); 00090 #ifndef _WIN32 00091 if (ret == -1) perror("select"); 00092 #else 00093 if (ret == 0) 00094 { 00095 if(!knetsilent) 00096 { 00097 fprintf(stderr, "select time-out\n"); 00098 } 00099 } 00100 else if (ret == SOCKET_ERROR) 00101 { 00102 if(!knetsilent) 00103 { 00104 fprintf(stderr, "select: %d\n", WSAGetLastError()); 00105 } 00106 } 00107 #endif 00108 return ret; 00109 } 00110 00111 #ifndef _WIN32 00112 /* This function does not work with Windows due to the lack of 00113 * getaddrinfo() in winsock. It is addapted from an example in "Beej's 00114 * Guide to Network Programming" (http://beej.us/guide/bgnet/). */ 00115 static int socket_connect(const char *host, const char *port) 00116 { 00117 #define __err_connect(func) do { if(!knetsilent){perror(func);} freeaddrinfo(res); return -1; } while (0) 00118 00119 int on = 1, fd; 00120 struct linger lng = { 0, 0 }; 00121 struct addrinfo hints, *res = 0; 00122 memset(&hints, 0, sizeof(struct addrinfo)); 00123 hints.ai_family = AF_UNSPEC; 00124 hints.ai_socktype = SOCK_STREAM; 00125 /* In Unix/Mac, getaddrinfo() is the most convenient way to get 00126 * server information. */ 00127 if (getaddrinfo(host, port, &hints, &res) != 0) __err_connect("getaddrinfo"); 00128 if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) __err_connect("socket"); 00129 /* The following two setsockopt() are used by ftplib 00130 * (http://nbpfaus.net/~pfau/ftplib/). I am not sure if they 00131 * necessary. */ 00132 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) __err_connect("setsockopt"); 00133 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1) __err_connect("setsockopt"); 00134 if (connect(fd, res->ai_addr, res->ai_addrlen) != 0) __err_connect("connect"); 00135 freeaddrinfo(res); 00136 return fd; 00137 } 00138 #else 00139 /* MinGW's printf has problem with "%lld" */ 00140 char *int64tostr(char *buf, int64_t x) 00141 { 00142 int cnt; 00143 int i = 0; 00144 do { 00145 buf[i++] = '0' + x % 10; 00146 x /= 10; 00147 } while (x); 00148 buf[i] = 0; 00149 for (cnt = i, i = 0; i < cnt/2; ++i) { 00150 int c = buf[i]; buf[i] = buf[cnt-i-1]; buf[cnt-i-1] = c; 00151 } 00152 return buf; 00153 } 00154 00155 int64_t strtoint64(const char *buf) 00156 { 00157 int64_t x; 00158 for (x = 0; *buf != '\0'; ++buf) 00159 x = x * 10 + ((int64_t) *buf - 48); 00160 return x; 00161 } 00162 /* In windows, the first thing is to establish the TCP connection. */ 00163 int knet_win32_init() 00164 { 00165 WSADATA wsaData; 00166 return WSAStartup(MAKEWORD(2, 2), &wsaData); 00167 } 00168 void knet_win32_destroy() 00169 { 00170 WSACleanup(); 00171 } 00172 /* A slightly modfied version of the following function also works on 00173 * Mac (and presummably Linux). However, this function is not stable on 00174 * my Mac. It sometimes works fine but sometimes does not. Therefore for 00175 * non-Windows OS, I do not use this one. */ 00176 static SOCKET socket_connect(const char *host, const char *port) 00177 { 00178 #define __err_connect(func) \ 00179 do { \ 00180 if(!knetsilent) {fprintf(stderr, "%s: %d\n", func, WSAGetLastError());} \ 00181 return -1; \ 00182 } while (0) 00183 00184 int on = 1; 00185 SOCKET fd; 00186 struct linger lng = { 0, 0 }; 00187 struct sockaddr_in server; 00188 struct hostent *hp = 0; 00189 // open socket 00190 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) __err_connect("socket"); 00191 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1) __err_connect("setsockopt"); 00192 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&lng, sizeof(lng)) == -1) __err_connect("setsockopt"); 00193 // get host info 00194 if (isalpha(host[0])) hp = gethostbyname(host); 00195 else { 00196 struct in_addr addr; 00197 addr.s_addr = inet_addr(host); 00198 hp = gethostbyaddr((char*)&addr, 4, AF_INET); 00199 } 00200 if (hp == 0) __err_connect("gethost"); 00201 // connect 00202 server.sin_addr.s_addr = *((unsigned long*)hp->h_addr); 00203 server.sin_family= AF_INET; 00204 server.sin_port = htons(atoi(port)); 00205 if (connect(fd, (struct sockaddr*)&server, sizeof(server)) != 0) __err_connect("connect"); 00206 // freehostent(hp); // strangely in MSDN, hp is NOT freed (memory leak?!) 00207 return fd; 00208 } 00209 #endif 00210 00211 static off_t my_netread(int fd, void *buf, off_t len) 00212 { 00213 off_t rest = len, curr, l = 0; 00214 /* recv() and read() may not read the required length of data with 00215 * one call. They have to be called repeatedly. */ 00216 while (rest) { 00217 if (socket_wait(fd, 1) <= 0) break; // socket is not ready for reading 00218 curr = netread(fd, (void*)((char*)buf + l), rest); 00219 /* According to the glibc manual, section 13.2, a zero returned 00220 * value indicates end-of-file (EOF), which should mean that 00221 * read() will not return zero if EOF has not been met but data 00222 * are not immediately available. */ 00223 if (curr == 0) break; 00224 l += curr; rest -= curr; 00225 } 00226 return l; 00227 } 00228 00229 /************************* 00230 * FTP specific routines * 00231 *************************/ 00232 00233 static int kftp_get_response(knetFile *ftp) 00234 { 00235 #ifndef _WIN32 00236 unsigned char c; 00237 #else 00238 char c; 00239 #endif 00240 int n = 0; 00241 char *p; 00242 if (socket_wait(ftp->ctrl_fd, 1) <= 0) return 0; 00243 while (netread(ftp->ctrl_fd, &c, 1)) { // FIXME: this is *VERY BAD* for unbuffered I/O 00244 //fputc(c, stderr); 00245 if (n >= ftp->max_response) { 00246 ftp->max_response = ftp->max_response? ftp->max_response<<1 : 256; 00247 ftp->response = (char*)realloc(ftp->response, ftp->max_response); 00248 } 00249 ftp->response[n++] = c; 00250 if (c == '\n') { 00251 if (n >= 4 && isdigit(ftp->response[0]) && isdigit(ftp->response[1]) && isdigit(ftp->response[2]) 00252 && ftp->response[3] != '-') break; 00253 n = 0; 00254 continue; 00255 } 00256 } 00257 if (n < 2) return -1; 00258 ftp->response[n-2] = 0; 00259 return strtol(ftp->response, &p, 0); 00260 } 00261 00262 static int kftp_send_cmd(knetFile *ftp, const char *cmd, int is_get) 00263 { 00264 if (socket_wait(ftp->ctrl_fd, 0) <= 0) return -1; // socket is not ready for writing 00265 if(netwrite(ftp->ctrl_fd, cmd, strlen(cmd)) != strlen(cmd)) 00266 { 00267 00268 } 00269 return is_get? kftp_get_response(ftp) : 0; 00270 } 00271 00272 static int kftp_pasv_prep(knetFile *ftp) 00273 { 00274 char *p; 00275 int v[6]; 00276 kftp_send_cmd(ftp, "PASV\r\n", 1); 00277 for (p = ftp->response; *p && *p != '('; ++p); 00278 if (*p != '(') return -1; 00279 ++p; 00280 sscanf(p, "%d,%d,%d,%d,%d,%d", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5]); 00281 memcpy(ftp->pasv_ip, v, 4 * sizeof(int)); 00282 ftp->pasv_port = (v[4]<<8&0xff00) + v[5]; 00283 return 0; 00284 } 00285 00286 00287 static int kftp_pasv_connect(knetFile *ftp) 00288 { 00289 char host[80], port[10]; 00290 if (ftp->pasv_port == 0) { 00291 if(!knetsilent) 00292 { 00293 fprintf(stderr, "[kftp_pasv_connect] kftp_pasv_prep() is not called before hand.\n"); 00294 } 00295 return -1; 00296 } 00297 sprintf(host, "%d.%d.%d.%d", ftp->pasv_ip[0], ftp->pasv_ip[1], ftp->pasv_ip[2], ftp->pasv_ip[3]); 00298 sprintf(port, "%d", ftp->pasv_port); 00299 ftp->fd = socket_connect(host, port); 00300 if (ftp->fd == -1) return -1; 00301 return 0; 00302 } 00303 00304 int kftp_connect(knetFile *ftp) 00305 { 00306 ftp->ctrl_fd = socket_connect(ftp->host, ftp->port); 00307 if (ftp->ctrl_fd == -1) return -1; 00308 kftp_get_response(ftp); 00309 kftp_send_cmd(ftp, "USER anonymous\r\n", 1); 00310 kftp_send_cmd(ftp, "PASS kftp@\r\n", 1); 00311 kftp_send_cmd(ftp, "TYPE I\r\n", 1); 00312 return 0; 00313 } 00314 00315 int kftp_reconnect(knetFile *ftp) 00316 { 00317 if (ftp->ctrl_fd != -1) { 00318 netclose(ftp->ctrl_fd); 00319 ftp->ctrl_fd = -1; 00320 } 00321 netclose(ftp->fd); 00322 ftp->fd = -1; 00323 return kftp_connect(ftp); 00324 } 00325 00326 // initialize ->type, ->host, ->retr and ->size 00327 knetFile *kftp_parse_url(const char *fn, const char *mode) 00328 { 00329 knetFile *fp; 00330 char *p; 00331 int l; 00332 if (strstr(fn, "ftp://") != fn) return 0; 00333 for (p = (char*)fn + 6; *p && *p != '/'; ++p); 00334 if (*p != '/') return 0; 00335 l = p - fn - 6; 00336 fp = (knetFile*)calloc(1, sizeof(knetFile)); 00337 fp->type = KNF_TYPE_FTP; 00338 fp->fd = -1; 00339 /* the Linux/Mac version of socket_connect() also recognizes a port 00340 * like "ftp", but the Windows version does not. */ 00341 fp->port = strdup("21"); 00342 fp->host = (char*)calloc(l + 1, 1); 00343 if (strchr(mode, 'c')) fp->no_reconnect = 1; 00344 strncpy(fp->host, fn + 6, l); 00345 fp->retr = (char*)calloc(strlen(p) + 8, 1); 00346 sprintf(fp->retr, "RETR %s\r\n", p); 00347 fp->size_cmd = (char*)calloc(strlen(p) + 8, 1); 00348 sprintf(fp->size_cmd, "SIZE %s\r\n", p); 00349 fp->seek_offset = 0; 00350 return fp; 00351 } 00352 // place ->fd at offset off 00353 int kftp_connect_file(knetFile *fp) 00354 { 00355 int ret; 00356 long long file_size; 00357 if (fp->fd != -1) { 00358 netclose(fp->fd); 00359 if (fp->no_reconnect) kftp_get_response(fp); 00360 } 00361 kftp_pasv_prep(fp); 00362 kftp_send_cmd(fp, fp->size_cmd, 1); 00363 if ( sscanf(fp->response,"%*d %lld", &file_size) != 1 ) 00364 { 00365 if(!knetsilent) 00366 { 00367 fprintf(stderr,"[kftp_connect_file] %s\n", fp->response); 00368 } 00369 return -1; 00370 } 00371 fp->file_size = file_size; 00372 if (fp->offset>=0) { 00373 char tmp[32]; 00374 #ifndef _WIN32 00375 sprintf(tmp, "REST %lld\r\n", (long long)fp->offset); 00376 #else 00377 strcpy(tmp, "REST "); 00378 int64tostr(tmp + 5, fp->offset); 00379 strcat(tmp, "\r\n"); 00380 #endif 00381 kftp_send_cmd(fp, tmp, 1); 00382 } 00383 kftp_send_cmd(fp, fp->retr, 0); 00384 kftp_pasv_connect(fp); 00385 ret = kftp_get_response(fp); 00386 if (ret != 150) { 00387 if(!knetsilent) 00388 { 00389 fprintf(stderr, "[kftp_connect_file] %s\n", fp->response); 00390 } 00391 netclose(fp->fd); 00392 fp->fd = -1; 00393 return -1; 00394 } 00395 fp->is_ready = 1; 00396 return 0; 00397 } 00398 00399 00400 /************************** 00401 * HTTP specific routines * 00402 **************************/ 00403 00404 knetFile *khttp_parse_url(const char *fn, const char *mode) 00405 { 00406 knetFile *fp; 00407 char *p, *proxy, *q; 00408 int l; 00409 if (strstr(fn, "http://") != fn) return 0; 00410 // set ->http_host 00411 for (p = (char*)fn + 7; *p && *p != '/'; ++p); 00412 l = p - fn - 7; 00413 fp = (knetFile*)calloc(1, sizeof(knetFile)); 00414 fp->http_host = (char*)calloc(l + 1, 1); 00415 strncpy(fp->http_host, fn + 7, l); 00416 fp->http_host[l] = 0; 00417 for (q = fp->http_host; *q && *q != ':'; ++q); 00418 if (*q == ':') *q++ = 0; 00419 // get http_proxy 00420 proxy = getenv("http_proxy"); 00421 // set ->host, ->port and ->path 00422 if (proxy == 0) { 00423 fp->host = strdup(fp->http_host); // when there is no proxy, server name is identical to http_host name. 00424 fp->port = strdup(*q? q : "80"); 00425 fp->path = strdup(*p? p : "/"); 00426 } else { 00427 fp->host = (strstr(proxy, "http://") == proxy)? strdup(proxy + 7) : strdup(proxy); 00428 for (q = fp->host; *q && *q != ':'; ++q); 00429 if (*q == ':') *q++ = 0; 00430 fp->port = strdup(*q? q : "80"); 00431 fp->path = strdup(fn); 00432 } 00433 fp->type = KNF_TYPE_HTTP; 00434 fp->ctrl_fd = fp->fd = -1; 00435 fp->seek_offset = 0; 00436 return fp; 00437 } 00438 00439 int khttp_connect_file(knetFile *fp) 00440 { 00441 int ret, l = 0; 00442 char *buf, *p; 00443 if (fp->fd != -1) netclose(fp->fd); 00444 fp->fd = socket_connect(fp->host, fp->port); 00445 buf = (char*)calloc(0x10000, 1); // FIXME: I am lazy... But in principle, 64KB should be large enough. 00446 l += sprintf(buf + l, "GET %s HTTP/1.0\r\nHost: %s\r\n", fp->path, fp->http_host); 00447 l += sprintf(buf + l, "Range: bytes=%lld-\r\n", (long long)fp->offset); 00448 l += sprintf(buf + l, "\r\n"); 00449 if(netwrite(fp->fd, buf, l) != l) 00450 { 00451 } 00452 l = 0; 00453 while (netread(fp->fd, buf + l, 1)) { // read HTTP header; FIXME: bad efficiency 00454 if (buf[l] == '\n' && l >= 3) 00455 if (strncmp(buf + l - 3, "\r\n\r\n", 4) == 0) break; 00456 ++l; 00457 } 00458 buf[l] = 0; 00459 if (l < 14) { // prematured header 00460 netclose(fp->fd); 00461 fp->fd = -1; 00462 return -1; 00463 } 00464 ret = strtol(buf + 8, &p, 0); // HTTP return code 00465 if (ret == 200 && fp->offset>0) { // 200 (complete result); then skip beginning of the file 00466 off_t rest = fp->offset; 00467 while (rest) { 00468 off_t l = rest < 0x10000? rest : 0x10000; 00469 rest -= my_netread(fp->fd, buf, l); 00470 } 00471 } else if (ret != 206 && ret != 200) { 00472 free(buf); 00473 if(!knetsilent) 00474 { 00475 fprintf(stderr, "[khttp_connect_file] fail to open file (HTTP code: %d).\n", ret); 00476 } 00477 netclose(fp->fd); 00478 fp->fd = -1; 00479 return -1; 00480 } 00481 free(buf); 00482 fp->is_ready = 1; 00483 return 0; 00484 } 00485 00486 /******************** 00487 * Generic routines * 00488 ********************/ 00489 00490 knetFile *knet_open(const char *fn, const char *mode) 00491 { 00492 knetFile *fp = 0; 00493 if (mode[0] != 'r') { 00494 if(!knetsilent) 00495 { 00496 fprintf(stderr, "[kftp_open] only mode \"r\" is supported.\n"); 00497 } 00498 return 0; 00499 } 00500 if (strstr(fn, "ftp://") == fn) { 00501 fp = kftp_parse_url(fn, mode); 00502 if (fp == 0) return 0; 00503 if (kftp_connect(fp) == -1) { 00504 knet_close(fp); 00505 return 0; 00506 } 00507 kftp_connect_file(fp); 00508 } else if (strstr(fn, "http://") == fn) { 00509 fp = khttp_parse_url(fn, mode); 00510 if (fp == 0) return 0; 00511 khttp_connect_file(fp); 00512 } else { // local file 00513 #ifdef _WIN32 00514 /* In windows, O_BINARY is necessary. In Linux/Mac, O_BINARY may 00515 * be undefined on some systems, although it is defined on my 00516 * Mac and the Linux I have tested on. */ 00517 int fd = open(fn, O_RDONLY | O_BINARY); 00518 #else 00519 int fd = open(fn, O_RDONLY); 00520 #endif 00521 if (fd == -1) { 00522 perror("open"); 00523 return 0; 00524 } 00525 fp = (knetFile*)calloc(1, sizeof(knetFile)); 00526 fp->type = KNF_TYPE_LOCAL; 00527 fp->fd = fd; 00528 fp->ctrl_fd = -1; 00529 } 00530 if (fp && fp->fd == -1) { 00531 knet_close(fp); 00532 return 0; 00533 } 00534 return fp; 00535 } 00536 00537 knetFile *knet_dopen(int fd, const char *mode) 00538 { 00539 knetFile *fp = (knetFile*)calloc(1, sizeof(knetFile)); 00540 fp->type = KNF_TYPE_LOCAL; 00541 fp->fd = fd; 00542 return fp; 00543 } 00544 00545 ssize_t knet_read(knetFile *fp, void *buf, size_t len) 00546 { 00547 off_t l = 0; 00548 if (fp->fd == -1) return 0; 00549 if (fp->type == KNF_TYPE_FTP) { 00550 if (fp->is_ready == 0) { 00551 if (!fp->no_reconnect) kftp_reconnect(fp); 00552 kftp_connect_file(fp); 00553 } 00554 } else if (fp->type == KNF_TYPE_HTTP) { 00555 if (fp->is_ready == 0) 00556 khttp_connect_file(fp); 00557 } 00558 if (fp->type == KNF_TYPE_LOCAL) { // on Windows, the following block is necessary; not on UNIX 00559 size_t rest = len; 00560 ssize_t curr; 00561 while (rest) { 00562 do { 00563 curr = read(fp->fd, (void*)((char*)buf + l), rest); 00564 } while (curr < 0 && EINTR == errno); 00565 if (curr < 0) return -1; 00566 if (curr == 0) break; 00567 l += curr; rest -= curr; 00568 } 00569 } else l = my_netread(fp->fd, buf, len); 00570 fp->offset += l; 00571 return l; 00572 } 00573 00574 off_t knet_seek(knetFile *fp, off_t off, int whence) 00575 { 00576 if (whence == SEEK_SET && off == fp->offset) return 0; 00577 if (fp->type == KNF_TYPE_LOCAL) { 00578 /* Be aware that lseek() returns the offset after seeking, while fseek() returns zero on success. */ 00579 off_t offset = lseek(fp->fd, off, whence); 00580 if (offset == -1) return -1; 00581 fp->offset = offset; 00582 return 0; 00583 } else if (fp->type == KNF_TYPE_FTP) { 00584 if (whence == SEEK_CUR) fp->offset += off; 00585 else if (whence == SEEK_SET) fp->offset = off; 00586 else if (whence == SEEK_END) fp->offset = fp->file_size + off; 00587 else return -1; 00588 fp->is_ready = 0; 00589 return 0; 00590 } else if (fp->type == KNF_TYPE_HTTP) { 00591 if (whence == SEEK_END) { // FIXME: can we allow SEEK_END in future? 00592 if(!knetsilent) 00593 { 00594 fprintf(stderr, "[knet_seek] SEEK_END is not supported for HTTP. Offset is unchanged.\n"); 00595 } 00596 errno = ESPIPE; 00597 return -1; 00598 } 00599 if (whence == SEEK_CUR) fp->offset += off; 00600 else if (whence == SEEK_SET) fp->offset = off; 00601 else return -1; 00602 fp->is_ready = 0; 00603 return 0; 00604 } 00605 errno = EINVAL; 00606 if(!knetsilent) 00607 { 00608 fprintf(stderr,"[knet_seek] %s\n", strerror(errno)); 00609 } 00610 return -1; 00611 } 00612 00613 int knet_close(knetFile *fp) 00614 { 00615 if (fp == 0) return 0; 00616 if (fp->ctrl_fd != -1) netclose(fp->ctrl_fd); // FTP specific 00617 if (fp->fd != -1) { 00618 /* On Linux/Mac, netclose() is an alias of close(), but on 00619 * Windows, it is an alias of closesocket(). */ 00620 if (fp->type == KNF_TYPE_LOCAL) close(fp->fd); 00621 else netclose(fp->fd); 00622 } 00623 free(fp->host); free(fp->port); 00624 free(fp->response); free(fp->retr); // FTP specific 00625 free(fp->path); free(fp->http_host); // HTTP specific 00626 free(fp); 00627 return 0; 00628 } 00629 00630 #ifdef KNETFILE_MAIN 00631 int main(void) 00632 { 00633 char *buf; 00634 knetFile *fp; 00635 int type = 4, l; 00636 #ifdef _WIN32 00637 knet_win32_init(); 00638 #endif 00639 buf = calloc(0x100000, 1); 00640 if (type == 0) { 00641 fp = knet_open("knetfile.c", "r"); 00642 knet_seek(fp, 1000, SEEK_SET); 00643 } else if (type == 1) { // NCBI FTP, large file 00644 fp = knet_open("ftp://ftp.ncbi.nih.gov/1000genomes/ftp/data/NA12878/alignment/NA12878.chrom6.SLX.SRP000032.2009_06.bam", "r"); 00645 knet_seek(fp, 2500000000ll, SEEK_SET); 00646 l = knet_read(fp, buf, 255); 00647 } else if (type == 2) { 00648 fp = knet_open("ftp://ftp.sanger.ac.uk/pub4/treefam/tmp/index.shtml", "r"); 00649 knet_seek(fp, 1000, SEEK_SET); 00650 } else if (type == 3) { 00651 fp = knet_open("http://www.sanger.ac.uk/Users/lh3/index.shtml", "r"); 00652 knet_seek(fp, 1000, SEEK_SET); 00653 } else if (type == 4) { 00654 fp = knet_open("http://www.sanger.ac.uk/Users/lh3/ex1.bam", "r"); 00655 knet_read(fp, buf, 10000); 00656 knet_seek(fp, 20000, SEEK_SET); 00657 knet_seek(fp, 10000, SEEK_SET); 00658 l = knet_read(fp, buf+10000, 10000000) + 10000; 00659 } 00660 if (type != 4 && type != 1) { 00661 knet_read(fp, buf, 255); 00662 buf[255] = 0; 00663 printf("%s\n", buf); 00664 } else write(fileno(stdout), buf, l); 00665 knet_close(fp); 00666 free(buf); 00667 return 0; 00668 } 00669 #endif