X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/d0137ef83eaef1fbdd9745cfb3c75ea68aa0fa12..HEAD:/packet.c diff --git a/packet.c b/packet.c index f3f8389a..994e35b6 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.163 2009/05/28 16:50:16 andreas Exp $ */ +/* $OpenBSD: packet.c,v 1.166 2009/06/27 09:29:06 andreas Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -182,13 +182,22 @@ struct session_state { /* Used in packet_read_poll2() */ u_int packlen; + /* Used in packet_send2 */ + int rekeying; + + /* Used in packet_set_interactive */ + int set_interactive_called; + + /* Used in packet_set_maxsize */ + int set_maxsize_called; + TAILQ_HEAD(, packet) outgoing; }; -static struct session_state *active_state; +static struct session_state *active_state, *backup_state; static struct session_state * -alloc_session_state() +alloc_session_state(void) { struct session_state *s = xcalloc(1, sizeof(*s)); @@ -950,7 +959,6 @@ packet_send2_wrapped(void) static void packet_send2(void) { - static int rekeying = 0; struct packet *p; u_char type, *cp; @@ -958,7 +966,7 @@ packet_send2(void) type = cp[5]; /* during rekeying we can only send key exchange messages */ - if (rekeying) { + if (active_state->rekeying) { if (!((type >= SSH2_MSG_TRANSPORT_MIN) && (type <= SSH2_MSG_TRANSPORT_MAX))) { debug("enqueue packet: %u", type); @@ -974,13 +982,13 @@ packet_send2(void) /* rekeying starts with sending KEXINIT */ if (type == SSH2_MSG_KEXINIT) - rekeying = 1; + active_state->rekeying = 1; packet_send2_wrapped(); /* after a NEWKEYS message we can send the complete queue */ if (type == SSH2_MSG_NEWKEYS) { - rekeying = 0; + active_state->rekeying = 0; while ((p = TAILQ_FIRST(&active_state->outgoing))) { type = p->type; debug("dequeue packet: %u", type); @@ -1062,7 +1070,8 @@ packet_read_seqnr(u_int32_t *seqnr_p) if ((ret = select(active_state->connection_in + 1, setp, NULL, NULL, timeoutp)) >= 0) break; - if (errno != EAGAIN && errno != EINTR) + if (errno != EAGAIN && errno != EINTR && + errno != EWOULDBLOCK) break; if (active_state->packet_timeout_ms == -1) continue; @@ -1635,7 +1644,8 @@ packet_write_poll(void) len = roaming_write(active_state->connection_out, buffer_ptr(&active_state->output), len, &cont); if (len == -1) { - if (errno == EINTR || errno == EAGAIN) + if (errno == EINTR || errno == EAGAIN || + errno == EWOULDBLOCK) return; fatal("Write failed: %.100s", strerror(errno)); } @@ -1677,7 +1687,8 @@ packet_write_wait(void) if ((ret = select(active_state->connection_out + 1, NULL, setp, NULL, timeoutp)) >= 0) break; - if (errno != EAGAIN && errno != EINTR) + if (errno != EAGAIN && errno != EINTR && + errno != EWOULDBLOCK) break; if (active_state->packet_timeout_ms == -1) continue; @@ -1737,11 +1748,9 @@ packet_set_tos(int interactive) void packet_set_interactive(int interactive) { - static int called = 0; - - if (called) + if (active_state->set_interactive_called) return; - called = 1; + active_state->set_interactive_called = 1; /* Record that we are in interactive mode. */ active_state->interactive_mode = interactive; @@ -1764,9 +1773,7 @@ packet_is_interactive(void) int packet_set_maxsize(u_int s) { - static int called = 0; - - if (called) { + if (active_state->set_maxsize_called) { logit("packet_set_maxsize: called twice: old %d new %d", active_state->max_packet_size, s); return -1; @@ -1775,7 +1782,7 @@ packet_set_maxsize(u_int s) logit("packet_set_maxsize: bad size %d", s); return -1; } - called = 1; + active_state->set_maxsize_called = 1; debug("packet_set_maxsize: setting to %d", s); active_state->max_packet_size = s; return s; @@ -1883,3 +1890,50 @@ packet_get_newkeys(int mode) { return (void *)active_state->newkeys[mode]; } + +/* + * Save the state for the real connection, and use a separate state when + * resuming a suspended connection. + */ +void +packet_backup_state(void) +{ + struct session_state *tmp; + + close(active_state->connection_in); + active_state->connection_in = -1; + close(active_state->connection_out); + active_state->connection_out = -1; + if (backup_state) + tmp = backup_state; + else + tmp = alloc_session_state(); + backup_state = active_state; + active_state = tmp; +} + +/* + * Swap in the old state when resuming a connecion. + */ +void +packet_restore_state(void) +{ + struct session_state *tmp; + void *buf; + u_int len; + + tmp = backup_state; + backup_state = active_state; + active_state = tmp; + active_state->connection_in = backup_state->connection_in; + backup_state->connection_in = -1; + active_state->connection_out = backup_state->connection_out; + backup_state->connection_out = -1; + len = buffer_len(&backup_state->input); + if (len > 0) { + buf = buffer_ptr(&backup_state->input); + buffer_append(&active_state->input, buf, len); + buffer_clear(&backup_state->input); + add_recv_bytes(len); + } +}