long bud_bio_ctrl(BIO* bio, int cmd, long num, void* ptr) { ringbuffer* buffer; long ret; buffer = bio->ptr; ret = 1; switch (cmd) { case BIO_CTRL_EOF: ret = ringbuffer_is_empty(buffer); break; case BIO_C_SET_BUF_MEM_EOF_RETURN: bio->num = num; break; case BIO_CTRL_INFO: ret = (long) ringbuffer_size(buffer); if (ptr != NULL) *(void**)(ptr) = NULL; break; case BIO_CTRL_RESET: ASSERT(0, "BIO_CTRL_RESET Unsupported"); break; case BIO_C_SET_BUF_MEM: ASSERT(0, "BIO_C_SET_BUF_MEM Unsupported"); break; case BIO_C_GET_BUF_MEM_PTR: ASSERT(0, "BIO_C_GET_BUF_MEM Unsupported"); break; case BIO_CTRL_GET_CLOSE: ret = bio->shutdown; break; case BIO_CTRL_SET_CLOSE: bio->shutdown = num; break; case BIO_CTRL_WPENDING: ret = 0; break; case BIO_CTRL_PENDING: ret = (long) ringbuffer_size(buffer); break; case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret = 1; break; case BIO_CTRL_PUSH: case BIO_CTRL_POP: default: ret = 0; break; } return ret; }
bud_client_error_t bud_client_throttle(bud_client_t* client, bud_client_side_t* side, ringbuffer* buf) { int err; bud_client_side_t* opposite; if (!ringbuffer_is_full(buf)) return bud_client_ok(side); opposite = side == &client->frontend ? &client->backend : &client->frontend; if (opposite->reading != kBudProgressRunning) goto done; DBG(opposite, "throttle, buffer full: %ld", ringbuffer_size(buf)); err = uv_read_stop((uv_stream_t*) &opposite->tcp); if (err != 0) { NOTICE(opposite, "uv_read_stop failed: %d - \"%s\"", err, uv_strerror(err)); return bud_client_error(bud_error_num(kBudErrClientReadStop, err), side); } opposite->reading = kBudProgressNone; done: return bud_client_error(bud_error(kBudErrClientThrottle), side); }
size_t ringbuffer_read_into(ringbuffer* rb, char* out, size_t length) { size_t bytes_read; size_t expected; size_t offset; size_t left; bufent* read_head; size_t avail; bytes_read = 0; expected = ringbuffer_size(rb) > length ? length : ringbuffer_size(rb); offset = 0; left = length; while (bytes_read < expected) { read_head = rb->read_head; assert(read_head->read_pos <= read_head->write_pos); avail = RB_BUF_SIZE(read_head); if (avail > left) avail = left; /* Copy data */ if (out != NULL) memcpy(out + offset, read_head->data + read_head->read_pos, avail); read_head->read_pos += avail; /* Move pointers */ bytes_read += avail; offset += avail; left -= avail; /* Move to next buffer */ ringbuffer_try_move_read_head(rb); } assert(expected == bytes_read); rb->length -= bytes_read; /* Free all empty buffers, but write_head's child */ ringbuffer_free_empty(rb); return bytes_read; }
bud_client_error_t bud_client_backend_in(bud_client_t* client) { size_t size; int written; int err; bud_client_error_t cerr; written = 0; while (!ringbuffer_is_empty(&client->backend.input)) { char* data; data = ringbuffer_read_next(&client->backend.input, &size); written = SSL_write(client->ssl, data, size); DBG(&client->frontend, "SSL_write() => %d", written); DBG(&client->frontend, "frontend.output => %d", ringbuffer_size(&client->frontend.output)); if (written < 0) break; ASSERT(written == (int) size, "SSL_write() did unexpected partial write"); ringbuffer_read_skip(&client->backend.input, written); /* info_cb() has closed front-end */ if (client->frontend.close != kBudProgressNone) return bud_client_ok(&client->backend); } cerr = bud_client_throttle(client, &client->frontend, &client->frontend.output); if (!bud_is_ok(cerr.err) && cerr.err.code != kBudErrClientThrottle) return cerr; if (written >= 0) return bud_client_ok(&client->backend); err = SSL_get_error(client->ssl, written); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_X509_LOOKUP) { return bud_client_ok(&client->backend); } return bud_client_error(bud_error_num(kBudErrClientSSLWrite, err), &client->backend); }
int ringbuffer_is_full(ringbuffer* rb) { return ringbuffer_size(rb) >= RING_MAX_SIZE; }
int ringbuffer_is_empty(ringbuffer* rb) { return ringbuffer_size(rb) == 0; }
int ringbuffer_insert(ringbuffer* rb, size_t off, const char* data, size_t length) { bufent* b; bufent* next; bufent* start; size_t left; size_t offset; int r; assert(length < RING_BUFFER_LEN); /* Find owner of `off` */ left = ringbuffer_size(rb); start = rb->read_head; while (off != 0) { if (off < RB_BUF_SIZE(start)) break; off -= RB_BUF_SIZE(start); left -= RB_BUF_SIZE(start); start = start->next; } /* Shift everything after `off` forward by `length` */ b = rb->write_head; /* Ensure that we have enough space for shift */ r = ringbuffer_write_append(rb, length); if (r != 0) return r; next = rb->write_head; while (left > 0) { /* Copy part of the data from the end of current to the next buffer */ if (next != b) memcpy(next->data, b->data + RING_BUFFER_LEN - length, length); /* Move rest inside current buffer */ offset = b->read_pos; if (b == start) offset += off; if (offset + length < RING_BUFFER_LEN) { memmove(b->data + offset + length, b->data + offset, RING_BUFFER_LEN - offset - length); } if (b == start) break; left -= RB_BUF_SIZE(b); /* Select previous buffer, O(N) */ next = b; b = start; while (b->next != next) b = b->next; } /* Copy input data into the free space */ if (off + length > RING_BUFFER_LEN) { size_t delta; delta = off + length - RING_BUFFER_LEN; memcpy(start->data + off, data, length - delta); memcpy(next->data, data + length - delta, delta); } else { memcpy(start->data + off, data, length); } return 0; }
int main() { int i; int j; int r; int after; ssize_t len; char* ptr; data = malloc(TEST_DATA_SIZE); assert(data != NULL); ringbuffer_init(&rb); /* Fill test data */ for (i = 0; i < TEST_DATA_SIZE; i++) data[i] = (i * i) % 137; /* Fill ringbuffer */ i = 0; after = 0; while (i < TEST_DATA_SIZE - TEST_INSERT_LEN) { if (after) len = TEST_DATA_SIZE - i - TEST_INSERT_LEN; else len = TEST_INSERT_OFF - i; ptr = ringbuffer_write_ptr(&rb, &len); ASSERT(ptr != NULL); /* Always make progress */ ASSERT(len > 0); if (after) memcpy(ptr, data + i + TEST_INSERT_LEN, len); else memcpy(ptr, data + i, len); i += len; r = ringbuffer_write_append(&rb, len); ASSERT(r == 0); if (i == TEST_INSERT_OFF) after = 1; } ASSERT(ringbuffer_size(&rb) == TEST_DATA_SIZE - TEST_INSERT_LEN); /* Insert stuff */ ringbuffer_insert(&rb, TEST_INSERT_OFF, data + TEST_INSERT_OFF, TEST_INSERT_LEN); /* Read from it */ i = 0; while (i < TEST_DATA_SIZE) { len = TEST_DATA_SIZE - i; ptr = ringbuffer_read_next(&rb, &len); ASSERT(ptr != NULL); /* Always make progress */ ASSERT(len > 0); for (j = 0; j < len; j++) ASSERT(ptr[j] == data[i + j]); ringbuffer_read_skip(&rb, len); i += len; } /* Destroy it */ ringbuffer_destroy(&rb); return 0; }
DECLARE_TEST( ringbuffer, allocate ) { ringbuffer_t* buffer; char store[256]; buffer = ringbuffer_allocate( 0 ); EXPECT_EQ( ringbuffer_size( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_read( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_size( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_read( buffer, store, 256 ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 256 ), 0 ); EXPECT_EQ( ringbuffer_size( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); ringbuffer_deallocate( buffer ); buffer = ringbuffer_allocate( 128 ); EXPECT_EQ( ringbuffer_size( buffer ), 128 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_read( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_size( buffer ), 128 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 256 ), 127 ); EXPECT_EQ( ringbuffer_read( buffer, store, 256 ), 127 ); EXPECT_EQ( ringbuffer_size( buffer ), 128 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 127 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 127 ); ringbuffer_deallocate( buffer ); buffer = ringbuffer_allocate( 256 ); EXPECT_EQ( ringbuffer_size( buffer ), 256 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_read( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_size( buffer ), 256 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 256 ), 255 ); EXPECT_EQ( ringbuffer_read( buffer, store, 256 ), 255 ); EXPECT_EQ( ringbuffer_size( buffer ), 256 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 255 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 255 ); ringbuffer_deallocate( buffer ); buffer = ringbuffer_allocate( 512 ); EXPECT_EQ( ringbuffer_size( buffer ), 512 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_read( buffer, store, 0 ), 0 ); EXPECT_EQ( ringbuffer_size( buffer ), 512 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 0 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 0 ); EXPECT_EQ( ringbuffer_write( buffer, store, 256 ), 256 ); EXPECT_EQ( ringbuffer_read( buffer, store, 256 ), 256 ); EXPECT_EQ( ringbuffer_size( buffer ), 512 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 256 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 256 ); EXPECT_EQ( ringbuffer_write( buffer, store, 256 ), 256 ); EXPECT_EQ( ringbuffer_read( buffer, store, 256 ), 256 ); EXPECT_EQ( ringbuffer_size( buffer ), 512 ); EXPECT_EQ( ringbuffer_total_read( buffer ), 512 ); EXPECT_EQ( ringbuffer_total_written( buffer ), 512 ); ringbuffer_deallocate( buffer ); return 0; }