X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=knetfile.c;h=12dc2d17af733d2c5bb93870a3285833fdb063cd;hb=8cab5e6afd245a6dbbb1580dc37cd3ee36e55078;hp=dbec205d2c29a0a562a5e5d337a3e914c3de7c21;hpb=34c418836df8a03e0eb5243b9240f55abab5bd08;p=samtools.git diff --git a/knetfile.c b/knetfile.c index dbec205..12dc2d1 100644 --- a/knetfile.c +++ b/knetfile.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -9,13 +10,29 @@ #include #include "knetfile.h" +static int socket_wait(int fd, int is_read) +{ + fd_set fds, *fdr = 0, *fdw = 0; + struct timeval tv; + int ret; + tv.tv_sec = 5; tv.tv_usec = 0; // 5 seconds time out + FD_ZERO(&fds); + FD_SET(fd, &fds); + if (is_read) fdr = &fds; + else fdw = &fds; + ret = select(fd+1, fdr, fdw, 0, &tv); + if (ret == -1) perror("select"); + return ret; +} + static int kftp_get_response(knetFile *ftp) { unsigned char c; int n = 0; char *p; + if (socket_wait(ftp->ctrl_fd, 1) <= 0) return 0; while (read(ftp->ctrl_fd, &c, 1)) { // FIXME: this is *VERY BAD* for unbuffered I/O -// fputc(c, stderr); + //fputc(c, stderr); if (n >= ftp->max_response) { ftp->max_response = ftp->max_response? ftp->max_response<<1 : 256; ftp->response = realloc(ftp->response, ftp->max_response); @@ -35,6 +52,7 @@ static int kftp_get_response(knetFile *ftp) static int kftp_send_cmd(knetFile *ftp, const char *cmd, int is_get) { + if (socket_wait(ftp->ctrl_fd, 0) <= 0) return -1; // socket is not ready for writing write(ftp->ctrl_fd, cmd, strlen(cmd)); return is_get? kftp_get_response(ftp) : 0; } @@ -107,16 +125,16 @@ int kftp_connect(knetFile *ftp) int kftp_reconnect(knetFile *ftp) { - if (ftp->ctrl_fd) { + if (ftp->ctrl_fd >= 0) { close(ftp->ctrl_fd); - ftp->ctrl_fd = 0; + ftp->ctrl_fd = -1; } close(ftp->fd); return kftp_connect(ftp); } // initialize ->type, ->host and ->retr -knetFile *kftp_prep(const char *fn, const char *mode) +knetFile *kftp_parse_url(const char *fn, const char *mode) { knetFile *fp; char *p; @@ -127,30 +145,39 @@ knetFile *kftp_prep(const char *fn, const char *mode) l = p - fn - 6; fp = calloc(1, sizeof(knetFile)); fp->type = KNF_TYPE_FTP; + fp->fd = -1; fp->host = calloc(l + 1, 1); if (strchr(mode, 'c')) fp->no_reconnect = 1; strncpy(fp->host, fn + 6, l); fp->retr = calloc(strlen(p) + 8, 1); sprintf(fp->retr, "RETR %s\r\n", p); + fp->seek_offset = -1; return fp; } // place ->fd at offset off -int kftp_connect_file(knetFile *fp, off_t off) +int kftp_connect_file(knetFile *fp) { - if (fp->fd) { + int ret; + if (fp->fd >= 0) { close(fp->fd); if (fp->no_reconnect) kftp_get_response(fp); } kftp_pasv_prep(fp); - if (off) { + if (fp->offset) { char tmp[32]; - sprintf(tmp, "REST %lld\r\n", (long long)off); + sprintf(tmp, "REST %lld\r\n", (long long)fp->offset); kftp_send_cmd(fp, tmp, 1); } kftp_send_cmd(fp, fp->retr, 0); kftp_pasv_connect(fp); - kftp_get_response(fp); - fp->offset = off; + ret = kftp_get_response(fp); + if (ret != 150) { + fprintf(stderr, "[kftp_connect_file] %s\n", fp->response); + close(fp->fd); + fp->fd = -1; + return -1; + } + fp->is_ready = 1; return 0; } @@ -162,13 +189,17 @@ knetFile *knet_open(const char *fn, const char *mode) return 0; } if (strstr(fn, "ftp://") == fn) { - fp = kftp_prep(fn, mode); + fp = kftp_parse_url(fn, mode); if (fp == 0) return 0; if (kftp_connect(fp) == -1) { knet_close(fp); return 0; } - kftp_connect_file(fp, 0); + kftp_connect_file(fp); + if (fp->fd < 0) { + knet_close(fp); + return 0; + } } else { int fd = open(fn, O_RDONLY); if (fd == -1) { @@ -193,12 +224,19 @@ knetFile *knet_dopen(int fd, const char *mode) off_t knet_read(knetFile *fp, void *buf, off_t len) { off_t l = 0; + if (fp->fd < 0) return 0; if (fp->type == KNF_TYPE_LOCAL) { l = read(fp->fd, buf, len); fp->offset += l; } else { off_t rest = len, curr; + if (fp->is_ready == 0) { + if (!fp->no_reconnect) kftp_reconnect(fp); + kftp_connect_file(fp); + fp->is_ready = 1; + } while (rest) { + if (socket_wait(fp->fd, 1) <= 0) break; // socket is not ready for reading curr = read(fp->fd, buf + l, rest); if (curr == 0) break; // FIXME: end of file or bad network? I do not know... l += curr; rest -= curr; @@ -208,29 +246,33 @@ off_t knet_read(knetFile *fp, void *buf, off_t len) return l; } -off_t knet_seek(knetFile *fp, off_t off, int whence) +int knet_seek(knetFile *fp, off_t off, int whence) { if (fp->type == KNF_TYPE_LOCAL) { - fp->offset = lseek(fp->fd, off, whence); - return fp->offset; + if (lseek(fp->fd, off, whence) == -1) { + perror("lseek"); + return -1; + } + fp->offset = off; + return 0; } if (fp->type == KNF_TYPE_FTP) { - if (whence != SEEK_SET) { + if (whence != SEEK_SET) { // FIXME: we can surely allow SEEK_CUR and SEEK_END in future fprintf(stderr, "[knet_seek] only SEEK_SET is supported for FTP. Offset is unchanged.\n"); return -1; } - if (!fp->no_reconnect) kftp_reconnect(fp); - kftp_connect_file(fp, off); - return fp->offset; + fp->offset = off; + fp->is_ready = 0; + return 0; } - return 0; + return -1; } int knet_close(knetFile *fp) { if (fp == 0) return 0; - if (fp->ctrl_fd > 0) close(fp->ctrl_fd); - if (fp->fd > 0) close(fp->fd); + if (fp->ctrl_fd >= 0) close(fp->ctrl_fd); + if (fp->fd >= 0) close(fp->fd); free(fp->response); free(fp->retr); free(fp->host); free(fp); return 0;