/* 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; }
/* 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 }
/* 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; }
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; }
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; }
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; }
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; }
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; }
/* 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; }
/* 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; }
/* 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; }
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; }