void set_nonblock(SOCKET fd, unsigned long nonblock) { #if defined F_GETFL && defined F_SETFL && defined O_NONBLOCK && !defined __INNOTEK_LIBC__ int err, flags; do { flags=fcntl(fd, F_GETFL, 0); } while(flags<0 && get_last_socket_error()==S_EINTR); if(flags<0) { sockerror("fcntl GETFL"); /* non-critical */ return; } if(nonblock) flags|=O_NONBLOCK; else flags&=~O_NONBLOCK; do { err=fcntl(fd, F_SETFL, flags); } while(err<0 && get_last_socket_error()==S_EINTR); if(err<0) sockerror("fcntl SETFL"); /* non-critical */ #else /* WIN32 or similar */ if(ioctlsocket(fd, (long)FIONBIO, &nonblock)<0) sockerror("ioctlsocket"); /* non-critical */ #if 0 else s_log(LOG_DEBUG, "Socket %d set to %s mode", fd, nonblock ? "non-blocking" : "blocking"); #endif #endif }
static void init_local(CLI * c) { SOCKADDR_UNION addr; socklen_t addr_len; char *accepted_address; addr_len = sizeof(SOCKADDR_UNION); c->local_rfd.is_socket = !getpeername(c->local_rfd.fd, &addr.sa, &addr_len); if (c->local_rfd.is_socket) { memcpy(&c->peer_addr.sa, &addr.sa, addr_len); c->peer_addr_len = addr_len; if (set_socket_options(c->local_rfd.fd, 1)) s_log(LOG_WARNING, "Failed to set local socket options"); } else { if (get_last_socket_error() != S_ENOTSOCK) { sockerror("getpeerbyname (local_rfd)"); longjmp(c->err, 1); } } if (c->local_rfd.fd == c->local_wfd.fd) { c->local_wfd.is_socket = c->local_rfd.is_socket; } else { addr_len = sizeof(SOCKADDR_UNION); c->local_wfd.is_socket = !getpeername(c->local_wfd.fd, &addr.sa, &addr_len); if (c->local_wfd.is_socket) { if (!c->local_rfd.is_socket) { memcpy(&c->peer_addr.sa, &addr.sa, addr_len); c->peer_addr_len = addr_len; } if (set_socket_options(c->local_wfd.fd, 1)) s_log(LOG_WARNING, "Failed to set local socket options"); } else { if (get_last_socket_error() != S_ENOTSOCK) { sockerror("getpeerbyname (local_wfd)"); longjmp(c->err, 1); } } } if (!c->local_rfd.is_socket && !c->local_rfd.is_socket) { s_log(LOG_NOTICE, "Service [%s] accepted connection", c->opt->servname); return; } accepted_address = s_ntop(&c->peer_addr, c->peer_addr_len); auth_user(c, accepted_address); s_log(LOG_NOTICE, "Service [%s] accepted connection from %s", c->opt->servname, accepted_address); str_free(accepted_address); }
int make_sockets(SOCKET fd[2]) { /* make a pair of connected ipv4 sockets */ #ifdef INET_SOCKET_PAIR struct sockaddr_in addr; socklen_t addrlen; SOCKET s; /* temporary socket awaiting for connection */ /* create two *blocking* sockets first */ s=s_socket(AF_INET, SOCK_STREAM, 0, 0, "make_sockets: s_socket#1"); if(s==INVALID_SOCKET) return 1; fd[1]=s_socket(AF_INET, SOCK_STREAM, 0, 0, "make_sockets: s_socket#2"); if(fd[1]==INVALID_SOCKET) { closesocket(s); return 1; } addrlen=sizeof addr; memset(&addr, 0, sizeof addr); addr.sin_family=AF_INET; addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK); addr.sin_port=htons(0); /* dynamic port allocation */ if(bind(s, (struct sockaddr *)&addr, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "make_sockets: bind#1"); if(bind(fd[1], (struct sockaddr *)&addr, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "make_sockets: bind#2"); if(listen(s, 1)) { sockerror("make_sockets: listen"); closesocket(s); closesocket(fd[1]); return 1; } if(getsockname(s, (struct sockaddr *)&addr, &addrlen)) { sockerror("make_sockets: getsockname"); closesocket(s); closesocket(fd[1]); return 1; } if(connect(fd[1], (struct sockaddr *)&addr, addrlen)) { sockerror("make_sockets: connect"); closesocket(s); closesocket(fd[1]); return 1; } fd[0]=s_accept(s, (struct sockaddr *)&addr, &addrlen, 1, "make_sockets: s_accept"); if(fd[0]==INVALID_SOCKET) { closesocket(s); closesocket(fd[1]); return 1; } closesocket(s); /* don't care about the result */ set_nonblock(fd[0], 1); set_nonblock(fd[1], 1); #else if(s_socketpair(AF_UNIX, SOCK_STREAM, 0, fd, 1, "make_sockets: socketpair")) return 1; #endif return 0; }
int s_connect(CLI *c, SOCKADDR_UNION *addr, socklen_t addrlen) { int error; char *dst; dst=s_ntop(addr, addrlen); s_log(LOG_INFO, "s_connect: connecting %s", dst); if(!connect(c->fd, &addr->sa, addrlen)) { s_log(LOG_NOTICE, "s_connect: connected %s", dst); str_free(dst); return 0; /* no error -> success (on some OSes over the loopback) */ } error=get_last_socket_error(); if(error!=S_EINPROGRESS && error!=S_EWOULDBLOCK) { s_log(LOG_ERR, "s_connect: connect %s: %s (%d)", dst, s_strerror(error), error); str_free(dst); return -1; } s_log(LOG_DEBUG, "s_connect: s_poll_wait %s: waiting %d seconds", dst, c->opt->timeout_connect); s_poll_init(c->fds); s_poll_add(c->fds, c->fd, 1, 1); switch(s_poll_wait(c->fds, c->opt->timeout_connect, 0)) { case -1: error=get_last_socket_error(); s_log(LOG_ERR, "s_connect: s_poll_wait %s: %s (%d)", dst, s_strerror(error), error); str_free(dst); return -1; case 0: s_log(LOG_ERR, "s_connect: s_poll_wait %s:" " TIMEOUTconnect exceeded", dst); str_free(dst); return -1; default: error=get_socket_error(c->fd); if(error) { s_log(LOG_ERR, "s_connect: connect %s: %s (%d)", dst, s_strerror(error), error); str_free(dst); return -1; } if(s_poll_canwrite(c->fds, c->fd)) { s_log(LOG_NOTICE, "s_connect: connected %s", dst); str_free(dst); return 0; /* success */ } s_log(LOG_ERR, "s_connect: s_poll_wait %s: internal error", dst); str_free(dst); return -1; } return -1; /* should not be possible */ }
static void make_sockets(CLI *c, int fd[2]) { /* make a pair of connected sockets */ #ifdef INET_SOCKET_PAIR SOCKADDR_UNION addr; socklen_t addrlen; int s; /* temporary socket awaiting for connection */ s=s_socket(AF_INET, SOCK_STREAM, 0, 1, "socket#1"); if(s<0) longjmp(c->err, 1); c->fd=s_socket(AF_INET, SOCK_STREAM, 0, 1, "socket#2"); if(c->fd<0) longjmp(c->err, 1); addrlen=sizeof addr; memset(&addr, 0, addrlen); addr.in.sin_family=AF_INET; addr.in.sin_addr.s_addr=htonl(INADDR_LOOPBACK); addr.in.sin_port=htons(0); /* dynamic port allocation */ if(bind(s, &addr.sa, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "bind#1"); if(bind(c->fd, &addr.sa, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "bind#2"); if(listen(s, 1)) { closesocket(s); sockerror("listen"); longjmp(c->err, 1); } if(getsockname(s, &addr.sa, &addrlen)) { closesocket(s); sockerror("getsockname"); longjmp(c->err, 1); } if(connect_blocking(c, &addr, addr_len(addr))) { closesocket(s); longjmp(c->err, 1); } fd[0]=s_accept(s, &addr.sa, &addrlen, 1, "accept"); if(fd[0]<0) { closesocket(s); longjmp(c->err, 1); } fd[1]=c->fd; c->fd=-1; closesocket(s); /* don't care about the result */ #else if(s_socketpair(AF_UNIX, SOCK_STREAM, 0, fd, 1, "socketpair")) longjmp(c->err, 1); #endif }
static int make_sockets(int fd[2]) { /* make a pair of connected sockets */ #ifdef INET_SOCKET_PAIR SOCKADDR_UNION addr; socklen_t addrlen; int s; /* temporary socket awaiting for connection */ if((s=socket(AF_INET, SOCK_STREAM, 0))<0) { sockerror("socket#1"); return -1; } if((fd[1]=socket(AF_INET, SOCK_STREAM, 0))<0) { sockerror("socket#2"); return -1; } addrlen=sizeof(SOCKADDR_UNION); memset(&addr, 0, addrlen); addr.in.sin_family=AF_INET; addr.in.sin_addr.s_addr=htonl(INADDR_LOOPBACK); addr.in.sin_port=0; /* dynamic port allocation */ if(bind(s, &addr.sa, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "bind#1"); if(bind(fd[1], &addr.sa, addrlen)) log_error(LOG_DEBUG, get_last_socket_error(), "bind#2"); if(listen(s, 5)) { sockerror("listen"); return -1; } if(getsockname(s, &addr.sa, &addrlen)) { sockerror("getsockname"); return -1; } if(connect(fd[1], &addr.sa, addrlen)) { sockerror("connect"); return -1; } if((fd[0]=accept(s, &addr.sa, &addrlen))<0) { sockerror("accept"); return -1; } closesocket(s); /* don't care about the result */ #else if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) { sockerror("socketpair"); return -1; } #endif return 0; }
/* returns 0 on close and 1 on non-critical errors */ static int parse_socket_error(CLI *c, const char *text) { switch(get_last_socket_error()) { /* http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html */ case 0: /* close on read, or close on write on WIN32 */ #ifndef USE_WIN32 case EPIPE: /* close on write on Unix */ #endif case S_ECONNABORTED: s_log(LOG_INFO, "%s: Socket is closed", text); return 0; case S_EINTR: s_log(LOG_DEBUG, "%s: Interrupted by a signal: retrying", text); return 1; case S_EWOULDBLOCK: s_log(LOG_NOTICE, "%s: Would block: retrying", text); sleep(1); /* Microsoft bug KB177346 */ return 1; #if S_EAGAIN!=S_EWOULDBLOCK case S_EAGAIN: s_log(LOG_DEBUG, "%s: Temporary lack of resources: retrying", text); return 1; #endif default: sockerror(text); longjmp(c->err, 1); } }
int win32_ioctl(int i, unsigned int u, char *data) { u_long u_long_arg; int retval; if (!wsock_started) { Perl_croak_nocontext("ioctl implemented only on sockets"); /* NOTREACHED */ } /* mauke says using memcpy avoids alignment issues */ memcpy(&u_long_arg, data, sizeof u_long_arg); retval = ioctlsocket(TO_SOCKET(i), (long)u, &u_long_arg); memcpy(data, &u_long_arg, sizeof u_long_arg); if (retval == SOCKET_ERROR) { int err = get_last_socket_error(); if (err == ENOTSOCK) { Perl_croak_nocontext("ioctl implemented only on sockets"); /* NOTREACHED */ } errno = err; } return retval; }
int my_fclose (FILE *pf) { int osf; if (!wsock_started) /* No WinSock? */ return(fclose(pf)); /* Then not a socket. */ osf = TO_SOCKET(win32_fileno(pf));/* Get it now before it's gone! */ if (osf != -1) { int err; win32_fflush(pf); err = closesocket(osf); if (err == 0) { assert(_osfhnd(win32_fileno(pf)) == osf); /* catch a bad ioinfo struct def */ /* don't close freed handle */ _set_osfhnd(win32_fileno(pf), INVALID_HANDLE_VALUE); return fclose(pf); } else if (err == SOCKET_ERROR) { err = get_last_socket_error(); if (err != ENOTSOCK) { (void)fclose(pf); errno = err; return EOF; } } } return fclose(pf); }
static int print_socket_options(void) { int fd, len; SOCK_OPT *ptr; OPT_UNION val; char line[STRLEN]; fd=socket(AF_INET, SOCK_STREAM, 0); log_raw("Socket option defaults:"); log_raw(" %-16s%-10s%-10s%-10s%-10s", "Option", "Accept", "Local", "Remote", "OS default"); for(ptr=sock_opts; ptr->opt_str; ptr++) { /* display option name */ sprintf(line, " %-16s", ptr->opt_str); /* display stunnel default values */ print_option(line, ptr->opt_type, ptr->opt_val[0]); print_option(line, ptr->opt_type, ptr->opt_val[1]); print_option(line, ptr->opt_type, ptr->opt_val[2]); /* display OS default value */ len = sizeof(val); if(getsockopt(fd, ptr->opt_level, ptr->opt_name, (void *)&val, &len)) { if(get_last_socket_error()!=ENOPROTOOPT) { log_raw("%s", line); /* dump the name and assigned values */ sockerror("getsockopt"); return 0; /* FAILED */ } safeconcat(line, " -- "); /* write-only value */ } else print_option(line, ptr->opt_type, &val); log_raw("%s", line); } return 1; /* OK */ }
static void local_bind(CLI * c) { if (!c->bind_addr) return; if (ntohs(c->bind_addr->in.sin_port) >= 1024) { if (!bind(c->fd, &c->bind_addr->sa, addr_len(c->bind_addr))) { s_log(LOG_INFO, "local_bind succeeded on the original port"); return; } if (get_last_socket_error() != S_EADDRINUSE) { sockerror("local_bind (original port)"); longjmp(c->err, 1); } } c->bind_addr->in.sin_port = htons(0); if (!bind(c->fd, &c->bind_addr->sa, addr_len(c->bind_addr))) { s_log(LOG_INFO, "local_bind succeeded on an ephemeral port"); return; } sockerror("local_bind (ephemeral port)"); longjmp(c->err, 1); }
static int parse_socket_error(CLI * c, const char *text) { switch (get_last_socket_error()) { case 0: case EPIPE: case S_ECONNABORTED: s_log(LOG_INFO, "%s: Socket is closed", text); return 0; case S_EINTR: s_log(LOG_DEBUG, "%s: Interrupted by a signal: retrying", text); return 1; case S_EWOULDBLOCK: s_log(LOG_NOTICE, "%s: Would block: retrying", text); sleep(1); return 1; #if S_EAGAIN!=S_EWOULDBLOCK case S_EAGAIN: s_log(LOG_DEBUG, "%s: Temporary lack of resources: retrying", text); return 1; #endif default: sockerror(text); longjmp(c->err, 1); } }
void daemon_loop(void) { SERVICE_OPTIONS *opt; int temporary_lack_of_resources; while(1) { temporary_lack_of_resources=0; if(s_poll_wait(fds, -1, -1)>=0) { if(s_poll_canread(fds, signal_pipe[0])) if(signal_pipe_dispatch()) /* received SIGNAL_TERMINATE */ break; /* terminate daemon_loop */ for(opt=service_options.next; opt; opt=opt->next) if(opt->option.accept && s_poll_canread(fds, opt->fd)) if(accept_connection(opt)) temporary_lack_of_resources=1; } else { log_error(LOG_NOTICE, get_last_socket_error(), "daemon_loop: s_poll_wait"); temporary_lack_of_resources=1; } if(temporary_lack_of_resources) { s_log(LOG_NOTICE, "Accepting new connections suspended for 1 second"); sleep(1); /* to avoid log trashing */ } } }
int s_poll_wait(s_poll_set *fds, int timeout) { int retval, retry; struct timeval tv, *tv_ptr; do { /* skip "Interrupted system call" errors */ retry=0; memcpy(&fds->orfds, &fds->irfds, sizeof(fd_set)); memcpy(&fds->owfds, &fds->iwfds, sizeof(fd_set)); if(timeout<0) { /* infinite timeout */ tv_ptr=NULL; } else { tv.tv_sec=timeout; tv.tv_usec=0; tv_ptr=&tv; } retval=select(fds->max+1, &fds->orfds, &fds->owfds, NULL, tv_ptr); #ifndef USE_WIN32 if(timeout<0 && retval>0 && s_poll_canread(fds, signal_pipe[0])) { signal_pipe_empty(); /* no timeout -> main loop */ retry=1; } #endif } while(retry || (retval<0 && get_last_socket_error()==EINTR)); return retval; }
/*- * BIO_accept_ex - Accept new incoming connections * @sock: the listening socket * @addr: the BIO_ADDR to store the peer address in * @options: BIO socket options, applied on the accepted socket. * */ int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options) { socklen_t len; int accepted_sock; BIO_ADDR locaddr; BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_; len = sizeof(*addr); accepted_sock = accept(accept_sock, BIO_ADDR_sockaddr_noconst(addr), &len); if (accepted_sock == -1) { if (!BIO_sock_should_retry(accepted_sock)) { SYSerr(SYS_F_ACCEPT, get_last_socket_error()); BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR); } return INVALID_SOCKET; } if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) { closesocket(accepted_sock); return INVALID_SOCKET; } return accepted_sock; }
static int dgram_write(BIO *b, const char *in, int inl) { int ret; bio_dgram_data *data = (bio_dgram_data *)b->ptr; clear_socket_error(); if ( data->connected ) ret=writesocket(b->num,in,inl); else #if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) ret=sendto(b->num, (char *)in, inl, 0, &data->peer, sizeof(data->peer)); #else ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer)); #endif BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) { BIO_set_retry_write(b); data->_errno = get_last_socket_error(); #if 0 /* higher layers are responsible for querying MTU, if necessary */ if ( data->_errno == EMSGSIZE) /* retrieve the new MTU */ BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); #endif } } return(ret); }
int BIO_accept(int sock, char **ip_port) { BIO_ADDR res; int ret = -1; ret = BIO_accept_ex(sock, &res, 0); if (ret == (int)INVALID_SOCKET) { if (BIO_sock_should_retry(ret)) { ret = -2; goto end; } SYSerr(SYS_F_ACCEPT, get_last_socket_error()); BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); goto end; } if (ip_port != NULL) { char *host = BIO_ADDR_hostname_string(&res, 1); char *port = BIO_ADDR_service_string(&res, 1); *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2); strcpy(*ip_port, host); strcat(*ip_port, ":"); strcat(*ip_port, port); OPENSSL_free(host); OPENSSL_free(port); } end: return ret; }
int BIO_fd_should_retry(int i) #endif { int err; if ((i == 0) || (i == -1)) { #ifndef BIO_FD err=get_last_socket_error(); #else err=get_last_sys_error(); #endif #if defined(WINDOWS) && 0 /* more microsoft stupidity? perhaps not? Ben 4/1/99 */ if ((i == -1) && (err == 0)) return(1); #endif #ifndef BIO_FD return(BIO_sock_non_fatal_error(err)); #else return(BIO_fd_non_fatal_error(err)); #endif } return(0); }
static int dgram_read(BIO *b, char *out, int outl) { int ret=0; bio_dgram_data *data = (bio_dgram_data *)b->ptr; struct sockaddr peer; int peerlen = sizeof(peer); if (out != NULL) { clear_socket_error(); memset(&peer, 0x00, peerlen); /* Last arg in recvfrom is signed on some platforms and * unsigned on others. It is of type socklen_t on some * but this is not universal. Cast to (void *) to avoid * compiler warnings. */ ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen); if ( ! data->connected && ret > 0) BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_dgram_should_retry(ret)) { BIO_set_retry_read(b); data->_errno = get_last_socket_error(); } } } return(ret); }
int BIO_sock_info(int sock, enum BIO_sock_info_type type, union BIO_sock_info_u *info) { switch (type) { case BIO_SOCK_INFO_ADDRESS: { socklen_t addr_len; int ret = 0; addr_len = sizeof(*info->addr); ret = getsockname(sock, BIO_ADDR_sockaddr_noconst(info->addr), &addr_len); if (ret == -1) { SYSerr(SYS_F_GETSOCKNAME, get_last_socket_error()); BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_ERROR); return 0; } if ((size_t)addr_len > sizeof(*info->addr)) { BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS); return 0; } } break; default: BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_UNKNOWN_INFO_TYPE); return 0; } return 1; }
/*- * addr_strings - helper function to get host and service names * @ap: the BIO_ADDR that has the input info * @numeric: 0 if actual names should be returned, 1 if the numeric * representation should be returned. * @hostname: a pointer to a pointer to a memory area to store the * host name or numeric representation. Unused if NULL. * @service: a pointer to a pointer to a memory area to store the * service name or numeric representation. Unused if NULL. * * The return value is 0 on failure, with the error code in the error * stack, and 1 on success. */ static int addr_strings(const BIO_ADDR *ap, int numeric, char **hostname, char **service) { if (BIO_sock_init() != 1) return 0; if (1) { #ifdef AI_PASSIVE int ret = 0; char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = ""; int flags = 0; if (numeric) flags |= NI_NUMERICHOST | NI_NUMERICSERV; if ((ret = getnameinfo(BIO_ADDR_sockaddr(ap), BIO_ADDR_sockaddr_size(ap), host, sizeof(host), serv, sizeof(serv), flags)) != 0) { # ifdef EAI_SYSTEM if (ret == EAI_SYSTEM) { SYSerr(SYS_F_GETNAMEINFO, get_last_socket_error()); BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); } else # endif { BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); ERR_add_error_data(1, gai_strerror(ret)); } return 0; } /* VMS getnameinfo() has a bug, it doesn't fill in serv, which * leaves it with whatever garbage that happens to be there. * However, we initialise serv with the empty string (serv[0] * is therefore NUL), so it gets real easy to detect when things * didn't go the way one might expect. */ if (serv[0] == '\0') { BIO_snprintf(serv, sizeof(serv), "%d", ntohs(BIO_ADDR_rawport(ap))); } if (hostname) *hostname = OPENSSL_strdup(host); if (service) *service = OPENSSL_strdup(serv); } else { #endif if (hostname) *hostname = OPENSSL_strdup(inet_ntoa(ap->s_in.sin_addr)); if (service) { char serv[6]; /* port is 16 bits => max 5 decimal digits */ BIO_snprintf(serv, sizeof(serv), "%d", ntohs(ap->s_in.sin_port)); *service = OPENSSL_strdup(serv); } } return 1; }
static int connect_remote(CLI *c) { /* connect to remote host */ SOCKADDR_UNION bind_addr, addr; SOCKADDR_LIST resolved_list, *address_list; int error; int s; /* destination socket */ u16 i; /* setup address_list */ if(c->opt->option.delayed_lookup) { resolved_list.num=0; if(!name2addrlist(&resolved_list, c->opt->remote_address, DEFAULT_LOOPBACK)) return -1; /* no host resolved */ address_list=&resolved_list; } else /* use pre-resolved addresses */ address_list=&c->opt->remote_addr; /* try to connect each host from the list */ for(i=0; i<address_list->num; i++) { memcpy(&addr, address_list->addr + address_list->cur, sizeof(SOCKADDR_UNION)); address_list->cur=(address_list->cur+1)%address_list->num; /* race condition is possible, but harmless in this case */ if((s=socket(addr.sa.sa_family, SOCK_STREAM, 0))<0) { sockerror("remote socket"); return -1; } if(alloc_fd(s)) return -1; if(c->bind_addr.num) { /* explicit local bind or transparent proxy */ memcpy(&bind_addr, &c->bind_addr.addr[0], sizeof(SOCKADDR_UNION)); if(bind(s, &bind_addr.sa, addr_len(bind_addr))<0) { sockerror("bind transparent"); closesocket(s); return -1; } } /* try to connect for the 1st time */ s_ntop(c->connecting_address, &addr); s_log(LOG_DEBUG, "%s connecting %s", c->opt->servname, c->connecting_address); if(!connect(s, &addr.sa, addr_len(addr))) return s; /* no error -> success (should not be possible) */ error=get_last_socket_error(); if(error!=EINPROGRESS && error!=EWOULDBLOCK) { s_log(LOG_ERR, "remote connect (%s): %s (%d)", c->connecting_address, my_strerror(error), error); closesocket(s); continue; /* next IP */ } if(!connect_wait(c, s, c->opt->timeout_connect)) return s; /* success! */ closesocket(s); /* error -> next IP */ } return -1; }
NOEXPORT int get_socket_error(const int fd) { int err; socklen_t optlen=sizeof err; if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &optlen)) err=get_last_socket_error(); /* failed -> ask why */ return err==S_ENOTSOCK ? 0 : err; }
int s_poll_wait(s_poll_set *fds, int sec, int msec) { int retval; do { /* skip "Interrupted system call" errors */ retval=poll(fds->ufds, fds->nfds, sec<0 ? -1 : 1000*sec+msec); } while(retval<0 && get_last_socket_error()==S_EINTR); return retval; }
static void reset(int fd, char *txt) { /* set lingering on a socket */ struct linger l; l.l_onoff=1; l.l_linger=0; if(setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&l, sizeof l)) log_error(LOG_DEBUG, get_last_socket_error(), txt); }
int BIO_get_port(const char *str, unsigned short *port_ptr) { int i; struct servent *s; if (str == NULL) { BIOerr(BIO_F_BIO_GET_PORT,BIO_R_NO_PORT_DEFINED); return(0); } i=atoi(str); if (i != 0) *port_ptr=(unsigned short)i; else { CRYPTO_w_lock(CRYPTO_LOCK_GETSERVBYNAME); /* Note: under VMS with SOCKETSHR, it seems like the first * parameter is 'char *', instead of 'const char *' */ s=getservbyname( #ifndef CONST_STRICT (char *) #endif str,"tcp"); if(s != NULL) *port_ptr=ntohs((unsigned short)s->s_port); CRYPTO_w_unlock(CRYPTO_LOCK_GETSERVBYNAME); if(s == NULL) { if (strcmp(str,"http") == 0) *port_ptr=80; else if (strcmp(str,"telnet") == 0) *port_ptr=23; else if (strcmp(str,"socks") == 0) *port_ptr=1080; else if (strcmp(str,"https") == 0) *port_ptr=443; else if (strcmp(str,"ssl") == 0) *port_ptr=443; else if (strcmp(str,"ftp") == 0) *port_ptr=21; else if (strcmp(str,"gopher") == 0) *port_ptr=70; #if 0 else if (strcmp(str,"wais") == 0) *port_ptr=21; #endif else { SYSerr(SYS_F_GETSERVBYNAME,get_last_socket_error()); ERR_add_error_data(3,"service='",str,"'"); return(0); } } } return(1); }
static int auth_user(CLI *c) { struct servent *s_ent; /* structure for getservbyname */ SOCKADDR_UNION ident; /* IDENT socket name */ int fd; /* IDENT socket descriptor */ char name[STRLEN]; int retval; int error; if(!c->opt->username) return 0; /* -u option not specified */ if((fd=socket(c->peer_addr.addr[0].sa.sa_family, SOCK_STREAM, 0))<0) { sockerror("socket (auth_user)"); return -1; } if(alloc_fd(fd)) return -1; memcpy(&ident, &c->peer_addr.addr[0], sizeof(SOCKADDR_UNION)); s_ent=getservbyname("auth", "tcp"); if(s_ent) { ident.in.sin_port=s_ent->s_port; } else { s_log(LOG_WARNING, "Unknown service 'auth': using default 113"); ident.in.sin_port=htons(113); } if(connect(fd, &ident.sa, addr_len(ident))) { error=get_last_socket_error(); if(error!=EINPROGRESS && error!=EWOULDBLOCK) { sockerror("ident connect (auth_user)"); closesocket(fd); return -1; } if(connect_wait(c, fd, c->opt->timeout_connect)) { /* error */ closesocket(fd); return -1; } } s_log(LOG_DEBUG, "IDENT server connected"); if(fdprintf(c, fd, "%u , %u", ntohs(c->peer_addr.addr[0].in.sin_port), ntohs(c->opt->local_addr.addr[0].in.sin_port))<0) { sockerror("fdprintf (auth_user)"); closesocket(fd); return -1; } if(fdscanf(c, fd, "%*[^:]: USERID :%*[^:]:%s", name)!=1) { s_log(LOG_ERR, "Incorrect data from IDENT server"); closesocket(fd); return -1; } closesocket(fd); retval=strcmp(name, c->opt->username) ? -1 : 0; safestring(name); s_log(LOG_INFO, "IDENT resolved remote user to %s", name); return retval; }
int BIO_sock_should_retry(int i) { int err; if ((i == 0) || (i == -1)) { err = get_last_socket_error(); return (BIO_sock_non_fatal_error(err)); } return (0); }
static int dgram_read(BIO *b, char *out, int outl) { int ret=0; bio_dgram_data *data = (bio_dgram_data *)b->ptr; struct { /* * See commentary in b_sock.c. <appro> */ union { size_t s; int i; } len; union { struct TINYCLR_SSL_SOCKADDR sa; struct TINYCLR_SSL_SOCKADDR_IN sa_in; #if OPENSSL_USE_IPV6 struct sockaddr_in6 sa_in6; #endif } peer; } sa; sa.len.s=0; sa.len.i=sizeof(sa.peer); if (out != NULL) { clear_socket_error(); TINYCLR_SSL_MEMSET(&sa.peer, 0x00, sizeof(sa.peer)); dgram_adjust_rcv_timeout(b); #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_ARM) || defined(OPENSSL_SYS_SH) ret=TINYCLR_SSL_RECVFROM(b->num,out,outl,0,&sa.peer.sa,(int *)&sa.len); #else ret=TINYCLR_SSL_RECVFROM(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len); #endif if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0) { OPENSSL_assert(sa.len.s<=sizeof(sa.peer)); sa.len.i = (int)sa.len.s; } dgram_reset_rcv_timeout(b); if ( ! data->connected && ret >= 0) BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); BIO_clear_retry_flags(b); if (ret < 0) { if (BIO_dgram_should_retry(ret)) { BIO_set_retry_read(b); data->_errno = get_last_socket_error(); } } } return(ret); }
/*- * BIO_connect - connect to an address * @sock: the socket to connect with * @addr: the address to connect to * @options: BIO socket options * * Connects to the address using the given socket and options. * * Options can be a combination of the following: * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. * - BIO_SOCK_NODELAY: don't delay small messages. * * options holds BIO socket options that can be used * You should call this for every address returned by BIO_lookup * until the connection is successful. * * Returns 1 on success or 0 on failure. On failure errno is set * and an error status is added to the OpenSSL error stack. */ int BIO_connect(int sock, const BIO_ADDR *addr, int options) { const int on = 1; if (sock == -1) { BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET); return 0; } if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) return 0; if (options & BIO_SOCK_KEEPALIVE) { if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const void *)&on, sizeof(on)) != 0) { SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE); return 0; } } if (options & BIO_SOCK_NODELAY) { if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const void *)&on, sizeof(on)) != 0) { SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY); return 0; } } if (connect(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) == -1) { if (!BIO_sock_should_retry(-1)) { SYSerr(SYS_F_CONNECT, get_last_socket_error()); BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR); } return 0; } return 1; }