Пример #1
0
/* Write some previously-buffered backend data upstream on the
 * secure socket using OpenSSL */
static void client_write(struct ev_loop *loop, ev_io *w, int revents) {
    (void) revents;
    int t;
    int sz;
    proxystate *ps = (proxystate *)w->data;
    assert(!ringbuffer_is_empty(&ps->ring_up));
    char * next = ringbuffer_read_next(&ps->ring_up, &sz);
    t = SSL_write(ps->ssl, next, sz);
    if (t > 0) {
        if (t == sz) {
            ringbuffer_read_pop(&ps->ring_up);
            safe_enable_io(ps, &ps->ev_r_down); // can be re-enabled b/c we've popped
            if (ringbuffer_is_empty(&ps->ring_up)) {
                if (ps->want_shutdown) {
                    shutdown_proxy(ps, SHUTDOWN_HARD);
                    return;
                }
                ev_io_stop(loop, &ps->ev_w_up);
            }
        }
        else {
            ringbuffer_read_skip(&ps->ring_up, t);
        }
    }
    else {
        int err = SSL_get_error(ps->ssl, t);
        if (err == SSL_ERROR_WANT_READ) {
            start_handshake(ps, err);
        }
        else if (err == SSL_ERROR_WANT_WRITE) {} /* incomplete SSL data */
        else
            handle_fatal_ssl_error(ps, err);
    }
}
Пример #2
0
/* Write some data, previously received on the secure upstream socket,
 * out of the downstream buffer and onto the backend socket */
