Пример #1
0
/*
 * Process at least one key in the buffer and invoke tty->key_callback. Return
 * 0 if there are no further keys, or 1 if there could be more in the buffer.
 */
key_code
tty_keys_next(struct tty *tty)
{
	struct tty_key		*tk;
	struct timeval		 tv;
	const char		*buf;
	size_t			 len, size;
	cc_t			 bspace;
	int			 delay, expired = 0;
	key_code		 key;
	struct utf8_data	 ud;
	enum utf8_state		 more;
	u_int			 i;

	/* Get key buffer. */
	buf = EVBUFFER_DATA(tty->event->input);
	len = EVBUFFER_LENGTH(tty->event->input);

	if (len == 0)
		return (0);
	log_debug("keys are %zu (%.*s)", len, (int) len, buf);

	/* Is this a mouse key press? */
	switch (tty_keys_mouse(tty, buf, len, &size)) {
	case 0:		/* yes */
		key = KEYC_MOUSE;
		goto complete_key;
	case -1:	/* no, or not valid */
		break;
	case -2:	/* yes, but we don't care. */
		key = KEYC_MOUSE;
		goto discard_key;
	case 1:		/* partial */
		goto partial_key;
	}

	/* Look for matching key string and return if found. */
	tk = tty_keys_find(tty, buf, len, &size);
	if (tk != NULL) {
		if (tk->next != NULL)
			goto partial_key;
		key = tk->key;
		goto complete_key;
	}

	/* Try to parse a key with an xterm-style modifier. */
	switch (xterm_keys_find(buf, len, &size, &key)) {
	case 0:		/* found */
		goto complete_key;
	case -1:	/* not found */
		break;
	case 1:
		goto partial_key;
	}

first_key:
	/* Is this a meta key? */
	if (len >= 2 && buf[0] == '\033') {
		if (buf[1] != '\033') {
			key = buf[1] | KEYC_ESCAPE;
			size = 2;
			goto complete_key;
		}

		tk = tty_keys_find(tty, buf + 1, len - 1, &size);
		if (tk != NULL && (!expired || tk->next == NULL)) {
			size++;	/* include escape */
			if (tk->next != NULL)
				goto partial_key;
			key = tk->key;
			if (key != KEYC_UNKNOWN)
				key |= KEYC_ESCAPE;
			goto complete_key;
		}
	}

	/* Is this valid UTF-8? */
	if ((more = utf8_open(&ud, (u_char)*buf) == UTF8_MORE)) {
		size = ud.size;
		if (len < size) {
			if (expired)
				goto discard_key;
			goto partial_key;
		}
		for (i = 1; i < size; i++)
			more = utf8_append(&ud, (u_char)buf[i]);
		if (more != UTF8_DONE)
			goto discard_key;
		key = utf8_combine(&ud);
		log_debug("UTF-8 key %.*s %#llx", (int)size, buf, key);
		goto complete_key;
	}

	/* No key found, take first. */
	key = (u_char)*buf;
	size = 1;

	/*
	 * Check for backspace key using termios VERASE - the terminfo
	 * kbs entry is extremely unreliable, so cannot be safely
	 * used. termios should have a better idea.
	 */
	bspace = tty->tio.c_cc[VERASE];
	if (bspace != _POSIX_VDISABLE && key == bspace)
		key = KEYC_BSPACE;

	goto complete_key;

partial_key:
	log_debug("partial key %.*s", (int) len, buf);

	/* If timer is going, check for expiration. */
	if (tty->flags & TTY_TIMER) {
		if (evtimer_initialized(&tty->key_timer) &&
		    !evtimer_pending(&tty->key_timer, NULL)) {
			expired = 1;
			goto first_key;
		}
		return (0);
	}

	/* Get the time period. */
	delay = options_get_number(global_options, "escape-time");
	tv.tv_sec = delay / 1000;
	tv.tv_usec = (delay % 1000) * 1000L;

	/* Start the timer. */
	if (event_initialized(&tty->key_timer))
		evtimer_del(&tty->key_timer);
	evtimer_set(&tty->key_timer, tty_keys_callback, tty);
	evtimer_add(&tty->key_timer, &tv);

	tty->flags |= TTY_TIMER;
	return (0);

complete_key:
	log_debug("complete key %.*s %#llx", (int)size, buf, key);

	/* Remove data from buffer. */
	evbuffer_drain(tty->event->input, size);

	/* Remove key timer. */
	if (event_initialized(&tty->key_timer))
		evtimer_del(&tty->key_timer);
	tty->flags &= ~TTY_TIMER;

	/* Check for focus events. */
	if (key == KEYC_FOCUS_OUT) {
		tty->client->flags &= ~CLIENT_FOCUSED;
		return (1);
	} else if (key == KEYC_FOCUS_IN) {
		tty->client->flags |= CLIENT_FOCUSED;
		return (1);
	}

	/* Fire the key. */
	if (key != KEYC_UNKNOWN)
		server_client_handle_key(tty->client, key);

	return (1);

discard_key:
	log_debug("discard key %.*s %#llx", (int)size, buf, key);

	/* Remove data from buffer. */
	evbuffer_drain(tty->event->input, size);

	return (1);
}
Пример #2
0
/*
 * Process at least one key in the buffer and invoke tty->key_callback. Return
 * 0 if there are no further keys, or 1 if there could be more in the buffer.
 */
