summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channel.h2
-rw-r--r--common-channel.c4
-rw-r--r--common-session.c22
-rw-r--r--packet.c26
-rw-r--r--packet.h3
-rw-r--r--session.h1
6 files changed, 41 insertions, 17 deletions
diff --git a/channel.h b/channel.h
index 99b1b42..d16cb03 100644
--- a/channel.h
+++ b/channel.h
@@ -106,7 +106,7 @@ void channel_connect_done(int result, int sock, void* user_data, const char* err
void chaninitialise(const struct ChanType *chantypes[]);
void chancleanup();
-void setchannelfds(fd_set *readfd, fd_set *writefd);
+void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel();
/* Returns an arbitrary channel that is in a ready state - not
diff --git a/common-channel.c b/common-channel.c
index a2ed283..0e5c0f1 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -531,7 +531,7 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
/* Set the file descriptors for the main select in session.c
* This avoid channels which don't have any window available, are closed, etc*/
-void setchannelfds(fd_set *readfds, fd_set *writefds) {
+void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
unsigned int i;
struct Channel * channel;
@@ -549,7 +549,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
FD if there's the possibility of "~."" to kill an
interactive session (the read_mangler) */
if (channel->transwindow > 0
- && (ses.dataallowed || channel->read_mangler)) {
+ && ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
if (channel->readfd >= 0) {
FD_SET(channel->readfd, readfds);
diff --git a/common-session.c b/common-session.c
index 164dc85..44e7030 100644
--- a/common-session.c
+++ b/common-session.c
@@ -64,6 +64,13 @@ void common_session_init(int sock_in, int sock_out) {
ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out);
+ if (sock_in >= 0) {
+ setnonblocking(sock_in);
+ }
+ if (sock_out >= 0) {
+ setnonblocking(sock_out);
+ }
+
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
@@ -145,6 +152,7 @@ void session_loop(void(*loophandler)()) {
/* main loop, select()s for all sockets in use */
for(;;) {
+ const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
timeout.tv_sec = select_timeout();
timeout.tv_usec = 0;
@@ -155,8 +163,12 @@ void session_loop(void(*loophandler)()) {
/* We delay reading from the input socket during initial setup until
after we have written out our initial KEXINIT packet (empty writequeue).
This means our initial packet can be in-flight while we're doing a blocking
- read for the remote ident */
- if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
+ read for the remote ident.
+ We also avoid reading from the socket if the writequeue is full, that avoids
+ replies backing up */
+ if (ses.sock_in != -1
+ && (ses.remoteident || isempty(&ses.writequeue))
+ && writequeue_has_space) {
FD_SET(ses.sock_in, &readfd);
}
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
@@ -168,7 +180,7 @@ void session_loop(void(*loophandler)()) {
FD_SET(ses.signal_pipe[0], &readfd);
/* set up for channels which can be read/written */
- setchannelfds(&readfd, &writefd);
+ setchannelfds(&readfd, &writefd, writequeue_has_space);
/* Pending connections to test */
set_connect_fds(&writefd);
@@ -318,9 +330,7 @@ void session_cleanup() {
void send_session_identification() {
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
- buf_putbyte(writebuf, 0x0); /* packet type */
- buf_setpos(writebuf, 0);
- enqueue(&ses.writequeue, writebuf);
+ writebuf_enqueue(writebuf, 0);
}
static void read_session_identification() {
diff --git a/packet.c b/packet.c
index 19abe6a..1d1be84 100644
--- a/packet.c
+++ b/packet.c
@@ -59,7 +59,7 @@ void write_packet() {
ssize_t written;
#ifdef HAVE_WRITEV
/* 50 is somewhat arbitrary */
- int iov_count = 50;
+ unsigned int iov_count = 50;
struct iovec iov[50];
#endif
@@ -83,6 +83,7 @@ void write_packet() {
}
packet_queue_consume(&ses.writequeue, written);
+ ses.writequeue_len -= written;
if (written == 0) {
ses.remoteclosed();
@@ -113,6 +114,8 @@ void write_packet() {
ses.remoteclosed();
}
+ ses.writequeue_len -= written;
+
if (written == len) {
/* We've finished with the packet, free it */
dequeue(&ses.writequeue);
@@ -570,15 +573,12 @@ void encrypt_packet() {
/* stick the MAC on it */
buf_putbytes(writebuf, mac_bytes, mac_size);
- /* The last byte of the buffer stores the cleartext packet_type. It is not
- * transmitted but is used for transmit timeout purposes */
- buf_putbyte(writebuf, packet_type);
- /* enqueue the packet for sending. It will get freed after transmission. */
- buf_setpos(writebuf, 0);
- enqueue(&ses.writequeue, (void*)writebuf);
-
/* Update counts */
ses.kexstate.datatrans += writebuf->len;
+
+ writebuf_enqueue(writebuf, packet_type);
+
+ /* Update counts */
ses.transseq++;
now = monotonic_now();
@@ -596,6 +596,16 @@ void encrypt_packet() {
TRACE2(("leave encrypt_packet()"))
}
+void writebuf_enqueue(buffer * writebuf, unsigned char packet_type) {
+ /* The last byte of the buffer stores the cleartext packet_type. It is not
+ * transmitted but is used for transmit timeout purposes */
+ buf_putbyte(writebuf, packet_type);
+ /* enqueue the packet for sending. It will get freed after transmission. */
+ buf_setpos(writebuf, 0);
+ enqueue(&ses.writequeue, (void*)writebuf);
+ ses.writequeue_len += writebuf->len-1;
+}
+
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
diff --git a/packet.h b/packet.h
index cd21fe0..6013b72 100644
--- a/packet.h
+++ b/packet.h
@@ -28,12 +28,15 @@
#include "includes.h"
#include "queue.h"
+#include "buffer.h"
void write_packet();
void read_packet();
void decrypt_packet();
void encrypt_packet();
+void writebuf_enqueue(buffer * writebuf, unsigned char packet_type);
+
void process_packet();
void maybe_flush_reply_queue();
diff --git a/session.h b/session.h
index 478de94..0059d94 100644
--- a/session.h
+++ b/session.h
@@ -125,6 +125,7 @@ struct sshsession {
throughout the code, as handlers fill out this
buffer with the packet to send. */
struct Queue writequeue; /* A queue of encrypted packets to send */
+ unsigned int writequeue_len; /* Number of bytes pending to send in writequeue */
buffer *readbuf; /* From the wire, decrypted in-place */
buffer *payload; /* Post-decompression, the actual SSH packet.
May have extra data at the beginning, will be