static void back_write(struct ev_loop *loop, ev_io *w, int revents) {
    (void) revents;
    int t;
    proxystate *ps = (proxystate *)w->data;
    int fd = w->fd;
    int sz;

    assert(!ringbuffer_is_empty(&ps->ring_down));

    char *next = ringbuffer_read_next(&ps->ring_down, &sz);
    t = send(fd, next, sz, MSG_NOSIGNAL);

    if (t > 0) {
        if (t == sz) {
            ringbuffer_read_pop(&ps->ring_down);
            safe_enable_io(ps, &ps->ev_r_up);
            if (ringbuffer_is_empty(&ps->ring_down)) {
                if (ps->want_shutdown) {
                    shutdown_proxy(ps, SHUTDOWN_HARD);
                    return; // dealloc'd
                }
                ev_io_stop(loop, &ps->ev_w_down);
            }
        }
        else {
            ringbuffer_read_skip(&ps->ring_down, t);
        }
    }
    else {
        assert(t == -1);
        handle_socket_errno(ps);
    }
}
Пример #3
0
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);
}
Пример #4
0
void ringbuffer_read_pop(ringbuffer* rb) {
  size_t avail;

  avail = RB_BUF_SIZE(rb->read_head);
  ringbuffer_read_skip(rb, avail);
}
Пример #5
0
void bud_client_send_cb(uv_write_t* req, int status) {
  bud_client_t* client;
  bud_client_error_t cerr;
  bud_client_side_t* side;
  bud_client_side_t* opposite;

  /* Closing, ignore */
  if (status == UV_ECANCELED)
    return;

  client = req->data;

  if (req == &client->frontend.write_req) {
    side = &client->frontend;
    opposite = &client->backend;
  } else {
    side = &client->backend;
    opposite = &client->frontend;
  }

  if (status != 0) {
    side->write = kBudProgressDone;
    bud_client_close(
        client,
        bud_client_error(bud_error_num(kBudErrClientWriteCb, status), side));
    return;
  }

  /* Consume written data */
  DBG(side, "write_cb => %d", side->write_size);
  ringbuffer_read_skip(&side->output, side->write_size);

  /* Skip data in xforward parser */
  if (side == &client->backend)
    bud_client_xforward_skip(client, side->write_size);

  side->write = kBudProgressNone;
  side->write_size = 0;

  if (opposite->reading == kBudProgressNone) {
    if ((client->retry == kBudProgressRunning ||
         client->connect == kBudProgressRunning) &&
        opposite == &client->backend) {
      /* Set reading mark on backend to resume it after reconnecting */
      opposite->reading = kBudProgressRunning;
    } else if (opposite->close != kBudProgressDone &&
               side->close != kBudProgressDone &&
               side->shutdown != kBudProgressDone &&
               !ringbuffer_is_full(&side->output)) {
      DBG_LN(opposite, "read_start");
      cerr = bud_client_read_start(client, opposite);
      if (!bud_is_ok(cerr.err))
        return bud_client_close(client, cerr);
      opposite->reading = kBudProgressRunning;
    }
  }

  /* Cycle again */
  cerr = bud_client_cycle(client);
  if (!bud_is_ok(cerr.err))
    return bud_client_close(client, cerr);

  if (side->close == kBudProgressRunning ||
      side->shutdown == kBudProgressRunning) {
    if (!ringbuffer_is_empty(&side->output))
      return;

    /* No new data, destroy or shutdown */
    if (side->shutdown == kBudProgressRunning) {
      cerr = bud_client_shutdown(client, side);
      if (!bud_is_ok(cerr.err))
        bud_client_close(client, cerr);
      return;
    }
    bud_client_close(client, bud_client_ok(side));
  }
}
Пример #6
0
bud_client_error_t bud_client_send(bud_client_t* client,
                                   bud_client_side_t* side) {
  char* out[RING_BUFFER_COUNT];
  uv_buf_t buf[RING_BUFFER_COUNT];
  uv_buf_t* pbuf;
  size_t size[ARRAY_SIZE(out)];
  size_t count;
  size_t i;
  int r;
  bud_client_error_t cerr;

  /* Already writing */
  if (side->write != kBudProgressNone)
    goto done;

  /* If client is closed - stop sending */
  if (client->close == kBudProgressDone)
    goto done;

  /* Backend still connecting */
  if (side == &client->backend && client->connect != kBudProgressDone)
    goto done;

  count = ARRAY_SIZE(out);
  side->write_size = ringbuffer_read_nextv(&side->output, out, size, &count);
  if (side->write_size == 0)
    goto done;

  DBG(side, "uv_write(%ld) iovcnt: %ld", side->write_size, count);

  side->write_req.data = client;
  for (i = 0; i < count; i++)
    buf[i] = uv_buf_init(out[i], size[i]);

  /* Try writing without queueing first */
  r = uv_try_write((uv_stream_t*) &side->tcp, buf, count);
  ASSERT((r >= 0 && (size_t) r <= side->write_size) || r < 0,
         "Value returned by uv_try_write is OOB");

  /* Fully written */
  if (r == (int) side->write_size) {
    DBG_LN(side, "immediate write");

    /* NOTE: not causing recursion */
    bud_client_send_cb(&side->write_req, 0);
    goto done;
  } if (r == UV_ENOSYS || r == UV_EAGAIN) {
    /* Not supported try_write */
    r = 0;
  } else if (r < 0) {
    cerr = bud_client_error(bud_error_num(kBudErrClientTryWrite, r), side);
    goto fatal;
  }

  /* Skip partially written bytes */
  ringbuffer_read_skip(&side->output, r);

  /* Partially written */
  side->write_size -= r;
  pbuf = buf;
  for (; r > 0; pbuf++, count--) {
    if ((int) pbuf->len > r) {
      /* Split */
      pbuf->base += r;
      pbuf->len -= r;
      r = 0;
      break;
    } else {
      r -= pbuf->len;
    }
  }
  DBG(side, "async uv_write(%ld) follow up: %ld", side->write_size, count);

  r = uv_write(&side->write_req,
               (uv_stream_t*) &side->tcp,
               pbuf,
               count,
               bud_client_send_cb);
  if (r != 0) {
    cerr = bud_client_error(bud_error_num(kBudErrClientWrite, r), side);
    goto fatal;
  }

  DBG_LN(side, "queued write");
  side->write = kBudProgressRunning;

done:
  return bud_client_ok(side);

fatal:
  side->write = kBudProgressDone;
  return cerr;
}
Пример #7
0
Файл: test.c Проект: Acconut/bud
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;
}
Пример #8
0
void ringbuffer_read_pop(ringbuffer* rb) {
  size_t avail;

  avail = rb->read_head->write_pos - rb->read_head->read_pos;
  ringbuffer_read_skip(rb, avail);
}