-/* $OpenBSD: packet.c,v 1.162 2009/05/27 06:36:07 andreas Exp $ */
+/* $OpenBSD: packet.c,v 1.166 2009/06/27 09:29:06 andreas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
#include "canohost.h"
#include "misc.h"
#include "ssh.h"
+#include "roaming.h"
#ifdef PACKET_DEBUG
#define DBG(x) x
/* 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));
static void
packet_send2(void)
{
- static int rekeying = 0;
struct packet *p;
u_char type, *cp;
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);
/* 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);
int
packet_read_seqnr(u_int32_t *seqnr_p)
{
- int type, len, ret, ms_remain;
+ int type, len, ret, ms_remain, cont;
fd_set *setp;
char buf[8192];
struct timeval timeout, start, *timeoutp = NULL;
cleanup_exit(255);
}
/* Read data from the socket. */
- len = read(active_state->connection_in, buf, sizeof(buf));
+ do {
+ cont = 0;
+ len = roaming_read(active_state->connection_in, buf,
+ sizeof(buf), &cont);
+ } while (len == 0 && cont);
if (len == 0) {
logit("Connection closed by %.200s", get_remote_ipaddr());
cleanup_exit(255);
packet_write_poll(void)
{
int len = buffer_len(&active_state->output);
+ int cont;
if (len > 0) {
- len = write(active_state->connection_out,
- buffer_ptr(&active_state->output), len);
+ cont = 0;
+ len = roaming_write(active_state->connection_out,
+ buffer_ptr(&active_state->output), len, &cont);
if (len == -1) {
if (errno == EINTR || errno == EAGAIN ||
errno == EWOULDBLOCK)
return;
fatal("Write failed: %.100s", strerror(errno));
}
- if (len == 0)
+ if (len == 0 && !cont)
fatal("Write connection closed");
buffer_consume(&active_state->output, len);
}
}
-
/*
* Calls packet_write_poll repeatedly until all pending output data has been
* written.
return buffer_len(&active_state->output) < 128 * 1024;
}
-
static void
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;
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;
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;
{
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);
+ }
+}