예제 #1
0
/* {{{ libssh2_packet_requirev
 * Loops libssh2_packet_read() until one of a list of packet types requested is available
 * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
 * packet_types is a null terminated list of packet_type numbers
 */
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len,
														 unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len)
{
	if (libssh2_packet_askv_ex(session, packet_types, data, data_len, match_ofs, match_buf, match_len, 0) == 0) {
		/* One of the packets listed was available in the packet brigade */
		return 0;
	}

	while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
		int ret = libssh2_packet_read(session, 1);
		if (ret < 0) {
			return -1;
		}
		if (ret == 0) {
			continue;
		}

		if (strchr(packet_types, ret)) {
			/* Be lazy, let packet_ask pull it out of the brigade */
			return libssh2_packet_askv_ex(session, packet_types, data, data_len, match_ofs, match_buf, match_len, 0);
		}
	}

	/* Only reached if the socket died */
	return -1;
}
예제 #2
0
/* {{{ libssh2_packet_require
 * Loops libssh2_packet_read() until the packet requested is available
 * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
 */
int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len,
														unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len)
{
	if (libssh2_packet_ask_ex(session, packet_type, data, data_len, match_ofs, match_buf, match_len, 0) == 0) {
		/* A packet was available in the packet brigade */
		return 0;
	}

#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet of type %d becomes available", (int)packet_type);
#endif
	while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
		int ret = libssh2_packet_read(session, 1);
		if (ret < 0) {
			return -1;
		}
		if (ret == 0) continue;

		if (packet_type == ret) {
			/* Be lazy, let packet_ask pull it out of the brigade */
			return libssh2_packet_ask_ex(session, packet_type, data, data_len, match_ofs, match_buf, match_len, 0);
		}
	}

	/* Only reached if the socket died */
	return -1;
}
예제 #3
0
/* {{{ libssh2_packet_ask
 * Scan the brigade for a matching packet type, optionally poll the socket for
 * a packet first
 */
int
libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
                      unsigned char **data, unsigned long *data_len,
                      unsigned long match_ofs, const unsigned char *match_buf,
                      unsigned long match_len, int poll_socket)
{
    LIBSSH2_PACKET *packet = session->packets.head;

    if (poll_socket) {
        /*
         * XXX CHECK ***
         * When "poll_socket" is "1" libhss2_packet_read() can return
         * PACKET_EAGAIN.  I am not sure what should happen, but internally
         * there is only one location that might do so, libssh2_packet_askv_ex()
         */
        libssh2pack_t rc = libssh2_packet_read(session);
        if ((rc < 0) && !packet) {
            return rc;
        }
    }
    _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                   "Looking for packet of type: %d", (int) packet_type);

    while (packet) {
        if (packet->data[0] == packet_type
            && (packet->data_len >= (match_ofs + match_len)) && (!match_buf
                                                                 ||
                                                                 (memcmp
                                                                  (packet->
                                                                   data +
                                                                   match_ofs,
                                                                   match_buf,
                                                                   match_len)
                                                                  == 0))) {
            *data = packet->data;
            *data_len = packet->data_len;

            if (packet->prev) {
                packet->prev->next = packet->next;
            } else {
                session->packets.head = packet->next;
            }

            if (packet->next) {
                packet->next->prev = packet->prev;
            } else {
                session->packets.tail = packet->prev;
            }

            LIBSSH2_FREE(session, packet);

            return 0;
        }
        packet = packet->next;
    }
    return -1;
}
예제 #4
0
/* {{{ libssh2_packet_require
 * Loops libssh2_packet_read() until the packet requested is available
 * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
 *
 * Returns negative on error
 * Returns 0 when it has taken care of the requested packet.
 */
