static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) { char *b = buf; size_t pos = 0; ssize_t res; ssh_pollfd_t pfd; socket_t fd = ssh_socket_get_fd_in(s); pfd.fd = fd; pfd.events = do_read ? POLLIN : POLLOUT; while (n > pos) { if (do_read) { res = read(fd, b + pos, n - pos); } else { res = write(fd, b + pos, n - pos); } switch (res) { case -1: if (errno == EINTR) { continue; } #ifdef EWOULDBLOCK if (errno == EAGAIN || errno == EWOULDBLOCK) { #else if (errno == EAGAIN) { #endif (void) ssh_poll(&pfd, 1, -1); continue; } return 0; case 0: errno = EPIPE; return pos; default: pos += (size_t) res; } } return pos; } ssh_agent agent_new(struct ssh_session_struct *session) { ssh_agent agent = NULL; agent = malloc(sizeof(struct ssh_agent_struct)); if (agent == NULL) { return NULL; } ZERO_STRUCTP(agent); agent->count = 0; agent->sock = ssh_socket_new(session); if (agent->sock == NULL) { SAFE_FREE(agent); return NULL; } return agent; }
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) { int rc; size_t i, used; ssh_poll_handle p; socket_t fd; int revents; struct ssh_timestamp ts; if (ctx->polls_used == 0) { return SSH_ERROR; } ssh_timestamp_init(&ts); do { int tm = ssh_timeout_update(&ts, timeout); rc = ssh_poll(ctx->pollfds, ctx->polls_used, tm); } while (rc == -1 && errno == EINTR); if (rc < 0) { return SSH_ERROR; } if (rc == 0) { return SSH_AGAIN; } used = ctx->polls_used; for (i = 0; i < used && rc > 0; ) { if (!ctx->pollfds[i].revents || ctx->pollptrs[i]->lock) { i++; } else { int ret; p = ctx->pollptrs[i]; fd = ctx->pollfds[i].fd; revents = ctx->pollfds[i].revents; /* avoid having any event caught during callback */ ctx->pollfds[i].events = 0; p->lock = 1; if (p->cb && (ret = p->cb(p, fd, revents, p->cb_data)) < 0) { if (ret == -2) { return -1; } /* the poll was removed, reload the used counter and start again */ used = ctx->polls_used; i = 0; } else { ctx->pollfds[i].revents = 0; ctx->pollfds[i].events = p->events; p->lock = 0; i++; } rc--; } } return rc; }
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) { int rc; int i, used; ssh_poll_handle p; socket_t fd; int revents; if (!ctx->polls_used) return SSH_ERROR; rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout); if(rc < 0) return SSH_ERROR; if (rc == 0) return SSH_AGAIN; used = ctx->polls_used; for (i = 0; i < used && rc > 0; ) { if (!ctx->pollfds[i].revents || ctx->pollptrs[i]->lock) { i++; } else { int ret; p = ctx->pollptrs[i]; fd = ctx->pollfds[i].fd; revents = ctx->pollfds[i].revents; /* avoid having any event caught during callback */ ctx->pollfds[i].events = 0; p->lock = 1; if (p->cb && (ret = p->cb(p, fd, revents, p->cb_data)) < 0) { if (ret == -2) { return -1; } /* the poll was removed, reload the used counter and start again */ used = ctx->polls_used; i=0; } else { ctx->pollfds[i].revents = 0; ctx->pollfds[i].events = p->events; p->lock = 0; i++; } rc--; } } return rc; }
static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int do_read) { char *b = buf; size_t pos = 0; ssize_t res; ssh_pollfd_t pfd; ssh_channel channel = agent->channel; socket_t fd; /* Using a socket ? */ if (channel == NULL) { fd = ssh_socket_get_fd_in(agent->sock); pfd.fd = fd; pfd.events = do_read ? POLLIN : POLLOUT; while (n > pos) { if (do_read) { res = read(fd, b + pos, n - pos); } else { res = write(fd, b + pos, n - pos); } switch (res) { case -1: if (errno == EINTR) { continue; } #ifdef EWOULDBLOCK if (errno == EAGAIN || errno == EWOULDBLOCK) { #else if (errno == EAGAIN) { #endif (void) ssh_poll(&pfd, 1, -1); continue; } return 0; case 0: /* read returns 0 on end-of-file */ errno = do_read ? 0 : EPIPE; return pos; default: pos += (size_t) res; } } return pos; } else { /* using an SSH channel */ while (n > pos){
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) { int rc; int i, used; ssh_poll_handle p; socket_t fd; int revents; if (!ctx->polls_used) return 0; rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout); if(rc < 0) rc=SSH_ERROR; if(rc <= 0) return rc; used = ctx->polls_used; for (i = 0; i < used && rc > 0; ) { if (!ctx->pollfds[i].revents) { i++; } else { p = ctx->pollptrs[i]; fd = ctx->pollfds[i].fd; revents = ctx->pollfds[i].revents; if (p->cb && p->cb(p, fd, revents, p->cb_data) < 0) { /* the poll was removed, reload the used counter and start again */ used = ctx->polls_used; i=0; } else { ctx->pollfds[i].revents = 0; i++; } rc--; } } return rc; }
static int ssh_connect_ai_timeout(ssh_session session, const char *host, int port, struct addrinfo *ai, long timeout, long usec, socket_t s) { int timeout_ms; ssh_pollfd_t fds; int rc = 0; int ret; socklen_t len = sizeof(rc); /* I know we're losing some precision. But it's not like poll-like family * type of mechanisms are precise up to the microsecond. */ timeout_ms=timeout * 1000 + usec / 1000; rc = ssh_socket_set_nonblocking(s); if (rc < 0) { ssh_set_error(session, SSH_FATAL, "Failed to set socket non-blocking for %s:%d", host, port); ssh_connect_socket_close(s); return -1; } SSH_LOG(SSH_LOG_RARE, "Trying to connect to host: %s:%d with " "timeout %d ms", host, port, timeout_ms); /* The return value is checked later */ connect(s, ai->ai_addr, ai->ai_addrlen); freeaddrinfo(ai); fds.fd=s; fds.revents=0; fds.events=POLLOUT; #ifdef _WIN32 fds.events |= POLLWRNORM; #endif rc = ssh_poll(&fds,1,timeout_ms); if (rc == 0) { /* timeout */ ssh_set_error(session, SSH_FATAL, "Timeout while connecting to %s:%d", host, port); ssh_connect_socket_close(s); return -1; } if (rc < 0) { ssh_set_error(session, SSH_FATAL, "poll error: %s", strerror(errno)); ssh_connect_socket_close(s); return -1; } rc = -1; /* Get connect(2) return code. Zero means no error */ ret = getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len); if (ret < 0 || rc != 0) { ssh_set_error(session, SSH_FATAL, "Connect to %s:%d failed: %s", host, port, strerror(rc)); ssh_connect_socket_close(s); return -1; } /* s is connected ? */ SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout\n"); ret = ssh_socket_set_blocking(s); if (ret < 0) { ssh_set_error(session, SSH_FATAL, "Failed to set socket as blocking connecting to %s:%d failed: %s", host, port, strerror(errno)); ssh_connect_socket_close(s); return -1; } return s; }