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