int
tty_keys_next(struct tty *tty)
{
	struct tty_key		*tk;
	struct timeval		 tv;
	struct mouse_event	 mouse;
	const char		*buf;
	size_t			 len, size;
	cc_t			 bspace;
	int			 key, delay;

	buf = EVBUFFER_DATA(tty->event->input);
	len = EVBUFFER_LENGTH(tty->event->input);
	if (len == 0)
		return (0);
	log_debug("keys are %zu (%.*s)", len, (int) len, buf);

	/* If a normal key, return it. */
	if (*buf != '\033') {
		key = (u_char) *buf;
		evbuffer_drain(tty->event->input, 1);

		/*
		 * Check for backspace key using termios VERASE - the terminfo
		 * kbs entry is extremely unreliable, so cannot be safely
		 * used. termios should have a better idea.
		 */
		bspace = tty->tio.c_cc[VERASE];
		if (bspace != _POSIX_VDISABLE && key == bspace)
			key = KEYC_BSPACE;
		goto handle_key;
	}

	/* Is this a mouse key press? */
	switch (tty_keys_mouse(buf, len, &size, &mouse)) {
	case 0:		/* yes */
		evbuffer_drain(tty->event->input, size);
		key = KEYC_MOUSE;
		goto handle_key;
	case -1:	/* no, or not valid */
		break;
	case 1:		/* partial */
		goto partial_key;
	}

	/* Try to parse a key with an xterm-style modifier. */
	switch (xterm_keys_find(buf, len, &size, &key)) {
	case 0:		/* found */
		evbuffer_drain(tty->event->input, size);
		goto handle_key;
	case -1:	/* not found */
		break;
	case 1:
		goto partial_key;
	}

	/* Look for matching key string and return if found. */
	tk = tty_keys_find(tty, buf + 1, len - 1, &size);
	if (tk != NULL) {
		key = tk->key;
		goto found_key;
	}

	/* Skip the escape. */
	buf++;
	len--;

	/* Is there a normal key following? */
	if (len != 0 && *buf != '\033') {
		key = *buf | KEYC_ESCAPE;
		evbuffer_drain(tty->event->input, 2);
		goto handle_key;
	}

	/* Or a key string? */
	if (len > 1) {
		tk = tty_keys_find(tty, buf + 1, len - 1, &size);
		if (tk != NULL) {
			key = tk->key | KEYC_ESCAPE;
			size++;	/* include escape */
			goto found_key;
		}
	}

	/* Escape and then nothing useful - fall through. */

partial_key:
	/*
	 * Escape but no key string. If have already seen an escape, then the
	 * timer must have expired, so give up waiting and send the escape.
	 */
	if (tty->flags & TTY_ESCAPE) {
		evbuffer_drain(tty->event->input, 1);
		key = '\033';
		goto handle_key;
	}

	/* Fall through to start the timer. */

start_timer:
	/* Start the timer and wait for expiry or more data. */
	delay = options_get_number(&global_options, "escape-time");
	tv.tv_sec = delay / 1000;
	tv.tv_usec = (delay % 1000) * 1000L;

	evtimer_del(&tty->key_timer);
	evtimer_set(&tty->key_timer, tty_keys_callback, tty);
	evtimer_add(&tty->key_timer, &tv);

	tty->flags |= TTY_ESCAPE;
	return (0);

found_key:
	if (tk->next != NULL) {
		/* Partial key. Start the timer if not already expired. */
		if (!(tty->flags & TTY_ESCAPE))
			goto start_timer;

		/* Otherwise, if no key, send the escape alone. */
		if (tk->key == KEYC_NONE)
			goto partial_key;

		/* Or fall through to send the partial key found. */
	}
	evbuffer_drain(tty->event->input, size + 1);

	goto handle_key;

handle_key:
	evtimer_del(&tty->key_timer);

	tty->key_callback(key, &mouse, tty->key_data);

	tty->flags &= ~TTY_ESCAPE;
	return (1);
}
Пример #3
0
static void
socks_read_cb(struct bufferevent *bev, void *ptr)
{
	obfsproxyssh_client_session_t *session = ptr;
	obfsproxyssh_t *state = session->client->state;
	struct evbuffer *buf;
	struct sockaddr_in addr;
	unsigned char *p, *userid;
	size_t len;
	int i;

	assert(bev == session->socks_ev);

	buf = bufferevent_get_input(bev);
	len = evbuffer_get_length(buf);
	if (len < SOCKS_4_CONNECT_REQUEST_LEN)
		return;

	p = evbuffer_pullup(buf, len);
	if (NULL == p) {
		log_f(state, "SOCKS: Error: %s Failed to pullup (OOM?)",
				bdata(session->socks_addr));
		goto out_free;
	}

	/*
	 * Parse the SOCKS 4 CONNECT
	 *
	 * uint8_4  VN  -> 4
	 * uint8_t  CN	-> 1
	 * uint16_t DSTPORT
	 * uint32_t DSTIP
	 * uint8_t  USERID[] (Tor PT arguments)
	 * uint8_t  NULL -> 0
	 */

	if (SOCKS_4_VER != p[0]) {
		log_f(state, "SOCKS: Error: %s Invalid SOCKS protocol version %d",
				bdata(session->socks_addr),
				p[0]);
		goto out_free;
	}

	if (SOCKS_4_CMD_CONNECT != p[1]) {
		log_f(state, "SOCKS: Error: %s Invalid SOCKS 4 command %d",
				bdata(session->socks_addr),
				p[1]);
		goto out_free;
	}

	userid = p + SOCKS_4_CONNECT_REQUEST_LEN;
	for (i = 0; i < len - SOCKS_4_CONNECT_REQUEST_LEN; i++) {
		if ('\0' == userid[i]) {
			if (len != SOCKS_4_CONNECT_REQUEST_LEN + i + 1) {
				log_f(state, "SOCKS: Error: %s Trailing garbage after CONNECT",
						bdata(session->socks_addr));
				goto out_free;
			}
			bufferevent_disable(bev, EV_READ);

			memset(&addr, 0, sizeof(addr));
			addr.sin_family = AF_INET;
			addr.sin_port = *(uint16_t *) (p + 2);
			addr.sin_addr.s_addr = *(uint32_t *) (p + 4);

			if (ssh_new_connection(session, &addr, (char *) userid))
				goto out_free;

			evbuffer_drain(buf, len);

			return;
		}
	}

	if (len > OBFSPROXYSSH_CLIENT_MAX_SOCKS_REQ) {
		log_f(state, "SOCKS: Error: %s SOCKS 4 Request too big",
				bdata(session->socks_addr));
		goto out_free;
	}
	return;

out_free:
	session_free(session);
	return;
}
Пример #4
0
/*
 * Discard any data received. This is used after reading the response's
 * status line.
 */