int
libssh2_packet_require_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
                          unsigned char **data, unsigned long *data_len,
                          unsigned long match_ofs,
                          const unsigned char *match_buf,
                          unsigned long match_len,
                          packet_require_state_t * state)
{
    if (state->start == 0) {
        if (libssh2_packet_ask_ex
            (session, packet_type, data, data_len, match_ofs, match_buf,
             match_len, 0) == 0) {
            /* A packet was available in the packet brigade */
            return 0;
        }

        state->start = time(NULL);

        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "May block until packet of type %d becomes available",
                       (int) packet_type);
    }

    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
        libssh2pack_t ret = libssh2_packet_read(session);
        if (ret == PACKET_EAGAIN) {
            return PACKET_EAGAIN;
        } else if ((ret == 0) && (!session->socket_block)) {
            /* If we are in non-blocking and there is no data, return that */
            return PACKET_EAGAIN;
        } else if (ret < 0) {
            state->start = 0;
            /* an error which is not just because of blocking */
            return ret;
        } else if (ret == packet_type) {
            /* Be lazy, let packet_ask pull it out of the brigade */
            ret =
                libssh2_packet_ask_ex(session, packet_type, data, data_len,
                                      match_ofs, match_buf, match_len, 0);
            state->start = 0;
            return ret;
        } else if (ret == 0) {
            /* nothing available, wait until data arrives or we time out */
            long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);

            if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
                state->start = 0;
                return PACKET_TIMEOUT;
            }
        }
    }

    /* Only reached if the socket died */
    return -1;
}
예제 #5
0
/* {{{ libssh2_packet_burn
 * Loops libssh2_packet_read() until any packet is available and promptly 
 * discards it
 * Used during KEX exchange to discard badly guessed KEX_INIT packets
 */
int
libssh2_packet_burn(LIBSSH2_SESSION * session,
                    libssh2_nonblocking_states * state)
{
    unsigned char *data;
    unsigned long data_len;
    unsigned char all_packets[255];
    int i;
    int ret;

    if (*state == libssh2_NB_state_idle) {
        for(i = 1; i < 256; i++) {
            all_packets[i - 1] = i;
        }

        if (libssh2_packet_askv_ex
            (session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
            i = data[0];
            /* A packet was available in the packet brigade, burn it */
            LIBSSH2_FREE(session, data);
            return i;
        }

        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "Blocking until packet becomes available to burn");
        *state = libssh2_NB_state_created;
    }

    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
        if ((ret = libssh2_packet_read(session)) == PACKET_EAGAIN) {
            return PACKET_EAGAIN;
        } else if (ret < 0) {
            *state = libssh2_NB_state_idle;
            return ret;
        } else if (ret == 0) {
            /* FIXME: this might busyloop */
            continue;
        }

        /* Be lazy, let packet_ask pull it out of the brigade */
        if (0 ==
            libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0,
                                  0)) {
            /* Smoke 'em if you got 'em */
            LIBSSH2_FREE(session, data);
            *state = libssh2_NB_state_idle;
            return ret;
        }
    }

    /* Only reached if the socket died */
    return -1;
}
예제 #6
0
int
libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
                           const unsigned char *packet_types,
                           unsigned char **data, unsigned long *data_len,
                           unsigned long match_ofs,
                           const unsigned char *match_buf,
                           unsigned long match_len,
                           packet_requirev_state_t * state)
{
    if (libssh2_packet_askv_ex
        (session, packet_types, data, data_len, match_ofs, match_buf,
         match_len, 0) == 0) {
        /* One of the packets listed was available in the packet
           brigade */
        state->start = 0;
        return 0;
    }

    if (state->start == 0) {
        state->start = time(NULL);
    }

    while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
        int ret = libssh2_packet_read(session);
        if ((ret < 0) && (ret != PACKET_EAGAIN)) {
            state->start = 0;
            return ret;
        }
        if (ret <= 0) {
            long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);

            if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
                state->start = 0;
                return PACKET_TIMEOUT;
            } else if (ret == PACKET_EAGAIN) {
                return PACKET_EAGAIN;
            }
        }

        if (strchr((char *) packet_types, ret)) {
            /* Be lazy, let packet_ask pull it out of the brigade */
            return libssh2_packet_askv_ex(session, packet_types, data,
                                          data_len, match_ofs, match_buf,
                                          match_len, 0);
        }
    }

    /* Only reached if the socket died */
    state->start = 0;
    return -1;
}
예제 #7
0
/* {{{ libssh2_packet_ask
 * Scan the brigade for a matching packet type, optionally poll the socket for a packet first
 */
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len,
													unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket)
{
	LIBSSH2_PACKET *packet = session->packets.head;

	if (poll_socket) {
		if (libssh2_packet_read(session, 0) < 0) {
			return -1;
		}
	}
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Looking for packet of type: %d", (int)packet_type);
#endif
	while (packet) {
		if (packet->data[0] == packet_type &&
			(packet->data_len >= (match_ofs + match_len)) &&
			(!match_buf || (memcmp(packet->data + match_ofs, match_buf, match_len) == 0))) {
			*data = packet->data;
			*data_len = packet->data_len;

			if (packet->prev) {
				packet->prev->next = packet->next;
			} else {
				session->packets.head = packet->next;
			}

			if (packet->next) {
				packet->next->prev = packet->prev;
			} else {
				session->packets.tail = packet->prev;
			}

			LIBSSH2_FREE(session, packet);

			return 0;
		}
		packet = packet->next;
	}
	return -1;
}
예제 #8
0
/* {{{ libssh2_packet_burn
 * Loops libssh2_packet_read() until any packet is available and promptly discards it
 * Used during KEX exchange to discard badly guessed KEX_INIT packets
 */
