libStatGen Software  1
knetfile.c
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends