예제 #1
0
파일: ne_socket.c 프로젝트: dveeden/Prestan
/* SSL error handling, according to SSL_get_error(3). */
static int error_ossl(ne_socket *sock, int sret)
{
    int err = SSL_get_error(sock->ssl, sret), ret = NE_SOCK_ERROR;
    
    switch (err) {
    case SSL_ERROR_ZERO_RETURN:
	ret = NE_SOCK_CLOSED;
	set_error(sock, _("Connection closed"));
	break;
    case SSL_ERROR_SYSCALL:
	err = ERR_get_error();
	if (err == 0) {
	    if (sret == 0) {
		/* EOF without close_notify, possible truncation */
		set_error(sock, _("Secure connection truncated"));
		ret = NE_SOCK_TRUNC;
	    } else {
		/* Other socket error. */
		err = ne_errno;
		set_strerror(sock, err);
		ret = MAP_ERR(err);
	    }
	} else {
	    ne_snprintf(sock->error, sizeof sock->error, 
			_("SSL error: %s"), ERR_reason_error_string(err));
	}
	break;
    default:
	ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"), 
		    ERR_reason_error_string(ERR_get_error()));
	break;
    }
    return ret;
}
예제 #2
0
/* Connect socket to address 'addr' on given 'port'.  Returns zero on
 * success or NE_SOCK_* on failure with sock->error set
 * appropriately. */
static int connect_socket(ne_socket *sock, int fd,
                          const ne_inet_addr *addr, unsigned int port)
{
#ifdef USE_GETADDRINFO
#ifdef AF_INET6
    /* fill in the _family field for AIX 4.3, which forgets to do so. */
    if (addr->ai_family == AF_INET6) {
	struct sockaddr_in6 in6;
	memcpy(&in6, addr->ai_addr, sizeof in6);
	in6.sin6_port = port;
        in6.sin6_family = AF_INET6;
        return timed_connect(sock, fd, (struct sockaddr *)&in6, sizeof in6);
    } else
#endif
    if (addr->ai_family == AF_INET) {
	struct sockaddr_in in;
	memcpy(&in, addr->ai_addr, sizeof in);
	in.sin_port = port;
        in.sin_family = AF_INET;
        return timed_connect(sock, fd, (struct sockaddr *)&in, sizeof in);
    } else {
        set_strerror(sock, EINVAL);
        return NE_SOCK_ERROR;
    }
#else
    struct sockaddr_in sa = {0};
    sa.sin_family = AF_INET;
    sa.sin_port = port;
    sa.sin_addr = *addr;
    return timed_connect(sock, fd, (struct sockaddr *)&sa, sizeof sa);
#endif
}
예제 #3
0
/* Await data on raw fd in socket. */
static int readable_raw(ne_socket *sock, int secs)
{
    int ret = raw_poll(sock->fd, 0, secs);

    if (ret < 0) {
	set_strerror(sock, ne_errno);
	return NE_SOCK_ERROR;
    }
    return (ret == 0) ? NE_SOCK_TIMEOUT : 0;
}
예제 #4
0
ne_inet_addr *ne_sock_peer(ne_socket *sock, unsigned int *port)
{
    union saun {
        struct sockaddr sa;
        struct sockaddr_in sin;
#if defined(USE_GETADDRINFO) && defined(AF_INET6)
        struct sockaddr_in6 sin6;
#endif
    } saun;
    socklen_t len = sizeof saun;
    ne_inet_addr *ia;
    struct sockaddr *sad = (struct sockaddr *)&saun;

    if (getpeername(sock->fd, sad, &len) != 0) {
        set_strerror(sock, errno);
        return NULL;
    }

#if !defined(USE_GETADDRINFO) || !defined(AF_INET6)
    if (sad->sa_family != AF_INET) {
        set_error(sock, _("Socket family not supported"));
        return NULL;
    }
#endif                  

    ia = ne_calloc(sizeof *ia);
#ifdef USE_GETADDRINFO
    ia->ai_addr = ne_malloc(sizeof *ia);
    ia->ai_addrlen = len;
    memcpy(ia->ai_addr, sad, len);
    ia->ai_family = saun.sa.sa_family;
#else
    memcpy(ia, &saun.sin.sin_addr.s_addr, sizeof *ia);
#endif    

#if defined(USE_GETADDRINFO) && defined(AF_INET6)
    *port = ntohs(saun.sa.sa_family == AF_INET ? 
                  saun.sin.sin_port : saun.sin6.sin6_port);
#else
    *port = ntohs(saun.sin.sin_port);
#endif

    return ia;
}
예제 #5
0
파일: ne_socket.c 프로젝트: dveeden/Prestan
static ssize_t write_raw(ne_socket *sock, const char *data, size_t length) 
{
    ssize_t wrote;
    
    do {
	wrote = ne_write(sock->fd, data, length);
        if (wrote > 0) {
            data += wrote;
            length -= wrote;
        }
    } while ((wrote > 0 || NE_ISINTR(ne_errno)) && length > 0);

    if (wrote < 0) {
	int errnum = ne_errno;
	set_strerror(sock, errnum);
	return MAP_ERR(errnum);
    }

    return 0;
}
예제 #6
0
static ssize_t write_raw(ne_socket *sock, const char *data, size_t length) 
{
    ssize_t ret;
    
#ifdef __QNX__
    /* Test failures seen on QNX over loopback, if passing large
     * buffer lengths to send().  */
    if (length > 8192) length = 8192;
#endif

    do {
	ret = send(sock->fd, data, length, 0);
    } while (ret == -1 && NE_ISINTR(ne_errno));

    if (ret < 0) {
	int errnum = ne_errno;
	set_strerror(sock, errnum);
	return MAP_ERR(errnum);
    }
    return ret;
}
예제 #7
0
static ssize_t read_raw(ne_socket *sock, char *buffer, size_t len)
{
    ssize_t ret;
    
    ret = readable_raw(sock, sock->rdtimeout);
    if (ret) return ret;

    do {
	ret = recv(sock->fd, buffer, len, 0);
    } while (ret == -1 && NE_ISINTR(ne_errno));

    if (ret == 0) {
	set_error(sock, _("Connection closed"));
	ret = NE_SOCK_CLOSED;
    } else if (ret < 0) {
	int errnum = ne_errno;
	ret = NE_ISRESET(errnum) ? NE_SOCK_RESET : NE_SOCK_ERROR;
	set_strerror(sock, errnum);
    }

    return ret;
}
예제 #8
0
int ne_sock_connect(ne_socket *sock,
                    const ne_inet_addr *addr, unsigned int port)
{
    int fd, ret;

#ifdef USE_GETADDRINFO
    /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo
     * implementations do not set ai_socktype, e.g. RHL6.2. */
    fd = socket(addr->ai_family, SOCK_STREAM, addr->ai_protocol);
#else
    fd = socket(AF_INET, SOCK_STREAM, 0);
#endif
    if (fd < 0) {
        set_strerror(sock, ne_errno);
	return -1;
    }
    
#if !defined(NE_USE_POLL) && !defined(WIN32)
    if (fd > FD_SETSIZE) {
        ne_close(fd);
        set_error(sock, _("Socket descriptor number exceeds FD_SETSIZE"));
        return NE_SOCK_ERROR;
    }
#endif

#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP)
    { /* Disable the Nagle algorithm; better to add write buffering
       * instead of doing this. */
        int flag = 1;
        setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag);
    }
#endif
    
    ret = connect_socket(sock, fd, addr, htons(port));
    if (ret == 0)
        sock->fd = fd;

    return ret;
}
예제 #9
0
파일: ne_socket.c 프로젝트: dveeden/Prestan
/* Await data on raw fd in socket. */
static int readable_raw(ne_socket *sock, int secs)
{
    int fdno = sock->fd, ret;
    fd_set rdfds;
    struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);

    /* Init the fd set */
    FD_ZERO(&rdfds);
    do {
	FD_SET(fdno, &rdfds);
	if (tvp) {
	    tvp->tv_sec = secs;
	    tvp->tv_usec = 0;
	}
	ret = select(fdno + 1, &rdfds, NULL, NULL, tvp);
    } while (ret < 0 && NE_ISINTR(ne_errno));
    if (ret < 0) {
	set_strerror(sock, ne_errno);
	return NE_SOCK_ERROR;
    }
    return (ret == 0) ? NE_SOCK_TIMEOUT : 0;
}
예제 #10
0
/* SSL error handling, according to SSL_get_error(3). */
static int error_ossl(ne_socket *sock, int sret)
{
    int errnum = SSL_get_error(sock->ssl, sret);
    unsigned long err;

    if (errnum == SSL_ERROR_ZERO_RETURN) {
	set_error(sock, _("Connection closed"));
        return NE_SOCK_CLOSED;
    }
    
    /* for all other errors, look at the OpenSSL error stack */
    err = ERR_get_error();
    if (err == 0) {
        /* Empty error stack, presume this is a system call error: */
        if (sret == 0) {
            /* EOF without close_notify, possible truncation */
            set_error(sock, _("Secure connection truncated"));
            return NE_SOCK_TRUNC;
        } else {
            /* Other socket error. */
            errnum = ne_errno;
            set_strerror(sock, errnum);
            return MAP_ERR(errnum);
        }
    }

    if (ERR_reason_error_string(err)) {
        ne_snprintf(sock->error, sizeof sock->error, 
                    _("SSL error: %s"), ERR_reason_error_string(err));
    } else {
	ne_snprintf(sock->error, sizeof sock->error, 
                    _("SSL error code %d/%d/%lu"), sret, errnum, err);
    }
    
    /* make sure the error stack is now empty. */
    ERR_clear_error();
    return NE_SOCK_ERROR;
}
예제 #11
0
/* Perform a connect() for fd to address sa of length salen, with a
 * timeout if supported on this platform.  Returns zero on success or
 * NE_SOCK_* on failure, with sock->error set appropriately. */