static void
session_readcb_drain(struct bufferevent *bev, void *thunk)
{
	struct evbuffer *evbuf = bufferevent_get_input(bev);
	evbuffer_drain(evbuf, evbuffer_get_length(evbuf));
}
Пример #5
0
static void
test_evbuffer(void *ptr)
{
	static char buffer[512], *tmp;
	struct evbuffer *evb = evbuffer_new();
	struct evbuffer *evb_two = evbuffer_new();
	size_t sz_tmp;
	int i;

	evbuffer_validate(evb);
	evbuffer_add_printf(evb, "%s/%d", "hello", 1);
	evbuffer_validate(evb);

	tt_assert(evbuffer_get_length(evb) == 7);
	tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1));

	evbuffer_add_buffer(evb, evb_two);
	evbuffer_validate(evb);

	evbuffer_drain(evb, strlen("hello/"));
	evbuffer_validate(evb);
	tt_assert(evbuffer_get_length(evb) == 1);
	tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1));

	evbuffer_add_printf(evb_two, "%s", "/hello");
	evbuffer_validate(evb);
	evbuffer_add_buffer(evb, evb_two);
	evbuffer_validate(evb);

	tt_assert(evbuffer_get_length(evb_two) == 0);
	tt_assert(evbuffer_get_length(evb) == 7);
	tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7) != 0);

	memset(buffer, 0, sizeof(buffer));
	evbuffer_add(evb, buffer, sizeof(buffer));
	evbuffer_validate(evb);
	tt_assert(evbuffer_get_length(evb) == 7 + 512);

	tmp = (char *)evbuffer_pullup(evb, 7 + 512);
	tt_assert(tmp);
	tt_assert(!strncmp(tmp, "1/hello", 7));
	tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer)));
	evbuffer_validate(evb);

	evbuffer_prepend(evb, "something", 9);
	evbuffer_validate(evb);
	evbuffer_prepend(evb, "else", 4);
	evbuffer_validate(evb);

	tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7);
	tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7));
	evbuffer_validate(evb);

	evbuffer_drain(evb, -1);
	evbuffer_validate(evb);
	evbuffer_drain(evb_two, -1);
	evbuffer_validate(evb);

	for (i = 0; i < 3; ++i) {
		evbuffer_add(evb_two, buffer, sizeof(buffer));
		evbuffer_validate(evb_two);
		evbuffer_add_buffer(evb, evb_two);
		evbuffer_validate(evb);
		evbuffer_validate(evb_two);
	}

	tt_assert(evbuffer_get_length(evb_two) == 0);
	tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer));

	/* test remove buffer */
	sz_tmp = (size_t)(sizeof(buffer)*2.5);
	evbuffer_remove_buffer(evb, evb_two, sz_tmp);
	tt_assert(evbuffer_get_length(evb_two) == sz_tmp);
	tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2);
	evbuffer_validate(evb);

	if (memcmp(evbuffer_pullup(
			   evb, -1), buffer, sizeof(buffer) / 2) != 0 ||
	    memcmp(evbuffer_pullup(
			   evb_two, -1), buffer, sizeof(buffer) != 0))
		tt_abort_msg("Pullup did not preserve content");

	evbuffer_validate(evb);


	/* testing one-vector reserve and commit */
	{
		struct evbuffer_iovec v[1];
		char *buf;
		int i, j, r;

		for (i = 0; i < 3; ++i) {
			r = evbuffer_reserve_space(evb, 10000, v, 1);
			tt_int_op(r, ==, 1);
			tt_assert(v[0].iov_len >= 10000);
			tt_assert(v[0].iov_base != NULL);

			evbuffer_validate(evb);
			buf = v[0].iov_base;
			for (j = 0; j < 10000; ++j) {
				buf[j] = j;
			}
			evbuffer_validate(evb);

			tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0);
			evbuffer_validate(evb);

			tt_assert(evbuffer_get_length(evb) >= 10000);

			evbuffer_drain(evb, j * 5000);
			evbuffer_validate(evb);
		}
	}

 end:
	evbuffer_free(evb);
	evbuffer_free(evb_two);
}
Пример #6
0
/* Parse input. */
void
input_parse(struct window_pane *wp)
{
	struct input_ctx		*ictx = &wp->ictx;
	const struct input_transition	*itr;
	struct evbuffer			*evb = wp->event->input;
	u_char				*buf;
	size_t				 len, off;

	if (EVBUFFER_LENGTH(evb) == 0)
		return;

	wp->window->flags |= WINDOW_ACTIVITY;
	wp->window->flags &= ~WINDOW_SILENCE;

	/*
	 * Open the screen. Use NULL wp if there is a mode set as don't want to
	 * update the tty.
	 */
	if (wp->mode == NULL)
		screen_write_start(&ictx->ctx, wp, &wp->base);
	else
		screen_write_start(&ictx->ctx, NULL, &wp->base);
	ictx->wp = wp;

	buf = EVBUFFER_DATA(evb);
	len = EVBUFFER_LENGTH(evb);
	notify_input(wp, evb);
	off = 0;

	/* Parse the input. */
	while (off < len) {
		ictx->ch = buf[off++];
		log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);

		/* Find the transition. */
		itr = ictx->state->transitions;
		while (itr->first != -1 && itr->last != -1) {
			if (ictx->ch >= itr->first && ictx->ch <= itr->last)
				break;
			itr++;
		}
		if (itr->first == -1 || itr->last == -1) {
			/* No transition? Eh? */
			fatalx("No transition from state!");
		}

		/*
		 * Execute the handler, if any. Don't switch state if it
		 * returns non-zero.
		 */
		if (itr->handler != NULL && itr->handler(ictx) != 0)
			continue;

		/* And switch state, if necessary. */
		if (itr->state != NULL)
			input_set_state(wp, itr);

		/* If not in ground state, save input. */
		if (ictx->state != &input_state_ground)
			evbuffer_add(ictx->since_ground, &ictx->ch, 1);
	}

	/* Close the screen. */
	screen_write_stop(&ictx->ctx);

	evbuffer_drain(evb, len);
}