]> git.donarmstrong.com Git - samtools.git/blobdiff - knetfile.c
works
[samtools.git] / knetfile.c
index 9e11dcc19ed71d42bab4ae47f480b81382602fc9..af091465862c238aefeb3d0562b03f75320b6c1d 100644 (file)
@@ -1,6 +1,7 @@
 /* The MIT License
 
-   Copyright (c) 2008 Genome Research Ltd (GRL).
+   Copyright (c) 2008 by Genome Research Ltd (GRL).
+                 2010 by Attractive Chaos <attractor@live.co.uk>
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
    SOFTWARE.
 */
 
-/* Contact: Heng Li <lh3@sanger.ac.uk> */
-
 /* Probably I will not do socket programming in the next few years and
    therefore I decide to heavily annotate this file, for Linux and
-   Windows as well.  -lh3 */
+   Windows as well.  -ac */
 
 #include <time.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <unistd.h>
 #include <sys/types.h>
 
-#ifdef _WIN32
-#include <winsock.h>
-#else
+#ifndef _WIN32
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <sys/socket.h>
@@ -70,7 +68,14 @@ static int socket_wait(int fd, int is_read)
        if (is_read) fdr = &fds;
        else fdw = &fds;
        ret = select(fd+1, fdr, fdw, 0, &tv);
+#ifndef _WIN32
        if (ret == -1) perror("select");
+#else
+       if (ret == 0)
+               fprintf(stderr, "select time-out\n");
+       else if (ret == SOCKET_ERROR)
+               fprintf(stderr, "select: %d\n", WSAGetLastError());
+#endif
        return ret;
 }
 
@@ -84,7 +89,7 @@ static int socket_connect(const char *host, const char *port)
 
        int on = 1, fd;
        struct linger lng = { 0, 0 };
-       struct addrinfo hints, *res;
+       struct addrinfo hints, *res = 0;
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
@@ -103,16 +108,28 @@ static int socket_connect(const char *host, const char *port)
 }
 #else
 /* MinGW's printf has problem with "%lld" */
-char *uint64tostr(char *buf, uint64_t x)
+char *int64tostr(char *buf, int64_t x)
 {
-       int i, cnt;
-       for (i = 0; x; x /= 10) buf[i++] = '0' + x%10;
+       int cnt;
+       int i = 0;
+       do {
+               buf[i++] = '0' + x % 10;
+               x /= 10;
+       } while (x);
        buf[i] = 0;
        for (cnt = i, i = 0; i < cnt/2; ++i) {
                int c = buf[i]; buf[i] = buf[cnt-i-1]; buf[cnt-i-1] = c;
        }
        return buf;
 }
+
+int64_t strtoint64(const char *buf)
+{
+       int64_t x;
+       for (x = 0; *buf != '\0'; ++buf)
+               x = x * 10 + ((int64_t) *buf - 48);
+       return x;
+}
 /* In windows, the first thing is to establish the TCP connection. */
 int knet_win32_init()
 {
@@ -129,7 +146,11 @@ void knet_win32_destroy()
  * non-Windows OS, I do not use this one. */
 static SOCKET socket_connect(const char *host, const char *port)
 {
-#define __err_connect(func) do { perror(func); return -1; } while (0)
+#define __err_connect(func)                                                                            \
+       do {                                                                                                            \
+               fprintf(stderr, "%s: %d\n", func, WSAGetLastError());   \
+               return -1;                                                                                              \
+       } while (0)
 
        int on = 1;
        SOCKET fd;
@@ -182,7 +203,11 @@ static off_t my_netread(int fd, void *buf, off_t len)
 
 static int kftp_get_response(knetFile *ftp)
 {
+#ifndef _WIN32
        unsigned char c;
+#else
+       char c;
+#endif
        int n = 0;
        char *p;
        if (socket_wait(ftp->ctrl_fd, 1) <= 0) return 0;
@@ -259,6 +284,7 @@ int kftp_reconnect(knetFile *ftp)
                ftp->ctrl_fd = -1;
        }
        netclose(ftp->fd);
+       ftp->fd = -1;
        return kftp_connect(ftp);
 }
 
@@ -299,18 +325,26 @@ int kftp_connect_file(knetFile *fp)
        }
        kftp_pasv_prep(fp);
     kftp_send_cmd(fp, fp->size_cmd, 1);
+#ifndef _WIN32
     if ( sscanf(fp->response,"%*d %lld", &file_size) != 1 )
     {
         fprintf(stderr,"[kftp_connect_file] %s\n", fp->response);
         return -1;
-    } else fp->file_size = file_size;
+    }
+#else
+       const char *p = fp->response;
+       while (*p != ' ') ++p;
+       while (*p < '0' || *p > '9') ++p;
+       file_size = strtoint64(p);
+#endif
+       fp->file_size = file_size;
        if (fp->offset>=0) {
                char tmp[32];
 #ifndef _WIN32
                sprintf(tmp, "REST %lld\r\n", (long long)fp->offset);
 #else
                strcpy(tmp, "REST ");
-               uint64tostr(tmp + 5, fp->offset);
+               int64tostr(tmp + 5, fp->offset);
                strcat(tmp, "\r\n");
 #endif
                kftp_send_cmd(fp, tmp, 1);
@@ -482,7 +516,10 @@ off_t knet_read(knetFile *fp, void *buf, off_t len)
        if (fp->type == KNF_TYPE_LOCAL) { // on Windows, the following block is necessary; not on UNIX
                off_t rest = len, curr;
                while (rest) {
-                       curr = read(fp->fd, buf + l, rest);
+                       do {
+                               curr = read(fp->fd, buf + l, rest);
+                       } while (curr < 0 && EINTR == errno);
+                       if (curr < 0) return -1;
                        if (curr == 0) break;
                        l += curr; rest -= curr;
                }
@@ -491,7 +528,7 @@ off_t knet_read(knetFile *fp, void *buf, off_t len)
        return l;
 }
 
-off_t knet_seek(knetFile *fp, off_t off, int whence)
+off_t knet_seek(knetFile *fp, int64_t off, int whence)
 {
        if (whence == SEEK_SET && off == fp->offset) return 0;
        if (fp->type == KNF_TYPE_LOCAL) {
@@ -499,7 +536,8 @@ off_t knet_seek(knetFile *fp, off_t off, int whence)
                 * while fseek() returns zero on success. */
                off_t offset = lseek(fp->fd, off, whence);
                if (offset == -1) {
-                       perror("lseek");
+            // Be silent, it is OK for knet_seek to fail when the file is streamed
+            // fprintf(stderr,"[knet_seek] %s\n", strerror(errno));
                        return -1;
                }
                fp->offset = offset;
@@ -520,6 +558,7 @@ off_t knet_seek(knetFile *fp, off_t off, int whence)
     {
                if (whence == SEEK_END) { // FIXME: can we allow SEEK_END in future?
                        fprintf(stderr, "[knet_seek] SEEK_END is not supported for HTTP. Offset is unchanged.\n");
+                       errno = ESPIPE;
                        return -1;
                }
         if (whence==SEEK_CUR)
@@ -527,8 +566,10 @@ off_t knet_seek(knetFile *fp, off_t off, int whence)
         else if (whence==SEEK_SET)
             fp->offset = off;
                fp->is_ready = 0;
-               return fp->offset;
+               return 0;
        }
+       errno = EINVAL;
+    fprintf(stderr,"[knet_seek] %s\n", strerror(errno));
        return -1;
 }