libStatGen Software  1
knetfile.c
1 /* The MIT License
2 
3  Copyright (c) 2008 by Genome Research Ltd (GRL).
4  2010 by Attractive Chaos <attractor@live.co.uk>
5 
6  Permission is hereby granted, free of charge, to any person obtaining
7  a copy of this software and associated documentation files (the
8  "Software"), to deal in the Software without restriction, including
9  without limitation the rights to use, copy, modify, merge, publish,
10  distribute, sublicense, and/or sell copies of the Software, and to
11  permit persons to whom the Software is furnished to do so, subject to
12  the following conditions:
13 
14  The above copyright notice and this permission notice shall be
15  included in all copies or substantial portions of the Software.
16 
17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  SOFTWARE.
25 */
26 
27 /* Probably I will not do socket programming in the next few years and
28  therefore I decide to heavily annotate this file, for Linux and
29  Windows as well. -ac */
30 
31 /*
32  * Updated 10/22/2013 by Mary Kate Wing
33  * Upgraded to latest version from htslib: develop branch
34  * 1) Fix compile warnings
35  * 2) Add flag to silently fail socket logic
36 */
37 
38 #include <time.h>
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/types.h>
45 
46 #ifndef _WIN32
47 #include <unistd.h>
48 #include <netdb.h>
49 #include <arpa/inet.h>
50 #include <sys/socket.h>
51 #else
52 #include <BaseTsd.h>
53 #endif
54 
55 #include "knetfile.h"
56 
57 
58 int knetsilent = 0;
59 
60 
61 void knet_silent(int silent)
62 {
63  knetsilent = silent;
64 }
65 
66 
67 /* In winsock.h, the type of a socket is SOCKET, which is: "typedef
68  * u_int SOCKET". An invalid SOCKET is: "(SOCKET)(~0)", or signed
69  * integer -1. In knetfile.c, I use "int" for socket type
70  * throughout. This should be improved to avoid confusion.
71  *
72  * In Linux/Mac, recv() and read() do almost the same thing. You can see
73  * in the header file that netread() is simply an alias of read(). In
74  * Windows, however, they are different and using recv() is mandatory.
75  */
76 
77 /* This function tests if the file handler is ready for reading (or
78  * writing if is_read==0). */
79 static int socket_wait(int fd, int is_read)
80 {
81  fd_set fds, *fdr = 0, *fdw = 0;
82  struct timeval tv;
83  int ret;
84  tv.tv_sec = 5; tv.tv_usec = 0; // 5 seconds time out
85  FD_ZERO(&fds);
86  FD_SET(fd, &fds);
87  if (is_read) fdr = &fds;
88  else fdw = &fds;
89  ret = select(fd+1, fdr, fdw, 0, &tv);
90 #ifndef _WIN32
91  if (ret == -1) perror("select");
92 #else
93  if (ret == 0)
94  {
95  if(!knetsilent)
96  {
97  fprintf(stderr, "select time-out\n");
98  }
99  }
100  else if (ret == SOCKET_ERROR)
101  {
102  if(!knetsilent)
103  {
104  fprintf(stderr, "select: %d\n", WSAGetLastError());
105  }
106  }
107 #endif
108  return ret;
109 }
110 
111 #ifndef _WIN32
112 /* This function does not work with Windows due to the lack of
113  * getaddrinfo() in winsock. It is addapted from an example in "Beej's
114  * Guide to Network Programming" (http://beej.us/guide/bgnet/). */
115 static int socket_connect(const char *host, const char *port)
116 {
117 #define __err_connect(func) do { if(!knetsilent){perror(func);} freeaddrinfo(res); return -1; } while (0)
118 
119  int on = 1, fd;
120  struct linger lng = { 0, 0 };
121  struct addrinfo hints, *res = 0;
122  memset(&hints, 0, sizeof(struct addrinfo));
123  hints.ai_family = AF_UNSPEC;
124  hints.ai_socktype = SOCK_STREAM;
125  /* In Unix/Mac, getaddrinfo() is the most convenient way to get
126  * server information. */
127  if (getaddrinfo(host, port, &hints, &res) != 0) __err_connect("getaddrinfo");
128  if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) __err_connect("socket");
129  /* The following two setsockopt() are used by ftplib
130  * (http://nbpfaus.net/~pfau/ftplib/). I am not sure if they
131  * necessary. */
132  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) __err_connect("setsockopt");
133  if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1) __err_connect("setsockopt");
134  if (connect(fd, res->ai_addr, res->ai_addrlen) != 0) __err_connect("connect");
135  freeaddrinfo(res);
136  return fd;
137 }
138 #else
139 /* MinGW's printf has problem with "%lld" */
140 char *int64tostr(char *buf, int64_t x)
141 {
142  int cnt;
143  int i = 0;
144  do {
145  buf[i++] = '0' + x % 10;
146  x /= 10;
147  } while (x);
148  buf[i] = 0;
149  for (cnt = i, i = 0; i < cnt/2; ++i) {
150  int c = buf[i]; buf[i] = buf[cnt-i-1]; buf[cnt-i-1] = c;
151  }
152  return buf;
153 }
154 
155 int64_t strtoint64(const char *buf)
156 {
157  int64_t x;
158  for (x = 0; *buf != '\0'; ++buf)
159  x = x * 10 + ((int64_t) *buf - 48);
160  return x;
161 }
162 /* In windows, the first thing is to establish the TCP connection. */
163 int knet_win32_init()
164 {
165  WSADATA wsaData;
166  return WSAStartup(MAKEWORD(2, 2), &wsaData);
167 }
168 void knet_win32_destroy()
169 {
170  WSACleanup();
171 }
172 /* A slightly modfied version of the following function also works on
173  * Mac (and presummably Linux). However, this function is not stable on
174  * my Mac. It sometimes works fine but sometimes does not. Therefore for
175  * non-Windows OS, I do not use this one. */
176 static SOCKET socket_connect(const char *host, const char *port)
177 {
178 #define __err_connect(func) \
179  do { \
180  if(!knetsilent) {fprintf(stderr, "%s: %d\n", func, WSAGetLastError());} \
181  return -1; \
182  } while (0)
183 
184  int on = 1;
185  SOCKET fd;
186  struct linger lng = { 0, 0 };
187  struct sockaddr_in server;
188  struct hostent *hp = 0;
189  // open socket
190  if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) __err_connect("socket");
191  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1) __err_connect("setsockopt");
192  if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&lng, sizeof(lng)) == -1) __err_connect("setsockopt");
193  // get host info
194  if (isalpha(host[0])) hp = gethostbyname(host);
195  else {
196  struct in_addr addr;
197  addr.s_addr = inet_addr(host);
198  hp = gethostbyaddr((char*)&addr, 4, AF_INET);
199  }
200  if (hp == 0) __err_connect("gethost");
201  // connect
202  server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
203  server.sin_family= AF_INET;
204  server.sin_port = htons(atoi(port));
205  if (connect(fd, (struct sockaddr*)&server, sizeof(server)) != 0) __err_connect("connect");
206  // freehostent(hp); // strangely in MSDN, hp is NOT freed (memory leak?!)
207  return fd;
208 }
209 #endif
210 
211 static off_t my_netread(int fd, void *buf, off_t len)
212 {
213  off_t rest = len, curr, l = 0;
214  /* recv() and read() may not read the required length of data with
215  * one call. They have to be called repeatedly. */
216  while (rest) {
217  if (socket_wait(fd, 1) <= 0) break; // socket is not ready for reading
218  curr = netread(fd, (void*)((char*)buf + l), rest);
219  /* According to the glibc manual, section 13.2, a zero returned
220  * value indicates end-of-file (EOF), which should mean that
221  * read() will not return zero if EOF has not been met but data
222  * are not immediately available. */
223  if (curr == 0) break;
224  l += curr; rest -= curr;
225  }
226  return l;
227 }
228 
229 /*************************
230  * FTP specific routines *
231  *************************/
232 
233 static int kftp_get_response(knetFile *ftp)
234 {
235 #ifndef _WIN32
236  unsigned char c;
237 #else
238  char c;
239 #endif
240  int n = 0;
241  char *p;
242  if (socket_wait(ftp->ctrl_fd, 1) <= 0) return 0;
243  while (netread(ftp->ctrl_fd, &c, 1)) { // FIXME: this is *VERY BAD* for unbuffered I/O
244  //fputc(c, stderr);
245  if (n >= ftp->max_response) {
246  ftp->max_response = ftp->max_response? ftp->max_response<<1 : 256;
247  ftp->response = (char*)realloc(ftp->response, ftp->max_response);
248  }
249  ftp->response[n++] = c;
250  if (c == '\n') {
251  if (n >= 4 && isdigit(ftp->response[0]) && isdigit(ftp->response[1]) && isdigit(ftp->response[2])
252  && ftp->response[3] != '-') break;
253  n = 0;
254  continue;
255  }
256  }
257  if (n < 2) return -1;
258  ftp->response[n-2] = 0;
259  return strtol(ftp->response, &p, 0);
260 }
261 
262 static int kftp_send_cmd(knetFile *ftp, const char *cmd, int is_get)
263 {
264  if (socket_wait(ftp->ctrl_fd, 0) <= 0) return -1; // socket is not ready for writing
265  if(netwrite(ftp->ctrl_fd, cmd, strlen(cmd)) != strlen(cmd))
266  {
267 
268  }
269  return is_get? kftp_get_response(ftp) : 0;
270 }
271 
272 static int kftp_pasv_prep(knetFile *ftp)
273 {
274  char *p;
275  int v[6];
276  kftp_send_cmd(ftp, "PASV\r\n", 1);
277  for (p = ftp->response; *p && *p != '('; ++p);
278  if (*p != '(') return -1;
279  ++p;
280  sscanf(p, "%d,%d,%d,%d,%d,%d", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5]);
281  memcpy(ftp->pasv_ip, v, 4 * sizeof(int));
282  ftp->pasv_port = (v[4]<<8&0xff00) + v[5];
283  return 0;
284 }
285 
286 
287 static int kftp_pasv_connect(knetFile *ftp)
288 {
289  char host[80], port[10];
290  if (ftp->pasv_port == 0) {
291  if(!knetsilent)
292  {
293  fprintf(stderr, "[kftp_pasv_connect] kftp_pasv_prep() is not called before hand.\n");
294  }
295  return -1;
296  }
297  sprintf(host, "%d.%d.%d.%d", ftp->pasv_ip[0], ftp->pasv_ip[1], ftp->pasv_ip[2], ftp->pasv_ip[3]);
298  sprintf(port, "%d", ftp->pasv_port);
299  ftp->fd = socket_connect(host, port);
300  if (ftp->fd == -1) return -1;
301  return 0;
302 }
303 
304 int kftp_connect(knetFile *ftp)
305 {
306  ftp->ctrl_fd = socket_connect(ftp->host, ftp->port);
307  if (ftp->ctrl_fd == -1) return -1;
308  kftp_get_response(ftp);
309  kftp_send_cmd(ftp, "USER anonymous\r\n", 1);
310  kftp_send_cmd(ftp, "PASS kftp@\r\n", 1);
311  kftp_send_cmd(ftp, "TYPE I\r\n", 1);
312  return 0;
313 }
314 
315 int kftp_reconnect(knetFile *ftp)
316 {
317  if (ftp->ctrl_fd != -1) {
318  netclose(ftp->ctrl_fd);
319  ftp->ctrl_fd = -1;
320  }
321  netclose(ftp->fd);
322  ftp->fd = -1;
323  return kftp_connect(ftp);
324 }
325 
326 // initialize ->type, ->host, ->retr and ->size
327 knetFile *kftp_parse_url(const char *fn, const char *mode)
328 {
329  knetFile *fp;
330  char *p;
331  int l;
332  if (strstr(fn, "ftp://") != fn) return 0;
333  for (p = (char*)fn + 6; *p && *p != '/'; ++p);
334  if (*p != '/') return 0;
335  l = p - fn - 6;
336  fp = (knetFile*)calloc(1, sizeof(knetFile));
337  fp->type = KNF_TYPE_FTP;
338  fp->fd = -1;
339  /* the Linux/Mac version of socket_connect() also recognizes a port
340  * like "ftp", but the Windows version does not. */
341  fp->port = strdup("21");
342  fp->host = (char*)calloc(l + 1, 1);
343  if (strchr(mode, 'c')) fp->no_reconnect = 1;
344  strncpy(fp->host, fn + 6, l);
345  fp->retr = (char*)calloc(strlen(p) + 8, 1);
346  sprintf(fp->retr, "RETR %s\r\n", p);
347  fp->size_cmd = (char*)calloc(strlen(p) + 8, 1);
348  sprintf(fp->size_cmd, "SIZE %s\r\n", p);
349  fp->seek_offset = 0;
350  return fp;
351 }
352 // place ->fd at offset off
353 int kftp_connect_file(knetFile *fp)
354 {
355  int ret;
356  long long file_size;
357  if (fp->fd != -1) {
358  netclose(fp->fd);
359  if (fp->no_reconnect) kftp_get_response(fp);
360  }
361  kftp_pasv_prep(fp);
362  kftp_send_cmd(fp, fp->size_cmd, 1);
363  if ( sscanf(fp->response,"%*d %lld", &file_size) != 1 )
364  {
365  if(!knetsilent)
366  {
367  fprintf(stderr,"[kftp_connect_file] %s\n", fp->response);
368  }
369  return -1;
370  }
371  fp->file_size = file_size;
372  if (fp->offset>=0) {
373  char tmp[32];
374 #ifndef _WIN32
375  sprintf(tmp, "REST %lld\r\n", (long long)fp->offset);
376 #else
377  strcpy(tmp, "REST ");
378  int64tostr(tmp + 5, fp->offset);
379  strcat(tmp, "\r\n");
380 #endif
381  kftp_send_cmd(fp, tmp, 1);
382  }
383  kftp_send_cmd(fp, fp->retr, 0);
384  kftp_pasv_connect(fp);
385  ret = kftp_get_response(fp);
386  if (ret != 150) {
387  if(!knetsilent)
388  {
389  fprintf(stderr, "[kftp_connect_file] %s\n", fp->response);
390  }
391  netclose(fp->fd);
392  fp->fd = -1;
393  return -1;
394  }
395  fp->is_ready = 1;
396  return 0;
397 }
398 
399 
400 /**************************
401  * HTTP specific routines *
402  **************************/
403 
404 knetFile *khttp_parse_url(const char *fn, const char *mode)
405 {
406  knetFile *fp;
407  char *p, *proxy, *q;
408  int l;
409  if (strstr(fn, "http://") != fn) return 0;
410  // set ->http_host
411  for (p = (char*)fn + 7; *p && *p != '/'; ++p);
412  l = p - fn - 7;
413  fp = (knetFile*)calloc(1, sizeof(knetFile));
414  fp->http_host = (char*)calloc(l + 1, 1);
415  strncpy(fp->http_host, fn + 7, l);
416  fp->http_host[l] = 0;
417  for (q = fp->http_host; *q && *q != ':'; ++q);
418  if (*q == ':') *q++ = 0;
419  // get http_proxy
420  proxy = getenv("http_proxy");
421  // set ->host, ->port and ->path
422  if (proxy == 0) {
423  fp->host = strdup(fp->http_host); // when there is no proxy, server name is identical to http_host name.
424  fp->port = strdup(*q? q : "80");
425  fp->path = strdup(*p? p : "/");
426  } else {
427  fp->host = (strstr(proxy, "http://") == proxy)? strdup(proxy + 7) : strdup(proxy);
428  for (q = fp->host; *q && *q != ':'; ++q);
429  if (*q == ':') *q++ = 0;
430  fp->port = strdup(*q? q : "80");
431  fp->path = strdup(fn);
432  }
433  fp->type = KNF_TYPE_HTTP;
434  fp->ctrl_fd = fp->fd = -1;
435  fp->seek_offset = 0;
436  return fp;
437 }
438 
439 int khttp_connect_file(knetFile *fp)
440 {
441  int ret, l = 0;
442  char *buf, *p;
443  if (fp->fd != -1) netclose(fp->fd);
444  fp->fd = socket_connect(fp->host, fp->port);
445  buf = (char*)calloc(0x10000, 1); // FIXME: I am lazy... But in principle, 64KB should be large enough.
446  l += sprintf(buf + l, "GET %s HTTP/1.0\r\nHost: %s\r\n", fp->path, fp->http_host);
447  l += sprintf(buf + l, "Range: bytes=%lld-\r\n", (long long)fp->offset);
448  l += sprintf(buf + l, "\r\n");
449  if(netwrite(fp->fd, buf, l) != l)
450  {
451  }
452  l = 0;
453  while (netread(fp->fd, buf + l, 1)) { // read HTTP header; FIXME: bad efficiency
454  if (buf[l] == '\n' && l >= 3)
455  if (strncmp(buf + l - 3, "\r\n\r\n", 4) == 0) break;
456  ++l;
457  }
458  buf[l] = 0;
459  if (l < 14) { // prematured header
460  netclose(fp->fd);
461  fp->fd = -1;
462  return -1;
463  }
464  ret = strtol(buf + 8, &p, 0); // HTTP return code
465  if (ret == 200 && fp->offset>0) { // 200 (complete result); then skip beginning of the file
466  off_t rest = fp->offset;
467  while (rest) {
468  off_t l = rest < 0x10000? rest : 0x10000;
469  rest -= my_netread(fp->fd, buf, l);
470  }
471  } else if (ret != 206 && ret != 200) {
472  free(buf);
473  if(!knetsilent)
474  {
475  fprintf(stderr, "[khttp_connect_file] fail to open file (HTTP code: %d).\n", ret);
476  }
477  netclose(fp->fd);
478  fp->fd = -1;
479  return -1;
480  }
481  free(buf);
482  fp->is_ready = 1;
483  return 0;
484 }
485 
486 /********************
487  * Generic routines *
488  ********************/
489 
490 knetFile *knet_open(const char *fn, const char *mode)
491 {
492  knetFile *fp = 0;
493  if (mode[0] != 'r') {
494  if(!knetsilent)
495  {
496  fprintf(stderr, "[kftp_open] only mode \"r\" is supported.\n");
497  }
498  return 0;
499  }
500  if (strstr(fn, "ftp://") == fn) {
501  fp = kftp_parse_url(fn, mode);
502  if (fp == 0) return 0;
503  if (kftp_connect(fp) == -1) {
504  knet_close(fp);
505  return 0;
506  }
507  kftp_connect_file(fp);
508  } else if (strstr(fn, "http://") == fn) {
509  fp = khttp_parse_url(fn, mode);
510  if (fp == 0) return 0;
511  khttp_connect_file(fp);
512  } else { // local file
513 #ifdef _WIN32
514  /* In windows, O_BINARY is necessary. In Linux/Mac, O_BINARY may
515  * be undefined on some systems, although it is defined on my
516  * Mac and the Linux I have tested on. */
517  int fd = open(fn, O_RDONLY | O_BINARY);
518 #else
519  int fd = open(fn, O_RDONLY);
520 #endif
521  if (fd == -1) {
522  perror("open");
523  return 0;
524  }
525  fp = (knetFile*)calloc(1, sizeof(knetFile));
526  fp->type = KNF_TYPE_LOCAL;
527  fp->fd = fd;
528  fp->ctrl_fd = -1;
529  }
530  if (fp && fp->fd == -1) {
531  knet_close(fp);
532  return 0;
533  }
534  return fp;
535 }
536 
537 knetFile *knet_dopen(int fd, const char *mode)
538 {
539  knetFile *fp = (knetFile*)calloc(1, sizeof(knetFile));
540  fp->type = KNF_TYPE_LOCAL;
541  fp->fd = fd;
542  return fp;
543 }
544 
545 ssize_t knet_read(knetFile *fp, void *buf, size_t len)
546 {
547  off_t l = 0;
548  if (fp->fd == -1) return 0;
549  if (fp->type == KNF_TYPE_FTP) {
550  if (fp->is_ready == 0) {
551  if (!fp->no_reconnect) kftp_reconnect(fp);
552  kftp_connect_file(fp);
553  }
554  } else if (fp->type == KNF_TYPE_HTTP) {
555  if (fp->is_ready == 0)
556  khttp_connect_file(fp);
557  }
558  if (fp->type == KNF_TYPE_LOCAL) { // on Windows, the following block is necessary; not on UNIX
559  size_t rest = len;
560  ssize_t curr;
561  while (rest) {
562  do {
563  curr = read(fp->fd, (void*)((char*)buf + l), rest);
564  } while (curr < 0 && EINTR == errno);
565  if (curr < 0) return -1;
566  if (curr == 0) break;
567  l += curr; rest -= curr;
568  }
569  } else l = my_netread(fp->fd, buf, len);
570  fp->offset += l;
571  return l;
572 }
573 
574 off_t knet_seek(knetFile *fp, off_t off, int whence)
575 {
576  if (whence == SEEK_SET && off == fp->offset) return 0;
577  if (fp->type == KNF_TYPE_LOCAL) {
578  /* Be aware that lseek() returns the offset after seeking, while fseek() returns zero on success. */
579  off_t offset = lseek(fp->fd, off, whence);
580  if (offset == -1) return -1;
581  fp->offset = offset;
582  return 0;
583  } else if (fp->type == KNF_TYPE_FTP) {
584  if (whence == SEEK_CUR) fp->offset += off;
585  else if (whence == SEEK_SET) fp->offset = off;
586  else if (whence == SEEK_END) fp->offset = fp->file_size + off;
587  else return -1;
588  fp->is_ready = 0;
589  return 0;
590  } else if (fp->type == KNF_TYPE_HTTP) {
591  if (whence == SEEK_END) { // FIXME: can we allow SEEK_END in future?
592  if(!knetsilent)
593  {
594  fprintf(stderr, "[knet_seek] SEEK_END is not supported for HTTP. Offset is unchanged.\n");
595  }
596  errno = ESPIPE;
597  return -1;
598  }
599  if (whence == SEEK_CUR) fp->offset += off;
600  else if (whence == SEEK_SET) fp->offset = off;
601  else return -1;
602  fp->is_ready = 0;
603  return 0;
604  }
605  errno = EINVAL;
606  if(!knetsilent)
607  {
608  fprintf(stderr,"[knet_seek] %s\n", strerror(errno));
609  }
610  return -1;
611 }
612 
613 int knet_close(knetFile *fp)
614 {
615  if (fp == 0) return 0;
616  if (fp->ctrl_fd != -1) netclose(fp->ctrl_fd); // FTP specific
617  if (fp->fd != -1) {
618  /* On Linux/Mac, netclose() is an alias of close(), but on
619  * Windows, it is an alias of closesocket(). */
620  if (fp->type == KNF_TYPE_LOCAL) close(fp->fd);
621  else netclose(fp->fd);
622  }
623  free(fp->host); free(fp->port);
624  free(fp->response); free(fp->retr); // FTP specific
625  free(fp->path); free(fp->http_host); // HTTP specific
626  free(fp);
627  return 0;
628 }
629 
630 #ifdef KNETFILE_MAIN
631 int main(void)
632 {
633  char *buf;
634  knetFile *fp;
635  int type = 4, l;
636 #ifdef _WIN32
637  knet_win32_init();
638 #endif
639  buf = calloc(0x100000, 1);
640  if (type == 0) {
641  fp = knet_open("knetfile.c", "r");
642  knet_seek(fp, 1000, SEEK_SET);
643  } else if (type == 1) { // NCBI FTP, large file
644  fp = knet_open("ftp://ftp.ncbi.nih.gov/1000genomes/ftp/data/NA12878/alignment/NA12878.chrom6.SLX.SRP000032.2009_06.bam", "r");
645  knet_seek(fp, 2500000000ll, SEEK_SET);
646  l = knet_read(fp, buf, 255);
647  } else if (type == 2) {
648  fp = knet_open("ftp://ftp.sanger.ac.uk/pub4/treefam/tmp/index.shtml", "r");
649  knet_seek(fp, 1000, SEEK_SET);
650  } else if (type == 3) {
651  fp = knet_open("http://www.sanger.ac.uk/Users/lh3/index.shtml", "r");
652  knet_seek(fp, 1000, SEEK_SET);
653  } else if (type == 4) {
654  fp = knet_open("http://www.sanger.ac.uk/Users/lh3/ex1.bam", "r");
655  knet_read(fp, buf, 10000);
656  knet_seek(fp, 20000, SEEK_SET);
657  knet_seek(fp, 10000, SEEK_SET);
658  l = knet_read(fp, buf+10000, 10000000) + 10000;
659  }
660  if (type != 4 && type != 1) {
661  knet_read(fp, buf, 255);
662  buf[255] = 0;
663  printf("%s\n", buf);
664  } else write(fileno(stdout), buf, l);
665  knet_close(fp);
666  free(buf);
667  return 0;
668 }
669 #endif
knetFile_s
Definition: knetfile.h:24