Back to index

avfs  1.0.1
Classes | Defines | Typedefs | Enumerations | Functions
nsocket.h File Reference
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "neon_defs.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  nssl_certificate

Defines

#define SOCK_ERROR   -1
#define SOCK_TIMEOUT   -2
#define SOCK_FULL   -3
#define SOCK_CLOSED   -4
#define SOCKET_READ_TIMEOUT   120

Typedefs

typedef struct nsocket_s
typedef void(* sock_block_reader )(void *userdata, const char *buf, size_t len)
typedef void(* sock_progress )(void *userdata, off_t progress, off_t total)
typedef void(* sock_notify )(void *userdata, sock_status status, const char *info)
typedef struct nssl_context_s
typedef int(* nssl_accept )(void *userdata, const nssl_certificate *info)
typedef int(* nssl_key_prompt )(void *userdata, const char *filename, char *buf, int buflen)

Enumerations

enum  sock_status { sock_namelookup, sock_connecting, sock_connected, sock_secure_details }

Functions

void sock_register_progress (sock_progress cb, void *userdata)
void sock_register_notify (sock_notify cb, void *userdata)
void sock_call_progress (off_t progress, off_t total)
int sock_init (void)
void sock_exit (void)
int sock_read (nsocket *sock, char *buffer, size_t count)
int sock_peek (nsocket *sock, char *buffer, size_t count)
int sock_block (nsocket *sock, int timeout)
int sock_transfer (int fd, nsocket *sock, off_t readlen)
int sock_sendline (nsocket *sock, const char *line)
int sock_fullwrite (nsocket *sock, const char *data, size_t length)
int sock_send_string (nsocket *sock, const char *string)
int sock_readline (nsocket *sock, char *line, int len)
int sock_fullread (nsocket *sock, char *buffer, int buflen)
nsocket * sock_connect (const struct in_addr host, unsigned short int portnum)
nsocket * sock_connect_u (const struct in_addr addr, unsigned short int portnum, int call_fe)
nsocket * sock_accept (int listener)
int sock_get_fd (nsocket *sock)
int sock_close (nsocket *sock)
const char * sock_get_error (nsocket *sock)
int sock_name_lookup (const char *hostname, struct in_addr *addr)
int sock_service_lookup (const char *name)
int sock_readfile_blocked (nsocket *sock, off_t length, sock_block_reader reader, void *userdata)
nssl_context * sock_create_ssl_context (void)
void sock_destroy_ssl_context (nssl_context *ctx)
void sock_set_cert_accept (nssl_context *c, nssl_accept accepter, void *userdata)
void sock_set_key_prompt (nssl_context *c, nssl_key_prompt prompt, void *userdata)
int sock_set_client_cert (nssl_context *ctx, const char *certfile, const char *keyfile)
void sock_disable_tlsv1 (nssl_context *c)
void sock_disable_sslv2 (nssl_context *c)
void sock_disable_sslv3 (nssl_context *c)
int sock_make_secure (nsocket *sock, nssl_context *ctx)

Class Documentation

struct nssl_certificate

Definition at line 188 of file nsocket.h.

Class Members
char * fingerprint
char * issuer
char * owner
char * valid_from
char * valid_till

Define Documentation

#define SOCK_CLOSED   -4

Definition at line 44 of file nsocket.h.

#define SOCK_ERROR   -1

Definition at line 38 of file nsocket.h.

#define SOCK_FULL   -3

Definition at line 42 of file nsocket.h.

#define SOCK_TIMEOUT   -2

Definition at line 40 of file nsocket.h.

#define SOCKET_READ_TIMEOUT   120

Definition at line 47 of file nsocket.h.


Typedef Documentation

typedef struct nsocket_s

Definition at line 57 of file nsocket.h.

typedef int(* nssl_accept)(void *userdata, const nssl_certificate *info)

Definition at line 202 of file nsocket.h.

typedef struct nssl_context_s

Definition at line 171 of file nsocket.h.

typedef int(* nssl_key_prompt)(void *userdata, const char *filename, char *buf, int buflen)

Definition at line 214 of file nsocket.h.

typedef void(* sock_block_reader)(void *userdata, const char *buf, size_t len)

Definition at line 59 of file nsocket.h.

typedef void(* sock_notify)(void *userdata, sock_status status, const char *info)

Definition at line 63 of file nsocket.h.

typedef void(* sock_progress)(void *userdata, off_t progress, off_t total)

Definition at line 62 of file nsocket.h.


Enumeration Type Documentation

Enumerator:
sock_namelookup 
sock_connecting 
sock_connected 
sock_secure_details 

Definition at line 49 of file nsocket.h.

             {
    sock_namelookup, /* Looking up hostname given by info */
    sock_connecting, /* Connecting to server */
    sock_connected, /* Connection established */
    sock_secure_details /* Secure connection details */
} sock_status;

Function Documentation

nsocket* sock_accept ( int  listener)

Definition at line 727 of file socket.c.

{
    int fd = accept(listener, NULL, NULL);
    if (fd > 0) {
       return create_sock(fd);
    } else {
       return NULL;
    }
}

Here is the call graph for this function:

int sock_block ( nsocket *  sock,
int  timeout 
)

Definition at line 345 of file socket.c.

{
    struct timeval tv;
    fd_set fds;
    int ret;

#ifdef ENABLE_SSL
    if (sock->ssl) {
       /* There may be data already available in the 
        * SSL buffers */
       if (SSL_pending(sock->ssl)) {
           return 0;
       }
       /* Otherwise, we should be able to select on
        * the socket as per normal. Probably? */
    }
#endif
#ifdef BEOS_PRE_BONE
    if (sock->peeked_bytes_avail > 0) {
        return 0;
    }
#endif

    /* Init the fd set */
    FD_ZERO(&fds);
    FD_SET(sock->fd, &fds);
    /* Set the timeout */
    tv.tv_sec = timeout;
    tv.tv_usec = 0;
    do {
       ret = select(sock->fd+1, &fds, NULL, NULL, &tv);
    } while (ret == -1 && errno == EINTR);

    switch(ret) {
    case 0:
       return SOCK_TIMEOUT;
    case -1:
       sock->error = strerror(errno);
       return SOCK_ERROR;
    default:
       return 0;
    }
}
void sock_call_progress ( off_t  progress,
off_t  total 
)

Definition at line 178 of file socket.c.

{
    if (progress_cb) {
       (*progress_cb)(progress_ud, progress, total);
    }
}
int sock_close ( nsocket *  sock)

Definition at line 870 of file socket.c.

                              {
    int ret;
#ifdef ENABLE_SSL
    if (sock->ssl) {
       SSL_shutdown(sock->ssl);
       SSL_free(sock->ssl);
    }
    SSL_CTX_free(sock->default_ctx);
#endif
    ret = NEON_CLOSE(sock->fd);
    free(sock);
    return ret;
}
nsocket* sock_connect ( const struct in_addr  host,
unsigned short int  portnum 
)

Definition at line 742 of file socket.c.

                                                {
    return sock_connect_u(addr, portnum, 1);
}
nsocket* sock_connect_u ( const struct in_addr  addr,
unsigned short int  portnum,
int  call_fe 
)

Definition at line 702 of file socket.c.

{
    struct sockaddr_in sa;
    int fd;

    /* Create the socket */
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0)
       return NULL;
    /* Connect the nsocket */
    sa.sin_family = AF_INET;
    sa.sin_port = htons(portnum); /* host -> net byte orders */
    sa.sin_addr = addr;
    if (call_fe && notify_cb) (*notify_cb)(notify_ud, sock_connecting, NULL);
    if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
       (void) NEON_CLOSE(fd);
       return NULL;
    }
    if (call_fe && notify_cb) (*notify_cb)(notify_ud, sock_connected, NULL);
    /* Success - return the nsocket */
    return create_sock(fd);
}

Here is the call graph for this function:

nssl_context* sock_create_ssl_context ( void  )

Definition at line 747 of file socket.c.

{
    nssl_context *ctx = ne_calloc(sizeof *ctx);
#ifdef ENABLE_SSL
    ctx->ctx = SSL_CTX_new(SSLv23_client_method());
#endif
    return ctx;
}
void sock_destroy_ssl_context ( nssl_context *  ctx)

Definition at line 756 of file socket.c.

{
#ifdef ENABLE_SSL
    SSL_CTX_free(ctx->ctx);
#endif
    free(ctx);
}
void sock_disable_sslv2 ( nssl_context *  c)

Definition at line 805 of file socket.c.

{}
void sock_disable_sslv3 ( nssl_context *  c)

Definition at line 806 of file socket.c.

{}
void sock_disable_tlsv1 ( nssl_context *  c)

Definition at line 804 of file socket.c.

{}
void sock_exit ( void  )

Definition at line 210 of file socket.c.

