libStatGen Software 1
Loading...
Searching...
No Matches
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
58int knetsilent = 0;
59
60
61void 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). */
79static 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/). */
115static 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" */
140char *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
155int64_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. */
163int knet_win32_init()
164{
165 WSADATA wsaData;
166 return WSAStartup(MAKEWORD(2, 2), &wsaData);
167}
168void 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. */
176static 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
211static 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
233static 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
262static 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
272static 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
287static 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
304int 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
315int 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
327knetFile *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
353int 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
404knetFile *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
439int 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
490knetFile *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
537knetFile *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
545ssize_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
574off_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
613int 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
631int 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