int libssh2_packet_burn(LIBSSH2_SESSION *session)
{
	unsigned char *data;
	unsigned long data_len;
	char all_packets[255];
	int i;
	for(i = 1; i < 256; i++) all_packets[i - 1] = i;

	if (libssh2_packet_askv_ex(session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
		i = data[0];
		/* A packet was available in the packet brigade, burn it */
		LIBSSH2_FREE(session, data);
		return i;
	}

#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet becomes available to burn");
#endif
	while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
		int ret = libssh2_packet_read(session, 1);
		if (ret < 0) {
			return -1;
		}
		if (ret == 0) continue;

		/* Be lazy, let packet_ask pull it out of the brigade */
		if (0 == libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0, 0)) {
			/* Smoke 'em if you got 'em */
			LIBSSH2_FREE(session, data);
			return ret;
		}
	}

	/* Only reached if the socket died */
	return -1;
}
예제 #9
0
파일: session.c 프로젝트: roderico/linm
/* {{{ libssh2_poll
 * Poll sockets, channels, and listeners for activity
 */
LIBSSH2_API int
libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
{
    long timeout_remaining;
    unsigned int i, active_fds;
#ifdef HAVE_POLL
    LIBSSH2_SESSION *session = NULL;
#ifdef HAVE_ALLOCA
    struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds);
#else
    struct pollfd sockets[256];

    if (nfds > 256)
        /* systems without alloca use a fixed-size array, this can be fixed
           if we really want to, at least if the compiler is a C99 capable one */
        return -1;
#endif
    /* Setup sockets for polling */
    for(i = 0; i < nfds; i++) {
        fds[i].revents = 0;
        switch (fds[i].type) {
        case LIBSSH2_POLLFD_SOCKET:
            sockets[i].fd = fds[i].fd.socket;
            sockets[i].events = fds[i].events;
            sockets[i].revents = 0;
            break;

        case LIBSSH2_POLLFD_CHANNEL:
            sockets[i].fd = fds[i].fd.channel->session->socket_fd;
            sockets[i].events = POLLIN;
            sockets[i].revents = 0;
            if (!session)
                session = fds[i].fd.channel->session;
            break;

        case LIBSSH2_POLLFD_LISTENER:
            sockets[i].fd = fds[i].fd.listener->session->socket_fd;
            sockets[i].events = POLLIN;
            sockets[i].revents = 0;
            if (!session)
                session = fds[i].fd.listener->session;
            break;

        default:
            if (session)
                libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
                              "Invalid descriptor passed to libssh2_poll()",
                              0);
            return -1;
        }
    }