{
#ifdef WIN32
    WSACleanup();
#endif 
}
int sock_fullread ( nsocket *  sock,
char *  buffer,
int  buflen 
)

Definition at line 625 of file socket.c.

{
    char *pnt; /* current position within buffer */
    int len;
    pnt = buffer;
    while (buflen > 0) {
       len = sock_read(sock, pnt, buflen);
       if (len < 0) return len;
       buflen -= len;
       pnt += len;
    }
    return 0;
}
int sock_fullwrite ( nsocket *  sock,
const char *  data,
size_t  length 
)

Definition at line 426 of file socket.c.

{
    ssize_t wrote;

#ifdef ENABLE_SSL
    if (sock->ssl) {
       /* joe: ssl.h says SSL_MODE_ENABLE_PARTIAL_WRITE must 
        * be enabled to have SSL_write return < length... 
        * so, SSL_write should never return < length. */
       wrote = SSL_write(sock->ssl, data, length);
       if (wrote >= 0 && wrote < length) {
           DEBUG(DEBUG_SOCKET, "SSL_write returned less than length!\n");
           sock->error = ERROR_SSL_STRING;
           return SOCK_ERROR;
       }
    } else {
#endif
       const char *pnt = data;
       size_t sent = 0;

       while (sent < length) {
           wrote = NEON_WRITE(sock->fd, pnt, length-sent);
           if (wrote < 0) {
              if (errno == EINTR) {
                  continue;
              } else if (errno == EPIPE) {
                  return SOCK_CLOSED;
              } else {
                  sock->error = strerror(errno);
                  return SOCK_ERROR;
              }
           }
           sent += wrote;
           pnt += wrote;
#ifdef ENABLE_SSL
       }
#endif
    }
    return 0;
}
const char* sock_get_error ( nsocket *  sock)

Definition at line 864 of file socket.c.

{
    return sock->error;
}
int sock_get_fd ( nsocket *  sock)

Definition at line 737 of file socket.c.

{
    return sock->fd;
}
int sock_init ( void  )

Definition at line 185 of file socket.c.

{
#ifdef WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    
    wVersionRequested = MAKEWORD(2, 2);
    
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
       return -1;

#endif

#ifdef ENABLE_SSL
    SSL_load_error_strings();
    SSL_library_init();

    DEBUG(DEBUG_SOCKET, "Initialized SSL.\n");
#endif

    return 0;
}
int sock_make_secure ( nsocket *  sock,
nssl_context *  ctx 
)

Definition at line 810 of file socket.c.

{
#ifdef ENABLE_SSL
    int ret;
    SSL_CTX *ssl_ctx;

    if (ctx) {
       ssl_ctx = ctx->ctx;
    } else {
       ssl_ctx = sock->default_ctx;
    }

    sock->ssl = SSL_new(ssl_ctx);
    if (!sock->ssl) {
       sock->error = ERROR_SSL_STRING;
       /* Usually goes wrong because: */
       fprintf(stderr, "Have you called sock_init()!?\n");
       return SOCK_ERROR;
    }
    
    SSL_set_fd(sock->ssl, sock->fd);
    
    ret = SSL_connect(sock->ssl);
    if (ret == -1) {
       sock->error = ERROR_SSL_STRING;
       SSL_free(sock->ssl);
       sock->ssl = NULL;
       return SOCK_ERROR;
    }

#if 0
    /* Tommi Komulainen <Tommi.Komulainen@iki.fi> has donated his SSL
     * cert verification from the mutt IMAP/SSL code under the
     * LGPL... it will plug in here */
    ret = sock_check_certicate(sock);
    if (ret) {
       SSL_shutdown(sock->ssl);
       SSL_free(sock->ssl);
       sock->ssl = NULL;
       return ret;
    }
#endif

    if (notify_cb) (*notify_cb)(notify_ud, sock_secure_details, 
                              SSL_get_version(sock->ssl));
    DEBUG(DEBUG_SOCKET, "SSL connected: version %s\n", 
          SSL_get_version(sock->ssl));
    return 0;
#else
    sock->error = _("This application does not have SSL support.");
    return SOCK_ERROR;
#endif
}
int sock_name_lookup ( const char *  hostname,
struct in_addr *  addr 
)

Definition at line 642 of file socket.c.

