Пример #1
0
static void zombie_list_hard_close_all(iocp_t *iocp)
{
  pni_iocp_drain_completions(iocp);
  size_t zs = pn_list_size(iocp->zombie_list);
  for (size_t i = 0; i < zs; i++) {
    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
    if (iocpd->socket != INVALID_SOCKET) {
      closesocket(iocpd->socket);
      iocpd->socket = INVALID_SOCKET;
      iocpd->read_closed = true;
      iocpd->write_closed = true;
    }
  }
  pni_iocp_drain_completions(iocp);

  // Zombies should be all gone.  Do a sanity check.
  zs = pn_list_size(iocp->zombie_list);
  int remaining = 0;
  int ops = 0;
  for (size_t i = 0; i < zs; i++) {
    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
    remaining++;
    ops += iocpd->ops_in_progress;
  }
  if (remaining)
    iocp_log("Proton: %d unfinished close operations (ops count = %d)\n", remaining, ops);
}
Пример #2
0
void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable)
{
  assert(selector);
  assert(selectable);

  int idx = pni_selectable_get_index(selectable);
  assert(idx >= 0);
  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);
  if (iocpd) {
    if (selector->current_triggered == iocpd)
      selector->current_triggered = iocpd->triggered_list_next;
    interests_update(iocpd, 0);
    deadlines_update(iocpd, 0);
    assert(selector->triggered_list_head != iocpd && !iocpd->triggered_list_prev);
    assert(selector->deadlines_head != iocpd && !iocpd->deadlines_prev);
    iocpd->selector = NULL;
    iocpd->selectable = NULL;
  }
  pn_list_del(selector->selectables, idx, 1);
  pn_list_del(selector->iocp_descriptors, idx, 1);
  size_t size = pn_list_size(selector->selectables);
  for (size_t i = idx; i < size; i++) {
    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(selector->selectables, i);
    pni_selectable_set_index(sel, i);
  }

  pni_selectable_set_index(selectable, -1);

  if (selector->current >= (size_t) idx) {
    selector->current--;
  }
}
Пример #3
0
void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
{
  // A selectable's fd may switch from PN_INVALID_SCOKET to a working socket between
  // update calls.  If a selectable without a valid socket has a deadline, we need
  // a dummy iocpdesc_t to participate in the deadlines list.
  int idx = pni_selectable_get_index(selectable);
  assert(idx >= 0);
  pn_timestamp_t deadline = pn_selectable_get_deadline(selectable);
  pn_socket_t sock = pn_selectable_get_fd(selectable);
  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);

  if (!iocpd && deadline && sock == PN_INVALID_SOCKET) {
    iocpd = pni_deadline_desc(selector->iocp);
    assert(iocpd);
    pn_list_set(selector->iocp_descriptors, idx, iocpd);
    pn_decref(iocpd);  // life is solely tied to iocp_descriptors list
    iocpd->selector = selector;
    iocpd->selectable = selectable;
  }
  else if (iocpd && iocpd->deadline_desc && sock != PN_INVALID_SOCKET) {
    // Switching to a real socket.  Stop using a deadline descriptor.
    deadlines_update(iocpd, 0);
    // decref descriptor in list and pick up a real iocpd below
    pn_list_set(selector->iocp_descriptors, idx, NULL);
    iocpd = NULL;
  }

  // The selectables socket may be set long after it has been added
  if (!iocpd && sock != PN_INVALID_SOCKET) {
    iocpd = pni_iocpdesc_map_get(selector->iocp, sock);
    if (!iocpd) {
      // Socket created outside proton.  Hook it up to iocp.
      iocpd = pni_iocpdesc_create(selector->iocp, sock, true);
      assert(iocpd);
      if (iocpd)
        pni_iocpdesc_start(iocpd);
    }
    if (iocpd) {
      pn_list_set(selector->iocp_descriptors, idx, iocpd);
      iocpd->selector = selector;
      iocpd->selectable = selectable;
    }
  }

  if (iocpd) {
    assert(sock == iocpd->socket || iocpd->closing);
    int interests = PN_ERROR; // Always
    if (pn_selectable_is_reading(selectable)) {
      interests |= PN_READABLE;
    }
    if (pn_selectable_is_writing(selectable)) {
      interests |= PN_WRITABLE;
    }
    if (deadline) {
      interests |= PN_EXPIRED;
    }
    interests_update(iocpd, interests);
    deadlines_update(iocpd, deadline);
  }
}
Пример #4
0
int pn_transform_apply(pn_transform_t *transform, const char *src,
                       pn_string_t *dst)
{
    for (size_t i = 0; i < pn_list_size(transform->rules); i++)
    {
        pn_rule_t *rule = (pn_rule_t *) pn_list_get(transform->rules, i);
        if (pni_match(&transform->matcher, pn_string_get(rule->pattern), src)) {
            transform->matched = true;
            if (!pn_string_get(rule->substitution)) {
                return pn_string_set(dst, NULL);
            }

            while (true) {
                size_t capacity = pn_string_capacity(dst);
                size_t n = pni_substitute(&transform->matcher,
                                          pn_string_get(rule->substitution),
                                          pn_string_buffer(dst), capacity);
                int err = pn_string_resize(dst, n);
                if (err) return err;
                if (n <= capacity) {
                    return 0;
                }
            }
        }
    }

    transform->matched = false;
    return pn_string_set(dst, src);
}
Пример #5
0
pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error)
{
  if (!is_listener(ld)) {
    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
    return INVALID_SOCKET;
  }
  if (ld->read_closed) {
    set_iocp_error_status(error, PN_ERR, WSAENOTSOCK);
    return INVALID_SOCKET;
  }
  if (pn_list_size(ld->acceptor->accepts) == 0) {
    if (ld->events & PN_READABLE && ld->iocp->iocp_trace)
      iocp_log("listen socket readable with no available accept completions\n");
    *would_block = true;
    return INVALID_SOCKET;
  }

  accept_result_t *result = (accept_result_t *) pn_list_get(ld->acceptor->accepts, 0);
  pn_list_del(ld->acceptor->accepts, 0, 1);
  if (!pn_list_size(ld->acceptor->accepts))
    pni_events_update(ld, ld->events & ~PN_READABLE);  // No pending accepts

  pn_socket_t accept_sock;
  if (result->base.status) {
    accept_sock = INVALID_SOCKET;
    pni_win32_error(ld->error, "accept failure", result->base.status);
    if (ld->iocp->iocp_trace)
      iocp_log("%s\n", pn_error_text(ld->error));
    // App never sees this socket so close it here.
    pni_iocp_begin_close(result->new_sock);
  } else {
    accept_sock = result->new_sock->socket;
    // AcceptEx special setsockopt:
    setsockopt(accept_sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&ld->socket,
                  sizeof (SOCKET));
    if (addr && addrlen && *addrlen > 0) {
      sockaddr_storage *local_addr = NULL;
      sockaddr_storage *remote_addr = NULL;
      int local_addrlen, remote_addrlen;
      LPFN_GETACCEPTEXSOCKADDRS fn = ld->acceptor->fn_get_accept_ex_sockaddrs;
      fn(result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
         (SOCKADDR **) &local_addr, &local_addrlen, (SOCKADDR **) &remote_addr,
         &remote_addrlen);
      *addrlen = pn_min(*addrlen, remote_addrlen);
      memmove(addr, remote_addr, *addrlen);
    }
  }

  if (accept_sock != INVALID_SOCKET) {
    // Connected.
    result->new_sock->read_closed = false;
    result->new_sock->write_closed = false;
  }

  // Done with the completion result, so reuse it
  result->new_sock = NULL;
  begin_accept(ld->acceptor, result);
  return accept_sock;
}
Пример #6
0
pn_timestamp_t pni_zombie_deadline(iocp_t *iocp)
{
  if (pn_list_size(iocp->zombie_list)) {
    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, 0);
    return iocpd->reap_time;
  }
  return 0;
}
Пример #7
0
static void pni_acceptor_finalize(void *object)
{
  pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
  size_t len = pn_list_size(acceptor->accepts);
  for (size_t i = 0; i < len; i++)
    free(pn_list_get(acceptor->accepts, i));
  pn_free(acceptor->accepts);
}
Пример #8
0
static void *pn_it_next(void *state) {
  pn_it_state_t *it = (pn_it_state_t *) state;
  if (it->index < pn_list_size(it->list)) {
    return pn_list_get(it->list, it->index++);
  } else {
    return NULL;
  }
}
Пример #9
0
static void pn_list_finalize(void *object)
{
  assert(object);
  pn_list_t *list = (pn_list_t *) object;
  for (size_t i = 0; i < list->size; i++) {
    pn_class_decref(list->clazz, pn_list_get(list, i));
  }
  free(list->elements);
}
Пример #10
0
static void *pni_list_next(void *ctx)
{
  pni_list_iter_t *iter = (pni_list_iter_t *) ctx;
  if (iter->index < pn_list_size(iter->list)) {
    return pn_list_get(iter->list, iter->index++);
  } else {
    return NULL;
  }
}
Пример #11
0
static intptr_t pn_list_compare(void *oa, void *ob)
{
  assert(oa); assert(ob);
  pn_list_t *a = (pn_list_t *) oa;
  pn_list_t *b = (pn_list_t *) ob;

  size_t na = pn_list_size(a);
  size_t nb = pn_list_size(b);
  if (na != nb) {
    return nb - na;
  } else {
    for (size_t i = 0; i < na; i++) {
      intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i));
      if (delta) return delta;
    }
  }

  return 0;
}
Пример #12
0
static void test_build_list(void)
{
  pn_list_t *l = build_list(0,
                            pn_string("one"),
                            pn_string("two"),
                            pn_string("three"),
                            END);

  assert(pn_list_size(l) == 3);

  assert(pn_strequals(pn_string_get((pn_string_t *) pn_list_get(l, 0)),
                      "one"));
  assert(pn_strequals(pn_string_get((pn_string_t *) pn_list_get(l, 1)),
                      "two"));
  assert(pn_strequals(pn_string_get((pn_string_t *) pn_list_get(l, 2)),
                      "three"));

  pn_free(l);
}
Пример #13
0
static uintptr_t pn_list_hashcode(void *object)
{
  assert(object);
  pn_list_t *list = (pn_list_t *) object;
  uintptr_t hash = 1;

  for (size_t i = 0; i < list->size; i++) {
    hash = hash * 31 + pn_hashcode(pn_list_get(list, i));
  }

  return hash;
}
Пример #14
0
void global_shutdown(global_context_t *gc)
{
  if (gc->shutting_down) return;
  gc->shutting_down = true;
  pn_acceptor_close(gc->acceptor);
  size_t n = pn_list_size(gc->active_connections);
  for (size_t i = 0; i < n; i++) {
    pn_connection_t *conn = (pn_connection_t *) pn_list_get(gc->active_connections, i);
    if (!(pn_connection_state(conn) & PN_LOCAL_CLOSED)) {
      pn_connection_close(conn);
    }
  }
}
Пример #15
0
static void test_map_iteration(int n)
{
  pn_list_t *pairs = pn_list(PN_OBJECT, 2*n);
  for (int i = 0; i < n; i++) {
    void *key = pn_class_new(PN_OBJECT, 0);
    void *value = pn_class_new(PN_OBJECT, 0);
    pn_list_add(pairs, key);
    pn_list_add(pairs, value);
    pn_decref(key);
    pn_decref(value);
  }

  pn_map_t *map = pn_map(PN_OBJECT, PN_OBJECT, 0, 0.75);

  assert(pn_map_head(map) == 0);

  for (int i = 0; i < n; i++) {
    pn_map_put(map, pn_list_get(pairs, 2*i), pn_list_get(pairs, 2*i + 1));
  }

  for (pn_handle_t entry = pn_map_head(map); entry; entry = pn_map_next(map, entry))
  {
    void *key = pn_map_key(map, entry);
    void *value = pn_map_value(map, entry);
    ssize_t idx = pn_list_index(pairs, key);
    assert(idx >= 0);

    assert(pn_list_get(pairs, idx) == key);
    assert(pn_list_get(pairs, idx + 1) == value);

    pn_list_del(pairs, idx, 2);
  }

  assert(pn_list_size(pairs) == 0);

  pn_decref(map);
  pn_decref(pairs);
}
Пример #16
0
static int pn_list_inspect(void *obj, pn_string_t *dst)
{
  assert(obj);
  pn_list_t *list = (pn_list_t *) obj;
  int err = pn_string_addf(dst, "[");
  if (err) return err;
  size_t n = pn_list_size(list);
  for (size_t i = 0; i < n; i++) {
    if (i > 0) {
      err = pn_string_addf(dst, ", ");
      if (err) return err;
    }
    err = pn_class_inspect(list->clazz, pn_list_get(list, i), dst);
    if (err) return err;
  }
  return pn_string_addf(dst, "]");
}
Пример #17
0
static void test_list_refcount(size_t capacity)
{
  void *one = pn_class_new(PN_OBJECT, 0);
  void *two = pn_class_new(PN_OBJECT, 0);
  void *three = pn_class_new(PN_OBJECT, 0);
  void *four = pn_class_new(PN_OBJECT, 0);

  pn_list_t *list = pn_list(PN_OBJECT, 0);
  assert(!pn_list_add(list, one));
  assert(!pn_list_add(list, two));
  assert(!pn_list_add(list, three));
  assert(!pn_list_add(list, four));
  assert(pn_list_get(list, 0) == one);
  assert(pn_list_get(list, 1) == two);
  assert(pn_list_get(list, 2) == three);
  assert(pn_list_get(list, 3) == four);
  assert(pn_list_size(list) == 4);

  assert(pn_refcount(one) == 2);
  assert(pn_refcount(two) == 2);
  assert(pn_refcount(three) == 2);
  assert(pn_refcount(four) == 2);

  pn_list_del(list, 1, 2);
  assert(pn_list_size(list) == 2);

  assert(pn_refcount(one) == 2);
  assert(pn_refcount(two) == 1);
  assert(pn_refcount(three) == 1);
  assert(pn_refcount(four) == 2);

  assert(pn_list_get(list, 0) == one);
  assert(pn_list_get(list, 1) == four);

  assert(!pn_list_add(list, one));

  assert(pn_list_size(list) == 3);
  assert(pn_refcount(one) == 3);

  pn_decref(list);

  assert(pn_refcount(one) == 1);
  assert(pn_refcount(two) == 1);
  assert(pn_refcount(three) == 1);
  assert(pn_refcount(four) == 1);

  pn_decref(one);
  pn_decref(two);
  pn_decref(three);
  pn_decref(four);
}
Пример #18
0
void pni_zombie_check(iocp_t *iocp, pn_timestamp_t now)
{
  pn_list_t *zl = iocp->zombie_list;
  // Look for stale zombies that should have been reaped by "now"
  for (size_t idx = 0; idx < pn_list_size(zl); idx++) {
    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(zl, idx);
    if (iocpd->reap_time > now)
      return;
    if (iocpd->socket == INVALID_SOCKET)
      continue;
    assert(iocpd->ops_in_progress > 0);
    if (iocp->iocp_trace)
      iocp_log("async close: graceful close timeout exceeded\n");
    closesocket(iocpd->socket);
    iocpd->socket = INVALID_SOCKET;
    iocpd->read_closed = true;
    // outstanding ops should complete immediately now
  }
}
Пример #19
0
static void drain_zombie_completions(iocp_t *iocp)
{
  // No more pn_selector_select() from App, but zombies still need care and feeding
  // until their outstanding async actions complete.
  pni_iocp_drain_completions(iocp);

  // Discard any that have no pending async IO
  size_t sz = pn_list_size(iocp->zombie_list);
  for (size_t idx = 0; idx < sz;) {
    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, idx);
    if (!iocpd->ops_in_progress) {
      pn_list_del(iocp->zombie_list, idx, 1);
      sz--;
    } else {
      idx++;
    }
  }

  unsigned shutdown_grace = 2000;
  char *override = getenv("PN_SHUTDOWN_GRACE");
  if (override) {
    int grace = atoi(override);
    if (grace > 0 && grace < 60000)
      shutdown_grace = (unsigned) grace;
  }
  pn_timestamp_t now = pn_i_now();
  pn_timestamp_t deadline = now + shutdown_grace;

  while (pn_list_size(iocp->zombie_list)) {
    if (now >= deadline)
      break;
    int rv = pni_iocp_wait_one(iocp, deadline - now, NULL);
    if (rv < 0) {
      iocp_log("unexpected IOCP failure on Proton IO shutdown %d\n", GetLastError());
      break;
    }
    now = pn_i_now();
  }
  if (now >= deadline && pn_list_size(iocp->zombie_list) && iocp->iocp_trace)
    // Should only happen if really slow TCP handshakes, i.e. total network failure
    iocp_log("network failure on Proton shutdown\n");
}
Пример #20
0
void test_iterator(void)
{
  pn_list_t *list = build_list(0,
                               pn_string("one"),
                               pn_string("two"),
                               pn_string("three"),
                               pn_string("four"),
                               END);
  pn_iterator_t *it = pn_iterator();
  pn_it_state_t *state = (pn_it_state_t *) pn_iterator_start
    (it, pn_it_next, sizeof(pn_it_state_t));
  state->list = list;
  state->index = 0;

  void *obj;
  int index = 0;
  while ((obj = pn_iterator_next(it))) {
    assert(obj == pn_list_get(list, index++));
  }
  assert(index == 4);

  pn_free(list);
  pn_free(it);
}
Пример #21
0
static void test_list(size_t capacity)
{
  pn_list_t *list = pn_list(PN_WEAKREF, 0);
  assert(pn_list_size(list) == 0);
  assert(!pn_list_add(list, (void *) 0));
  assert(!pn_list_add(list, (void *) 1));
  assert(!pn_list_add(list, (void *) 2));
  assert(!pn_list_add(list, (void *) 3));
  assert(pn_list_get(list, 0) == (void *) 0);
  assert(pn_list_get(list, 1) == (void *) 1);
  assert(pn_list_get(list, 2) == (void *) 2);
  assert(pn_list_get(list, 3) == (void *) 3);
  assert(pn_list_size(list) == 4);
  pn_list_del(list, 1, 2);
  assert(pn_list_size(list) == 2);
  assert(pn_list_get(list, 0) == (void *) 0);
  assert(pn_list_get(list, 1) == (void *) 3);
  pn_decref(list);
}