#elif defined(HAVE_SELECT)
    LIBSSH2_SESSION *session = NULL;
    int maxfd = 0;
    fd_set rfds, wfds;
    struct timeval tv;

    FD_ZERO(&rfds);
    FD_ZERO(&wfds);
    for(i = 0; i < nfds; i++) {
        fds[i].revents = 0;
        switch (fds[i].type) {
        case LIBSSH2_POLLFD_SOCKET:
            if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
                FD_SET(fds[i].fd.socket, &rfds);
                if (fds[i].fd.socket > maxfd)
                    maxfd = fds[i].fd.socket;
            }
            if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
                FD_SET(fds[i].fd.socket, &wfds);
                if (fds[i].fd.socket > maxfd)
                    maxfd = fds[i].fd.socket;
            }
            break;

        case LIBSSH2_POLLFD_CHANNEL:
            FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
            if (fds[i].fd.channel->session->socket_fd > maxfd)
                maxfd = fds[i].fd.channel->session->socket_fd;
            if (!session)
                session = fds[i].fd.channel->session;
            break;

        case LIBSSH2_POLLFD_LISTENER:
            FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
            if (fds[i].fd.listener->session->socket_fd > maxfd)
                maxfd = fds[i].fd.listener->session->socket_fd;
            if (!session)
                session = fds[i].fd.listener->session;
            break;

        default:
            if (session)
                libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
                              "Invalid descriptor passed to libssh2_poll()",
                              0);
            return -1;
        }
    }
#else
    /* No select() or poll()
     * no sockets sturcture to setup
     */

    timeout = 0;
#endif /* HAVE_POLL or HAVE_SELECT */

    timeout_remaining = timeout;
    do {
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
        int sysret;
#endif

        active_fds = 0;

        for(i = 0; i < nfds; i++) {
            if (fds[i].events != fds[i].revents) {
                switch (fds[i].type) {
                case LIBSSH2_POLLFD_CHANNEL:
                    if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) &&      /* Want to be ready for read */
                        ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) {      /* Not yet known to be ready for read */
                        fds[i].revents |=
                            libssh2_poll_channel_read(fds[i].fd.channel,
                                                      0) ?
                            LIBSSH2_POLLFD_POLLIN : 0;
                    }
                    if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) &&     /* Want to be ready for extended read */
                        ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) {     /* Not yet known to be ready for extended read */
                        fds[i].revents |=
                            libssh2_poll_channel_read(fds[i].fd.channel,
                                                      1) ?
                            LIBSSH2_POLLFD_POLLEXT : 0;
                    }
                    if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) &&     /* Want to be ready for write */
                        ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) {     /* Not yet known to be ready for write */
                        fds[i].revents |=
                            libssh2_poll_channel_write(fds[i].fd.
                                                       channel) ?
                            LIBSSH2_POLLFD_POLLOUT : 0;
                    }
                    if (fds[i].fd.channel->remote.close
                        || fds[i].fd.channel->local.close) {
                        fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
                    }
                    if (fds[i].fd.channel->session->socket_state ==
                        LIBSSH2_SOCKET_DISCONNECTED) {
                        fds[i].revents |=
                            LIBSSH2_POLLFD_CHANNEL_CLOSED |
                            LIBSSH2_POLLFD_SESSION_CLOSED;
                    }
                    break;

                case LIBSSH2_POLLFD_LISTENER:
                    if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) &&      /* Want a connection */
                        ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) {      /* No connections known of yet */
                        fds[i].revents |=
                            libssh2_poll_listener_queued(fds[i].fd.
                                                         listener) ?
                            LIBSSH2_POLLFD_POLLIN : 0;
                    }
                    if (fds[i].fd.listener->session->socket_state ==
                        LIBSSH2_SOCKET_DISCONNECTED) {
                        fds[i].revents |=
                            LIBSSH2_POLLFD_LISTENER_CLOSED |
                            LIBSSH2_POLLFD_SESSION_CLOSED;
                    }
                    break;
                }
            }
            if (fds[i].revents) {
                active_fds++;
            }
        }

        if (active_fds) {
            /* Don't block on the sockets if we have channels/listeners which are ready */
            timeout_remaining = 0;
        }