{
    struct hostent *hp;
    unsigned long laddr;
    
    if (notify_cb)
       (*notify_cb)(notify_ud, sock_namelookup, hostname);
    
    /* TODO?: a possible problem here, is that if we are passed an
     * invalid IP address e.g. "500.500.500.500", then this gets
     * passed to gethostbyname and returned as "Host not found".
     * Arguably wrong, but maybe difficult to detect correctly what is
     * an invalid IP address and what is a hostname... can hostnames
     * begin with a numeric character? */
    laddr = (unsigned long)inet_addr(hostname);
    if ((int)laddr == -1) {
       /* inet_addr failed. */
       hp = gethostbyname(hostname);
       if (hp == NULL) {
#if 0
           /* Need to get this back somehow, but we don't have 
            * an nsocket * yet... */
           switch(h_errno) {
           case HOST_NOT_FOUND:
              sock->error = _("Host not found");
              break;
           case TRY_AGAIN:
              sock->error = _("Host not found (try again later?)");
              break;
           case NO_ADDRESS:
              sock->error = _("Host exists but has no address.");
              break;
           case NO_RECOVERY:
           default:
              sock->error = _("Non-recoverable error in resolver library.");
              break;
           }
#endif
           return SOCK_ERROR;
       }
       memcpy(addr, hp->h_addr, hp->h_length);
    } else {
       addr->s_addr = laddr;
    }
    return 0;
}
int sock_peek ( nsocket *  sock,
char *  buffer,
size_t  count 
)

Definition at line 278 of file socket.c.

{
    int ret;
    ret = sock_block(sock, SOCKET_READ_TIMEOUT);
    if (ret < 0) {
       return ret;
    }
    /* Got data */
#ifdef ENABLE_SSL
    if (sock->ssl) {
       ret = SSL_peek(sock->ssl, buffer, count);
       /* TODO: This is the fetchmail fix as in sock_readline.
        * Do we really need it? */
       if (ret == 0) {
           if (sock->ssl->shutdown) {
              return SOCK_CLOSED;
           }
           if (0 != ERR_get_error()) {
              sock->error = ERROR_SSL_STRING;
              return SOCK_ERROR;
           }
       }
    } else {
#endif
    do {
#ifndef BEOS_PRE_BONE
       ret = recv(sock->fd, buffer, count, MSG_PEEK);
#else /* we're on BeOS pre-BONE so we need to use the buffer... */
       if (sock->peeked_bytes_avail > 0) {
           /* we've got some from last time!!! */
           if (count >= sock->peeked_bytes_avail) {
              strncpy(buffer, sock->peeked_bytes_curpos, sock->peeked_bytes_avail);
              ret = sock->peeked_bytes_avail;
           } else {
              strncpy(buffer, sock->peeked_bytes_curpos, count);
              ret = count;
           }
       } else {
           if (count > MAX_PEEK_BUFFER)
              count = MAX_PEEK_BUFFER;
           ret = recv(sock->fd, buffer, count, 0);
           sock->peeked_bytes_avail = ret;
           strncpy(sock->peeked_bytes, buffer, ret);
           sock->peeked_bytes_curpos = sock->peeked_bytes;
       }
#endif
    } while (ret == -1 && errno == EINTR);
#ifdef ENABLE_SSL
    }
#endif
    /* According to the Single Unix Spec, recv() will return
     * zero if the socket has been closed the other end. */
    if (ret == 0) {
       ret = SOCK_CLOSED;
    } else if (ret < 0) {
       sock->error = strerror(errno);
       ret = SOCK_ERROR;
    } 
    return ret;
}
int sock_read ( nsocket *  sock,
char *  buffer,
size_t  count 
)

Definition at line 218 of file socket.c.

{
    int ret;

    if (count == 0) {
       DEBUG(DEBUG_SOCKET, "Passing 0 to sock_read is probably bad.\n");
       /* But follow normal read() semantics anyway... */
       return 0;
    }

    ret = sock_block(sock, SOCKET_READ_TIMEOUT);
    if (ret == 0) {
       /* Got data */
       do {
#ifdef ENABLE_SSL
           if (sock->ssl) {
              ret = SSL_read(sock->ssl, buffer, count);
           } else {
#endif
#ifndef BEOS_PRE_BONE
              ret = NEON_READ(sock->fd, buffer, count);
#else
              if (sock->peeked_bytes_avail > 0) {
                  /* simply return the peeked bytes.... */
                  if (count >= sock->peeked_bytes_avail){
                     /* we have room */
                     strncpy(buffer, sock->peeked_bytes_curpos, 
                            sock->peeked_bytes_avail);
                     ret = sock->peeked_bytes_avail;
                     sock->peeked_bytes_avail = 0;
                  } else {
                     strncpy(buffer, sock->peeked_bytes_curpos, count);
                     sock->peeked_bytes_curpos += count;
                     sock->peeked_bytes_avail -= count;
                     ret = count;
                  }
              } else {
                  ret = recv(sock->fd, buffer, count, 0);
              }
#endif
#ifdef ENABLE_SSL
           }
#endif
       } while (ret == -1 && errno == EINTR);
       if (ret < 0) {
           sock->error = strerror(errno);
           ret = SOCK_ERROR;
       } else if (ret == 0) {
           /* This might not or might not be an error depending on
               the context. */
           sock->error = _("Connection was closed by server");
           DEBUG(DEBUG_SOCKET, "read returned zero.\n");
           ret = SOCK_CLOSED;
       }
    }
    return ret;
}
int sock_readfile_blocked ( nsocket *  sock,
off_t  length,
sock_block_reader  reader,
void *  userdata 
)

