Permalink
Browse files

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

  • Loading branch information...
2 parents f1bd938 + 606ac43 commit e3d010c8f6a2d91218826e922e16a2f14c59d5c0 Nick Mathewson committed Aug 23, 2012
Showing with 39 additions and 28 deletions.
  1. +39 −28 bufferevent_openssl.c
View
@@ -559,32 +559,38 @@ 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)
n_to_read = atmost;
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,23 +679,23 @@ 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:
/* This read operation requires a write, and the
* 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:
conn_closed(bev_ssl, BEV_EVENT_WRITING, err, r);
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,16 +842,16 @@ 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;
if (evbuffer_get_length(input) >= bev->wm_read.low) {
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;
}

0 comments on commit e3d010c

Please sign in to comment.