#ifdef HAVE_POLL

#ifdef HAVE_GETTIMEOFDAY
        {
            struct timeval tv_begin, tv_end;

            gettimeofday((struct timeval *) &tv_begin, NULL);
            sysret = poll(sockets, nfds, timeout_remaining);
            gettimeofday((struct timeval *) &tv_end, NULL);
            timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
            timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
        }
#else
        /* If the platform doesn't support gettimeofday,
         * then just make the call non-blocking and walk away
         */
        sysret = poll(sockets, nfds, timeout_remaining);
        timeout_remaining = 0;
#endif /* HAVE_GETTIMEOFDAY */

        if (sysret > 0) {
            for(i = 0; i < nfds; i++) {
                switch (fds[i].type) {
                case LIBSSH2_POLLFD_SOCKET:
                    fds[i].revents = sockets[i].revents;
                    sockets[i].revents = 0;     /* In case we loop again, be nice */
                    if (fds[i].revents) {
                        active_fds++;
                    }
                    break;
                case LIBSSH2_POLLFD_CHANNEL:
                    if (sockets[i].events & POLLIN) {
                        /* Spin session until no data available */
                        while (libssh2_packet_read(fds[i].fd.channel->session)
                               > 0);
                    }
                    if (sockets[i].revents & POLLHUP) {
                        fds[i].revents |=
                            LIBSSH2_POLLFD_CHANNEL_CLOSED |
                            LIBSSH2_POLLFD_SESSION_CLOSED;
                    }
                    sockets[i].revents = 0;
                    break;
                case LIBSSH2_POLLFD_LISTENER:
                    if (sockets[i].events & POLLIN) {
                        /* Spin session until no data available */
                        while (libssh2_packet_read(fds[i].fd.listener->session)
                               > 0);
                    }
                    if (sockets[i].revents & POLLHUP) {
                        fds[i].revents |=
                            LIBSSH2_POLLFD_LISTENER_CLOSED |
                            LIBSSH2_POLLFD_SESSION_CLOSED;
                    }
                    sockets[i].revents = 0;
                    break;
                }
            }
        }
#elif defined(HAVE_SELECT)
        tv.tv_sec = timeout_remaining / 1000;
        tv.tv_usec = (timeout_remaining % 1000) * 1000;
#ifdef HAVE_GETTIMEOFDAY
        {
            struct timeval tv_begin, tv_end;

            gettimeofday((struct timeval *) &tv_begin, NULL);
            sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
            gettimeofday((struct timeval *) &tv_end, NULL);

            timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
            timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
        }
#else
        /* If the platform doesn't support gettimeofday,
         * then just make the call non-blocking and walk away
         */
        sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
        timeout_remaining = 0;
#endif

        if (sysret > 0) {
            for(i = 0; i < nfds; i++) {
                switch (fds[i].type) {
                case LIBSSH2_POLLFD_SOCKET:
                    if (FD_ISSET(fds[i].fd.socket, &rfds)) {
                        fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
                    }
                    if (FD_ISSET(fds[i].fd.socket, &wfds)) {
                        fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
                    }
                    if (fds[i].revents) {
                        active_fds++;
                    }
                    break;

                case LIBSSH2_POLLFD_CHANNEL:
                    if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
                        /* Spin session until no data available */
                        while (libssh2_packet_read(fds[i].fd.channel->session)
                               > 0);
                    }
                    break;

                case LIBSSH2_POLLFD_LISTENER:
                    if (FD_ISSET
                        (fds[i].fd.listener->session->socket_fd, &rfds)) {
                        /* Spin session until no data available */
                        while (libssh2_packet_read(fds[i].fd.listener->session)
                               > 0);
                    }
                    break;
                }
            }
        }
#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
    } while ((timeout_remaining > 0) && !active_fds);

    return active_fds;
}