Merge remote-tracking branch 'origin/patches-2.0'

This commit is contained in:
Nick Mathewson 2012-08-23 10:13:26 -04:00
commit e3d010c8f6

View File

@ -559,15 +559,20 @@ decrement_buckets(struct bufferevent_openssl *bev_ssl)
bev_ssl->counts.n_read = num_r;
}
/* returns -1 on internal error, 0 on stall, 1 on progress */
static int
do_read(struct bufferevent_openssl *bev_ssl, int n_to_read)
{
#define OP_MADE_PROGRESS 1
#define OP_BLOCKED 2
#define OP_ERR 4
/* Return a bitmask of OP_MADE_PROGRESS (if we read anything); OP_BLOCKED (if
we're now blocked); and OP_ERR (if an error occurred). */
static int
do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
/* Requires lock */
struct bufferevent *bev = &bev_ssl->bev.bev;
struct evbuffer *input = bev->input;
int r, n, i, n_used = 0, blocked = 0, atmost;
int r, n, i, n_used = 0, atmost;
struct evbuffer_iovec space[2];
int result = 0;
atmost = bufferevent_get_read_max_(&bev_ssl->bev);
if (n_to_read > atmost)
@ -575,16 +580,17 @@ do_read(struct bufferevent_openssl *bev_ssl, int n_to_read)
n = evbuffer_reserve_space(input, n_to_read, space, 2);
if (n < 0)
return -1;
return OP_ERR;
for (i=0; i<n; ++i) {
if (bev_ssl->bev.read_suspended)
break;
r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
if (r>0) {
result |= OP_MADE_PROGRESS;
if (bev_ssl->read_blocked_on_write)
if (clear_rbow(bev_ssl) < 0)
return -1;
return OP_ERR | result;
++n_used;
space[i].iov_len = r;
decrement_buckets(bev_ssl);
@ -596,20 +602,20 @@ do_read(struct bufferevent_openssl *bev_ssl, int n_to_read)
/* Can't read until underlying has more data. */
if (bev_ssl->read_blocked_on_write)
if (clear_rbow(bev_ssl) < 0)
return -1;
return OP_ERR | result;
break;
case SSL_ERROR_WANT_WRITE:
/* This read operation requires a write, and the
* underlying is full */
if (!bev_ssl->read_blocked_on_write)
if (set_rbow(bev_ssl) < 0)
return -1;
return OP_ERR | result;
break;
default:
conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
break;
}
blocked = 1;
result |= OP_BLOCKED;
break; /* out of the loop */
}
}
@ -620,16 +626,19 @@ do_read(struct bufferevent_openssl *bev_ssl, int n_to_read)
BEV_RESET_GENERIC_READ_TIMEOUT(bev);
}
return blocked ? 0 : 1;
return result;
}
/* Return a bitmask of OP_MADE_PROGRESS (if we wrote anything); OP_BLOCKED (if
we're now blocked); and OP_ERR (if an error occurred). */
static int
do_write(struct bufferevent_openssl *bev_ssl, int atmost)
{
int i, r, n, n_written = 0, blocked=0;
int i, r, n, n_written = 0;
struct bufferevent *bev = &bev_ssl->bev.bev;
struct evbuffer *output = bev->output;
struct evbuffer_iovec space[8];
int result = 0;
if (bev_ssl->last_write > 0)
atmost = bev_ssl->last_write;
@ -638,7 +647,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
n = evbuffer_peek(output, atmost, NULL, space, 8);
if (n < 0)
return -1;
return OP_ERR | result;
if (n > 8)
n = 8;
@ -655,9 +664,10 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
r = SSL_write(bev_ssl->ssl, space[i].iov_base,
space[i].iov_len);
if (r > 0) {
result |= OP_MADE_PROGRESS;
if (bev_ssl->write_blocked_on_read)
if (clear_wbor(bev_ssl) < 0)
return -1;
return OP_ERR | result;
n_written += r;
bev_ssl->last_write = -1;
decrement_buckets(bev_ssl);
@ -669,7 +679,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
/* Can't read until underlying has more data. */
if (bev_ssl->write_blocked_on_read)
if (clear_wbor(bev_ssl) < 0)
return -1;
return OP_ERR | result;
bev_ssl->last_write = space[i].iov_len;
break;
case SSL_ERROR_WANT_READ:
@ -677,7 +687,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
* underlying is full */
if (!bev_ssl->write_blocked_on_read)
if (set_wbor(bev_ssl) < 0)
return -1;
return OP_ERR | result;
bev_ssl->last_write = space[i].iov_len;
break;
default:
@ -685,7 +695,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
bev_ssl->last_write = -1;
break;
}
blocked = 1;
result |= OP_BLOCKED;
break;
}
}
@ -697,7 +707,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
if (evbuffer_get_length(output) <= bev->wm_write.low)
bufferevent_run_writecb_(bev);
}
return blocked ? 0 : 1;
return result;
}
#define WRITE_FRAME 15000
@ -757,11 +767,11 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
{
int r;
int n_to_read;
int read_data = 0;
int all_result_flags = 0;
while (bev_ssl->write_blocked_on_read) {
r = do_write(bev_ssl, WRITE_FRAME);
if (r <= 0)
if (r & (OP_BLOCKED|OP_ERR))
break;
}
if (bev_ssl->write_blocked_on_read)
@ -770,10 +780,11 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
n_to_read = bytes_to_read(bev_ssl);
while (n_to_read) {
if (do_read(bev_ssl, n_to_read) <= 0)
break;
r = do_read(bev_ssl, n_to_read);
all_result_flags |= r;
read_data = 1;
if (r & (OP_BLOCKED|OP_ERR))
break;
/* Read all pending data. This won't hit the network
* again, and will (most importantly) put us in a state
@ -803,7 +814,7 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
n_to_read = bytes_to_read(bev_ssl);
}
if (read_data == 1) {
if (all_result_flags & OP_MADE_PROGRESS) {
struct bufferevent *bev = &bev_ssl->bev.bev;
struct evbuffer *input = bev->input;
@ -831,9 +842,7 @@ consider_writing(struct bufferevent_openssl *bev_ssl)
while (bev_ssl->read_blocked_on_write) {
r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
if (r <= 0)
break;
else {
if (r & OP_MADE_PROGRESS) {
struct bufferevent *bev = &bev_ssl->bev.bev;
struct evbuffer *input = bev->input;
@ -841,6 +850,8 @@ consider_writing(struct bufferevent_openssl *bev_ssl)
bufferevent_run_readcb_(bev);
}
}
if (r & (OP_ERR|OP_BLOCKED))
break;
}
if (bev_ssl->read_blocked_on_write)
return;
@ -858,7 +869,7 @@ consider_writing(struct bufferevent_openssl *bev_ssl)
else
n_to_write = WRITE_FRAME;
r = do_write(bev_ssl, n_to_write);
if (r <= 0)
if (r & (OP_BLOCKED|OP_ERR))
break;
}