Definition at line 401 of file socket.c.

{
    char buffer[BUFSIZ];
    int ret;
    off_t done = 0;
    do {
       ret = sock_read(sock, buffer, BUFSIZ);
       if (ret < 0) {
           if (length == -1 && ret == SOCK_CLOSED) {
              /* Not an error condition. */
              return 0;
           }
           return ret;
       } 
       done += ret;
       sock_call_progress(done, length);
       (*reader)(userdata, buffer, ret);
    } while ((length == -1) || (done < length));
    return 0;
}
int sock_readline ( nsocket *  sock,
char *  line,
int  len 
)

Definition at line 479 of file socket.c.

{
    char *newline, *bp = buf;
    int n;

    do {
       /* 
        * The reason for these gymnastics is that we want two things:
        * (1) to read \n-terminated lines,
        * (2) to return the true length of data read, even if the
        *     data coming in has embedded NULS.
        */
#ifdef ENABLE_SSL

       if (sock->ssl) {
           /* Hack alert! */
           /* OK...  SSL_peek works a little different from MSG_PEEK
              Problem is that SSL_peek can return 0 if there is no
              data currently available.  If, on the other hand, we
              loose the socket, we also get a zero, but the SSL_read
              then SEGFAULTS!  To deal with this, we'll check the
              error code any time we get a return of zero from
              SSL_peek.  If we have an error, we bail.  If we don't,
              we read one character in SSL_read and loop.  This
              should continue to work even if they later change the
              behavior of SSL_peek to "fix" this problem...  :-(*/
           DEBUG(DEBUG_SOCKET, "SSL readline... \n");
           if ((n = SSL_peek(sock->ssl, bp, len)) < 0) {
              sock->error = ERROR_SSL_STRING;
              return(-1);
           }
           if (0 == n) {
              /* SSL_peek says no data...  Does he mean no data
                 or did the connection blow up?  If we got an error
                 then bail! */
              DEBUG(DEBUG_SOCKET, "SSL_Peek says no data!\n");
              /* Check properly to see if the connection has closed */
              if (sock->ssl->shutdown) {
                  DEBUG(DEBUG_SOCKET, "SSL says shutdown.");
                  return SOCK_CLOSED;
              } else if (0 != (n = ERR_get_error())) {
                  DEBUG(DEBUG_SOCKET, "SSL error occured.\n");
                  sock->error = ERROR_SSL_STRING;
                  return -1;
              }
                  
              /* We didn't get an error so read at least one
                 character at this point and loop */
              n = 1;
              /* Make sure newline start out NULL!  We don't have a
               * string to pass through the strchr at this point yet
               * */
              newline = NULL;
           } else if ((newline = memchr(bp, '\n', n)) != NULL)
              n = newline - bp + 1;
           n = SSL_read(sock->ssl, bp, n);
           DEBUG(DEBUG_SOCKET, "SSL_read returned %d\n", n);
           if (n == -1) {
              sock->error = ERROR_SSL_STRING;
              return(-1);
           }
           /* Check for case where our single character turned out to
            * be a newline...  (It wasn't going to get caught by
            * the strchr above if it came from the hack...). */
           if (NULL == newline && 1 == n && '\n' == *bp) {
              /* Got our newline - this will break
                            out of the loop now */
              newline = bp;
           }
       } else {
#endif
           if ((n = sock_peek(sock, bp, len)) <= 0)
              return n;
           if ((newline = memchr(bp, '\n', n)) != NULL)
              n = newline - bp + 1;
           if ((n = sock_read(sock, bp, n)) < 0)
              return n;
#ifdef ENABLE_SSL
       }
#endif
       bp += n;
       len -= n;
       if (len < 1) {
           sock->error = _("Line too long");
           return SOCK_FULL;
       }
    } while (!newline && len);
    *bp = '\0';
    return bp - buf;
}
void sock_register_notify ( sock_notify  cb,
void *  userdata 
)

