Beispiel #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);
}
Beispiel #2
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;
}
Beispiel #3
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);
}
Beispiel #4
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--;
  }
}
Beispiel #5
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);
}
Beispiel #6
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;
  }
}
Beispiel #7
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;
}
Beispiel #8
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);
}
Beispiel #9
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;
  }
}
Beispiel #10
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);
}
Beispiel #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;
}
Beispiel #12
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");
}
Beispiel #13
0
void test_heap(int seed, int size)
{
  srand(seed);
  pn_list_t *list = pn_list(PN_VOID, 0);

  intptr_t min = 0;
  intptr_t max = 0;

  for (int i = 0; i < size; i++) {
    intptr_t r = rand();

    if (i == 0) {
      min = r;
      max = r;
    } else {
      if (r < min) {
        min = r;
      }
      if (r > max) {
        max = r;
      }
    }

    pn_list_minpush(list, (void *) r);
  }

  intptr_t prev = (intptr_t) pn_list_minpop(list);
  assert(prev == min);
  assert(pn_list_size(list) == (size_t)(size - 1));
  int count = 0;
  while (pn_list_size(list)) {
    intptr_t r = (intptr_t) pn_list_minpop(list);
    assert(r >= prev);
    prev = r;
    count++;
  }
  assert(count == size - 1);
  assert(prev == max);

  pn_free(list);
}
Beispiel #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);
    }
  }
}
Beispiel #15
0
static void begin_accept(pni_acceptor_t *acceptor, accept_result_t *result)
{
  if (acceptor->listen_sock->closing) {
    if (result) {
      free(result);
      acceptor->accept_queue_size--;
    }
    if (acceptor->accept_queue_size == 0)
      acceptor->signalled = true;
    return;
  }

  if (result) {
    reset_accept_result(result);
  } else {
    if (acceptor->accept_queue_size < IOCP_MAX_ACCEPTS &&
        pn_list_size(acceptor->accepts) == acceptor->accept_queue_size ) {
      result = accept_result(acceptor->listen_sock);
      acceptor->accept_queue_size++;
    } else {
      // an async accept is still pending or max concurrent accepts already hit
      return;
    }
  }

  result->new_sock = create_same_type_socket(acceptor->listen_sock);
  if (result->new_sock) {
    // Not yet connected.
    result->new_sock->read_closed = true;
    result->new_sock->write_closed = true;

    bool success = acceptor->fn_accept_ex(acceptor->listen_sock->socket, result->new_sock->socket,
                     result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
                     &result->unused, (LPOVERLAPPED) result);
    if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
      result->base.status = WSAGetLastError();
      pn_list_add(acceptor->accepts, result);
      pni_events_update(acceptor->listen_sock, acceptor->listen_sock->events | PN_READABLE);
    } else {
      acceptor->listen_sock->ops_in_progress++;
      // This socket is equally involved in the async operation.
      result->new_sock->ops_in_progress++;
    }
  } else {
    iocpdesc_fail(acceptor->listen_sock, WSAGetLastError(), "create accept socket");
  }
}
Beispiel #16
0
void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
{
  assert(selector);
  assert(selectable);
  assert(pni_selectable_get_index(selectable) < 0);
  pn_socket_t sock = pn_selectable_get_fd(selectable);
  iocpdesc_t *iocpd = NULL;

  if (pni_selectable_get_index(selectable) < 0) {
    pn_list_add(selector->selectables, selectable);
    pn_list_add(selector->iocp_descriptors, NULL);
    size_t size = pn_list_size(selector->selectables);
    pni_selectable_set_index(selectable, size - 1);
  }

  pn_selector_update(selector, selectable);
}
Beispiel #17
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, "]");
}
Beispiel #18
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);
}
Beispiel #19
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
  }
}
Beispiel #20
0
void pni_iocp_finalize(void *obj)
{
  iocp_t *iocp = (iocp_t *) obj;
  // Move sockets to closed state, except external sockets.
  pn_list_t *externals = iocp_map_close_all(iocp);
  // Now everything with ops_in_progress is in the zombie_list or the externals list.
  assert(!pn_hash_head(iocp->iocpdesc_map));
  pn_free(iocp->iocpdesc_map);

  drain_zombie_completions(iocp);    // Last chance for graceful close
  zombie_list_hard_close_all(iocp);
  CloseHandle(iocp->completion_port);  // This cancels all our async ops
  iocp->completion_port = NULL;

  if (pn_list_size(externals) && iocp->iocp_trace)
    iocp_log("%d external sockets not closed and removed from Proton IOCP control\n", pn_list_size(externals));

  // Now safe to free everything that might be touched by a former async operation.
  pn_free(externals);
  pn_free(iocp->zombie_list);
  pni_shared_pool_free(iocp);
}
Beispiel #21
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);
}
Beispiel #22
0
void *pn_list_minpop(pn_list_t *list)
{
  assert(list);
  // we use one based indexing for the heap
  void **heap = list->elements - 1;
  void *min = heap[1];
  void *last = pn_list_pop(list);
  int size = pn_list_size(list);
  int now, child;
  for (now = 1; now*2 <= size; now = child) {
    child = now*2;
    if (child != size && pn_class_compare(list->clazz, heap[child], heap[child + 1]) > 0) {
      child++;
    }
    if (pn_class_compare(list->clazz, last, heap[child]) > 0) {
      heap[now] = heap[child];
    } else {
      break;
    }
  }
  heap[now] = last;
  return min;
}
Beispiel #23
0
size_t pn_selector_size(pn_selector_t *selector) {
  assert(selector);
  return pn_list_size(selector->selectables);
}