static int timed_connect(ne_socket *sock, int fd,
                         const struct sockaddr *sa, size_t salen)
{
    int ret;

#ifdef USE_NONBLOCKING_CONNECT
    if (sock->cotimeout) {
        int errnum, flags;

        /* Get flags and then set O_NONBLOCK. */
        flags = fcntl(fd, F_GETFL);
        if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
            set_strerror(sock, errno);
            return NE_SOCK_ERROR;
        }
        
        ret = connect(fd, sa, salen);
        if (ret == -1) {
            errnum = ne_errno;
            if (NE_ISINPROGRESS(errnum)) {
                ret = raw_poll(fd, 1, sock->cotimeout);
                if (ret > 0) { /* poll got data */
                    socklen_t len = sizeof(errnum);
                    
                    /* Check whether there is a pending error for the
                     * socket.  Per Stevens UNPv1§15.4, Solaris will
                     * return a pending error via errno by failing the
                     * getsockopt() call. */

                    errnum = 0;
                    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errnum, &len))
                        errnum = errno;
                    
                    if (errnum == 0) {
                        ret = 0;
                    } else {
                        set_strerror(sock, errnum);
                        ret = NE_SOCK_ERROR;
                    }
                } else if (ret == 0) { /* poll timed out */
                    set_error(sock, _("Connection timed out"));
                    ret = NE_SOCK_TIMEOUT;
                } else /* poll failed */ {
                    set_strerror(sock, errno);
                    ret = NE_SOCK_ERROR;
                }
            } else /* non-EINPROGRESS error from connect() */ { 
                set_strerror(sock, errnum);
                ret = NE_SOCK_ERROR;
            }
        }
        
        /* Reset to old flags: */
        if (fcntl(fd, F_SETFL, flags) == -1) {
            set_strerror(sock, errno);
            ret = NE_SOCK_ERROR;
        }       
    } else 
#endif /* USE_NONBLOCKING_CONNECT */
    {
        ret = connect(fd, sa, salen);
        
        if (ret < 0) {
            set_strerror(sock, errno);
            ret = NE_SOCK_ERROR;
        }
    }

    return ret;
}
예제 #12
0
int ne_sock_connect(ne_socket *sock,
                    const ne_inet_addr *addr, unsigned int port)
{
    int fd, ret;
    int type = SOCK_STREAM | sock_cloexec;

#if defined(RETRY_ON_EINVAL) && defined(SOCK_NONBLOCK) \
    && defined(USE_NONBLOCKING_CONNECT)
    /* If the SOCK_NONBLOCK flag is defined, and the retry-on-EINVAL
     * logic is enabled, and the socket has a configured timeout, then
     * also use the SOCK_NONBLOCK flag to save enabling O_NONBLOCK
     * later. */
    if (sock->cotimeout && sock_cloexec) {
        type |= SOCK_NONBLOCK;
    }
#endif

    /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo
     * implementations do not set ai_socktype, e.g. RHL6.2. */
    fd = socket(ia_family(addr), type, ia_proto(addr));
#ifdef RETRY_ON_EINVAL
    /* Handle forwards compat for new glibc on an older kernels; clear
     * the sock_cloexec flag and retry the call: */
    if (fd < 0 && sock_cloexec && errno == EINVAL) {
        sock_cloexec = 0;
        fd = socket(ia_family(addr), SOCK_STREAM, ia_proto(addr));
    }
#endif
    if (fd < 0) {
        set_strerror(sock, ne_errno);
	return -1;
    }
    
#if !defined(NE_USE_POLL) && !defined(WIN32)
    if (fd > FD_SETSIZE) {
        ne_close(fd);
        set_error(sock, _("Socket descriptor number exceeds FD_SETSIZE"));
        return NE_SOCK_ERROR;
    }
#endif
   
#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) \
  && defined(FD_CLOEXEC)
    /* Set the FD_CLOEXEC bit for the new fd, if the socket was not
     * created with the CLOEXEC bit already set. */
    if (!sock_cloexec && (ret = fcntl(fd, F_GETFD)) >= 0) {
        fcntl(fd, F_SETFD, ret | FD_CLOEXEC);
        /* ignore failure; not a critical error. */
    }
#endif

    if (sock->laddr && (sock->laddr == &dummy_laddr || 
                        ia_family(sock->laddr) == ia_family(addr))) {
        ret = do_bind(fd, ia_family(addr), sock->laddr, sock->lport);
        if (ret < 0) {
            int errnum = errno;
            ne_close(fd);
            set_strerror(sock, errnum);
            return NE_SOCK_ERROR;
        }
    }

#if defined(HAVE_SETSOCKOPT) && (defined(TCP_NODELAY) || defined(WIN32))
    { /* Disable the Nagle algorithm. */
        int flag = 1;
        setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag);
    }
#endif
    
    ret = connect_socket(sock, fd, addr, htons(port));
    if (ret == 0)
        sock->fd = fd;
    else
        ne_close(fd);

    return ret;
}