Definition at line 172 of file socket.c.

{
    notify_cb = cb;
    notify_ud = userdata;
}
void sock_register_progress ( sock_progress  cb,
void *  userdata 
)

Definition at line 166 of file socket.c.

{
    progress_cb = cb;
    progress_ud = userdata;
}
int sock_send_string ( nsocket *  sock,
const char *  string 
)

Definition at line 469 of file socket.c.

{
    return sock_fullwrite(sock, data, strlen(data));
}
int sock_sendline ( nsocket *  sock,
const char *  line 
)

Definition at line 391 of file socket.c.

{
    char *buffer;
    int ret;
    CONCAT2(buffer, line, "\r\n");
    ret = sock_send_string(sock, buffer);
    free(buffer);
    return ret;
}
int sock_service_lookup ( const char *  name)

Definition at line 919 of file socket.c.

                                          {
    struct servent *ent;
    ent = getservbyname(name, "tcp");
    if (ent == NULL) {
       return 0;
    } else {
       return ntohs(ent->s_port);
    }
}
void sock_set_cert_accept ( nssl_context *  c,
nssl_accept  accepter,
void *  userdata 
)
int sock_set_client_cert ( nssl_context *  ctx,
const char *  certfile,
const char *  keyfile 
)

Definition at line 885 of file socket.c.

{
#ifdef ENABLE_SSL
    if (SSL_CTX_use_certificate_file(ctx->ctx, cert, SSL_FILETYPE_PEM) <= 0) {
       DEBUG(DEBUG_SOCKET, "Could not load cert file.\n");
       return -1;
    }
    
    /* The cert file can contain the private key too, apparently. Not
     * sure under what circumstances this is sensible, but hey. */
    if (key == NULL)
       key = cert;
    
    /* Set this so the callback can tell the user what's going on. */
    ctx->key_file = key;
    
    if (SSL_CTX_use_PrivateKey_file(ctx->ctx, key, SSL_FILETYPE_PEM) <= 0) {
       DEBUG(DEBUG_SOCKET, "Could not load private key file.\n");
       return -1;
    }

    /* Sanity check. */
    if (!SSL_CTX_check_private_key(ctx->ctx)) {
       DEBUG(DEBUG_SOCKET, "Private key does not match certificate.\n");
       return -1;
    }

    return 0;
#else
    return -1;
#endif
}
void sock_set_key_prompt ( nssl_context *  c,
nssl_key_prompt  prompt,
void *  userdata 
)

Definition at line 807 of file socket.c.

{}
int sock_transfer ( int  fd,
nsocket *  sock,
off_t  readlen 
)

Definition at line 576 of file socket.c.

{
    char buffer[BUFSIZ];
    size_t curlen; /* total bytes yet to read from srcfd */
    off_t sumwrlen; /* total bytes written to destfd */

    if (readlen == -1) {
       curlen = BUFSIZ; /* so the buffer size test works */
    } else {
       curlen = readlen; /* everything to do */
    }
    sumwrlen = 0; /* nowt done yet */

    while (curlen > 0) {
       int rdlen, wrlen;

       /* Get a chunk... if the number of bytes that are left to read
        * is less than the buffer size, only read that many bytes. */
       rdlen = read(fd, buffer, (readlen==-1)?BUFSIZ:(min(BUFSIZ, curlen)));
       sock_call_progress(sumwrlen, readlen);
       if (rdlen < 0) { 
           if (errno == EPIPE) {
              return SOCK_CLOSED;
           } else {
              sock->error = strerror(errno);
              return SOCK_ERROR;
           }
       } else if (rdlen == 0) { 
           /* End of file... get out of here */
           break;
       }
       if (readlen != -1)
           curlen -= rdlen;

       /* Otherwise, we have bytes!  Write them to destfd */
       
       wrlen = sock_fullwrite(sock, buffer, rdlen);
       if (wrlen < 0) { 
           return wrlen;
       }

       sumwrlen += rdlen;
    }
    sock_call_progress(sumwrlen, readlen);
    return sumwrlen;
}

Here is the call graph for this function: