Merge branch 'vendor/OPENSSH'
[dragonfly.git] / crypto / openssh / channels.c
index d67fdf4..e45e730 100644 (file)
@@ -179,8 +179,14 @@ static void port_open_helper(Channel *c, char *rtype);
 static int connect_next(struct channel_connect *);
 static void channel_connect_ctx_free(struct channel_connect *);
 
+
+static int hpn_disabled = 0;
+static int hpn_buffer_size = 2 * 1024 * 1024;
+
 /* -- channel core */
 
+
+
 Channel *
 channel_by_id(int id)
 {
@@ -329,6 +335,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
        c->local_window_max = window;
        c->local_consumed = 0;
        c->local_maxpacket = maxpack;
+       c->dynamic_window = 0;
        c->remote_id = -1;
        c->remote_name = xstrdup(remote_name);
        c->remote_window = 0;
@@ -833,11 +840,35 @@ channel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset)
                FD_SET(c->sock, writeset);
 }
 
+int channel_tcpwinsz () {
+        u_int32_t tcpwinsz = 0;
+        socklen_t optsz = sizeof(tcpwinsz);
+       int ret = -1;
+
+       /* if we aren't on a socket return 128KB*/
+       if(!packet_connection_is_on_socket())
+           return(128*1024);
+       ret = getsockopt(packet_get_connection_in(),
+                        SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz);
+       /* return no more than 64MB */
+       if ((ret == 0) && tcpwinsz > BUFFER_MAX_LEN_HPN)
+           tcpwinsz = BUFFER_MAX_LEN_HPN;
+       debug2("tcpwinsz: %d for connection: %d", tcpwinsz,
+              packet_get_connection_in());
+       return(tcpwinsz);
+}
+
 static void
 channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
 {
        u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
 
+        /* check buffer limits */
+       if ((!c->tcpwinsz) || (c->dynamic_window > 0))
+           c->tcpwinsz = channel_tcpwinsz();
+
+       limit = MIN(limit, 2 * c->tcpwinsz);
+
        if (c->istate == CHAN_INPUT_OPEN &&
            limit > 0 &&
            buffer_len(&c->input) < limit &&
@@ -1842,14 +1873,21 @@ channel_check_window(Channel *c)
            c->local_maxpacket*3) ||
            c->local_window < c->local_window_max/2) &&
            c->local_consumed > 0) {
+               u_int addition = 0;
+               /* adjust max window size if we are in a dynamic environment */
+               if (c->dynamic_window && (c->tcpwinsz > c->local_window_max)) {
+                       /* grow the window somewhat aggressively to maintain pressure */
+                       addition = 1.5*(c->tcpwinsz - c->local_window_max);
+                       c->local_window_max += addition;
+               }
                packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
                packet_put_int(c->remote_id);
-               packet_put_int(c->local_consumed);
+               packet_put_int(c->local_consumed + addition);
                packet_send();
                debug2("channel %d: window %d sent adjust %d",
                    c->self, c->local_window,
                    c->local_consumed);
-               c->local_window += c->local_consumed;
+               c->local_window += c->local_consumed + addition;
                c->local_consumed = 0;
        }
        return 1;
@@ -2213,11 +2251,12 @@ channel_after_select(fd_set *readset, fd_set *writeset)
 
 
 /* If there is data to send to the connection, enqueue some of it now. */
-void
+int
 channel_output_poll(void)
 {
        Channel *c;
        u_int i, len;
+       int packet_length = 0;
 
        for (i = 0; i < channels_alloc; i++) {
                c = channels[i];
@@ -2265,7 +2304,7 @@ channel_output_poll(void)
                                        packet_start(SSH2_MSG_CHANNEL_DATA);
                                        packet_put_int(c->remote_id);
                                        packet_put_string(data, dlen);
-                                       packet_send();
+                                       packet_length = packet_send();
                                        c->remote_window -= dlen + 4;
                                        free(data);
                                }
@@ -2295,7 +2334,7 @@ channel_output_poll(void)
                                    SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
                                packet_put_int(c->remote_id);
                                packet_put_string(buffer_ptr(&c->input), len);
-                               packet_send();
+                               packet_length = packet_send();
                                buffer_consume(&c->input, len);
                                c->remote_window -= len;
                        }
@@ -2330,12 +2369,13 @@ channel_output_poll(void)
                        packet_put_int(c->remote_id);
                        packet_put_int(SSH2_EXTENDED_DATA_STDERR);
                        packet_put_string(buffer_ptr(&c->extended), len);
-                       packet_send();
+                       packet_length = packet_send();
                        buffer_consume(&c->extended, len);
                        c->remote_window -= len;
                        debug2("channel %d: sent ext data %d", c->self, len);
                }
        }
+       return (packet_length);
 }
 
 
@@ -2718,6 +2758,13 @@ channel_set_af(int af)
 }
 
 
+void
+channel_set_hpn(int external_hpn_disabled, int external_hpn_buffer_size)
+{
+       hpn_disabled = external_hpn_disabled;
+       hpn_buffer_size = external_hpn_buffer_size;
+       debug("HPN Disabled: %d, HPN Buffer Size: %d", hpn_disabled, hpn_buffer_size);
+}
 /*
  * Determine whether or not a port forward listens to loopback, the
  * specified address or wildcard. On the client, a specified bind
@@ -2905,9 +2952,15 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
                }
 
                /* Allocate a channel number for the socket. */
+               /* explicitly test for hpn disabled option. if true use smaller window size */
+               if (hpn_disabled)
                c = channel_new("port listener", type, sock, sock, -1,
                    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
                    0, "port listener", 1);
+               else
+                       c = channel_new("port listener", type, sock, sock, -1,
+                         hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT,
+                         0, "port listener", 1);
                c->path = xstrdup(host);
                c->host_port = fwd->connect_port;
                c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
@@ -3939,10 +3992,17 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
        *chanids = xcalloc(num_socks + 1, sizeof(**chanids));
        for (n = 0; n < num_socks; n++) {
                sock = socks[n];
+               /* Is this really necassary? */
+               if (hpn_disabled)
                nc = channel_new("x11 listener",
                    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
                    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
                    0, "X11 inet listener", 1);
+               else
+                       nc = channel_new("x11 listener",
+                           SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
+                           hpn_buffer_size, CHAN_X11_PACKET_DEFAULT,
+                           0, "X11 inet listener", 1);
                nc->single_connection = single_connection;
                (*chanids)[n] = nc->self;
        }