-/* $OpenBSD: channels.c,v 1.266 2006/08/29 10:40:18 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.270 2007/06/25 08:20:03 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
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 &&
if (have < nmethods + 2)
return 0;
/* look for method: "NO AUTHENTICATION REQUIRED" */
- for (found = 0, i = 2 ; i < nmethods + 2; i++) {
+ for (found = 0, i = 2; i < nmethods + 2; i++) {
if (p[i] == SSH_SOCKS5_NOAUTH) {
found = 1;
break;
channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
{
char buf[CHAN_RBUF];
- int len;
+ int len, force;
- if (c->rfd != -1 &&
- FD_ISSET(c->rfd, readset)) {
+ force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
+ if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
errno = 0;
len = read(c->rfd, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR || errno == EAGAIN))
+ if (len < 0 && (errno == EINTR || (errno == EAGAIN && !force)))
return 1;
#ifndef PTY_ZEROREAD
if (len <= 0) {
c->local_consumed += len;
}
} else if (c->extended_usage == CHAN_EXTENDED_READ &&
- FD_ISSET(c->efd, readset)) {
+ (c->detach_close || FD_ISSET(c->efd, readset))) {
len = read(c->efd, buf, sizeof(buf));
debug2("channel %d: read %d from efd %d",
c->self, len, c->efd);
- if (len < 0 && (errno == EINTR || errno == EAGAIN))
+ if (len < 0 && (errno == EINTR ||
+ (errno == EAGAIN && !c->detach_close)))
return 1;
if (len <= 0) {
debug2("channel %d: closing read-efd %d",
{
if (c->type == SSH_CHANNEL_OPEN &&
!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
- c->local_window < c->local_window_max/2 &&
+ ((c->local_window_max - c->local_window >
+ 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)) {
- addition = 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);
/* 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];
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;
xfree(data);
}
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;
}
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);
}
/* 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);
+ 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,
/* Send the forward request to the remote side. */
if (compat20) {
const char *address_to_bind;
- if (listen_host == NULL)
- address_to_bind = "localhost";
- else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0)
- address_to_bind = "";
- else
+ if (listen_host == NULL) {
+ if (datafellows & SSH_BUG_RFWD_ADDR)
+ address_to_bind = "127.0.0.1";
+ else
+ address_to_bind = "localhost";
+ } else if (*listen_host == '\0' ||
+ strcmp(listen_host, "*") == 0) {
+ if (datafellows & SSH_BUG_RFWD_ADDR)
+ address_to_bind = "0.0.0.0";
+ else
+ address_to_bind = "";
+ } else
address_to_bind = listen_host;
packet_start(SSH2_MSG_GLOBAL_REQUEST);
* message if there was an error).
*/
int
-channel_input_port_forward_request(int is_root, int gateway_ports,
- int hpn_disabled, int hpn_buffer_size)
+channel_input_port_forward_request(int is_root, int gateway_ports,
+ int hpn_disabled, int hpn_buffer_size)
{
u_short port, host_port;
int success = 0;
*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);
+ 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,