You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2016/11/14 18:28:22 UTC
[01/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Repository: qpid-proton
Updated Branches:
refs/heads/master efd033c98 -> eac0bb663
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/selector.c b/proton-c/src/windows/selector.c
deleted file mode 100644
index f139aec..0000000
--- a/proton-c/src/windows/selector.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/object.h>
-#include <proton/io.h>
-#include <proton/selector.h>
-#include <proton/error.h>
-#include <assert.h>
-#include "selectable.h"
-#include "util.h"
-#include "iocp.h"
-
-static void interests_update(iocpdesc_t *iocpd, int interests);
-static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t t);
-
-struct pn_selector_t {
- iocp_t *iocp;
- pn_list_t *selectables;
- pn_list_t *iocp_descriptors;
- size_t current;
- iocpdesc_t *current_triggered;
- pn_timestamp_t awoken;
- pn_error_t *error;
- iocpdesc_t *triggered_list_head;
- iocpdesc_t *triggered_list_tail;
- iocpdesc_t *deadlines_head;
- iocpdesc_t *deadlines_tail;
-};
-
-void pn_selector_initialize(void *obj)
-{
- pn_selector_t *selector = (pn_selector_t *) obj;
- selector->iocp = NULL;
- selector->selectables = pn_list(PN_WEAKREF, 0);
- selector->iocp_descriptors = pn_list(PN_OBJECT, 0);
- selector->current = 0;
- selector->current_triggered = NULL;
- selector->awoken = 0;
- selector->error = pn_error();
- selector->triggered_list_head = NULL;
- selector->triggered_list_tail = NULL;
- selector->deadlines_head = NULL;
- selector->deadlines_tail = NULL;
-}
-
-void pn_selector_finalize(void *obj)
-{
- pn_selector_t *selector = (pn_selector_t *) obj;
- pn_free(selector->selectables);
- pn_free(selector->iocp_descriptors);
- pn_error_free(selector->error);
- selector->iocp->selector = NULL;
-}
-
-#define pn_selector_hashcode NULL
-#define pn_selector_compare NULL
-#define pn_selector_inspect NULL
-
-pn_selector_t *pni_selector()
-{
- static const pn_class_t clazz = PN_CLASS(pn_selector);
- pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
- return selector;
-}
-
-pn_selector_t *pni_selector_create(iocp_t *iocp)
-{
- pn_selector_t *selector = pni_selector();
- selector->iocp = iocp;
- return selector;
-}
-
-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);
-}
-
-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);
- }
-}
-
-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--;
- }
-}
-
-size_t pn_selector_size(pn_selector_t *selector) {
- assert(selector);
- return pn_list_size(selector->selectables);
-}
-
-int pn_selector_select(pn_selector_t *selector, int timeout)
-{
- assert(selector);
- pn_error_clear(selector->error);
- pn_timestamp_t deadline = 0;
- pn_timestamp_t now = pn_i_now();
-
- if (timeout) {
- if (selector->deadlines_head)
- deadline = selector->deadlines_head->deadline;
- }
- if (deadline) {
- int64_t delta = deadline - now;
- if (delta < 0) {
- delta = 0;
- }
- if (timeout < 0)
- timeout = delta;
- else if (timeout > delta)
- timeout = delta;
- }
- deadline = (timeout >= 0) ? now + timeout : 0;
-
- // Process all currently available completions, even if matched events available
- pni_iocp_drain_completions(selector->iocp);
- pni_zombie_check(selector->iocp, now);
- // Loop until an interested event is matched, or until deadline
- while (true) {
- if (selector->triggered_list_head)
- break;
- if (deadline && deadline <= now)
- break;
- pn_timestamp_t completion_deadline = deadline;
- pn_timestamp_t zd = pni_zombie_deadline(selector->iocp);
- if (zd)
- completion_deadline = completion_deadline ? pn_min(zd, completion_deadline) : zd;
-
- int completion_timeout = (!completion_deadline) ? -1 : completion_deadline - now;
- int rv = pni_iocp_wait_one(selector->iocp, completion_timeout, selector->error);
- if (rv < 0)
- return pn_error_code(selector->error);
-
- now = pn_i_now();
- if (zd && zd <= now) {
- pni_zombie_check(selector->iocp, now);
- }
- }
-
- selector->current = 0;
- selector->awoken = now;
- for (iocpdesc_t *iocpd = selector->deadlines_head; iocpd; iocpd = iocpd->deadlines_next) {
- if (iocpd->deadline <= now)
- pni_events_update(iocpd, iocpd->events | PN_EXPIRED);
- else
- break;
- }
- selector->current_triggered = selector->triggered_list_head;
- return pn_error_code(selector->error);
-}
-
-pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
-{
- if (selector->current_triggered) {
- iocpdesc_t *iocpd = selector->current_triggered;
- *events = iocpd->interests & iocpd->events;
- selector->current_triggered = iocpd->triggered_list_next;
- return iocpd->selectable;
- }
- return NULL;
-}
-
-void pn_selector_free(pn_selector_t *selector)
-{
- assert(selector);
- pn_free(selector);
-}
-
-
-static void triggered_list_add(pn_selector_t *selector, iocpdesc_t *iocpd)
-{
- if (iocpd->triggered_list_prev || selector->triggered_list_head == iocpd)
- return; // already in list
- LL_ADD(selector, triggered_list, iocpd);
-}
-
-static void triggered_list_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
-{
- if (!iocpd->triggered_list_prev && selector->triggered_list_head != iocpd)
- return; // not in list
- LL_REMOVE(selector, triggered_list, iocpd);
- iocpd->triggered_list_prev = NULL;
- iocpd->triggered_list_next = NULL;
-}
-
-
-void pni_events_update(iocpdesc_t *iocpd, int events)
-{
- // If set, a poll error is permanent
- if (iocpd->poll_error)
- events |= PN_ERROR;
- if (iocpd->events == events)
- return;
- iocpd->events = events;
- if (iocpd->selector) {
- if (iocpd->events & iocpd->interests)
- triggered_list_add(iocpd->selector, iocpd);
- else
- triggered_list_remove(iocpd->selector, iocpd);
- }
-}
-
-static void interests_update(iocpdesc_t *iocpd, int interests)
-{
- int old_interests = iocpd->interests;
- if (old_interests == interests)
- return;
- iocpd->interests = interests;
- if (iocpd->selector) {
- if (iocpd->events & iocpd->interests)
- triggered_list_add(iocpd->selector, iocpd);
- else
- triggered_list_remove(iocpd->selector, iocpd);
- }
-}
-
-static void deadlines_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
-{
- if (!iocpd->deadlines_prev && selector->deadlines_head != iocpd)
- return; // not in list
- LL_REMOVE(selector, deadlines, iocpd);
- iocpd->deadlines_prev = NULL;
- iocpd->deadlines_next = NULL;
-}
-
-
-static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t deadline)
-{
- if (deadline == iocpd->deadline)
- return;
-
- iocpd->deadline = deadline;
- pn_selector_t *selector = iocpd->selector;
- if (!deadline) {
- deadlines_remove(selector, iocpd);
- pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
- } else {
- if (iocpd->deadlines_prev || selector->deadlines_head == iocpd) {
- deadlines_remove(selector, iocpd);
- pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
- }
- iocpdesc_t *dl_iocpd = LL_HEAD(selector, deadlines);
- while (dl_iocpd && dl_iocpd->deadline <= deadline)
- dl_iocpd = dl_iocpd->deadlines_next;
- if (dl_iocpd) {
- // insert
- iocpd->deadlines_prev = dl_iocpd->deadlines_prev;
- iocpd->deadlines_next = dl_iocpd;
- dl_iocpd->deadlines_prev = iocpd;
- if (selector->deadlines_head == dl_iocpd)
- selector->deadlines_head = iocpd;
- } else {
- LL_ADD(selector, deadlines, iocpd); // append
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/write_pipeline.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/write_pipeline.c b/proton-c/src/windows/write_pipeline.c
deleted file mode 100644
index e14e714..0000000
--- a/proton-c/src/windows/write_pipeline.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/*
- * A simple write buffer pool. Each socket has a dedicated "primary"
- * buffer and can borrow from a shared pool with limited size tuning.
- * Could enhance e.g. with separate pools per network interface and fancier
- * memory tuning based on interface speed, system resources, and
- * number of connections, etc.
- */
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/object.h>
-#include <proton/io.h>
-#include <proton/selector.h>
-#include <proton/error.h>
-#include <assert.h>
-#include "selectable.h"
-#include "util.h"
-#include "iocp.h"
-
-// Max overlapped writes per socket
-#define IOCP_MAX_OWRITES 16
-// Write buffer size
-#define IOCP_WBUFSIZE 16384
-
-static void pipeline_log(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fflush(stderr);
-}
-
-void pni_shared_pool_create(iocp_t *iocp)
-{
- // TODO: more pools (or larger one) when using multiple non-loopback interfaces
- iocp->shared_pool_size = 16;
- char *env = getenv("PNI_WRITE_BUFFERS"); // Internal: for debugging
- if (env) {
- int sz = atoi(env);
- if (sz >= 0 && sz < 256) {
- iocp->shared_pool_size = sz;
- }
- }
- iocp->loopback_bufsize = 0;
- env = getenv("PNI_LB_BUFSIZE"); // Internal: for debugging
- if (env) {
- int sz = atoi(env);
- if (sz >= 0 && sz <= 128 * 1024) {
- iocp->loopback_bufsize = sz;
- }
- }
-
- if (iocp->shared_pool_size) {
- iocp->shared_pool_memory = (char *) VirtualAlloc(NULL, IOCP_WBUFSIZE * iocp->shared_pool_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
- HRESULT status = GetLastError();
- if (!iocp->shared_pool_memory) {
- perror("Proton write buffer pool allocation failure\n");
- iocp->shared_pool_size = 0;
- iocp->shared_available_count = 0;
- return;
- }
-
- iocp->shared_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
- iocp->available_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
- iocp->shared_available_count = iocp->shared_pool_size;
- char *mem = iocp->shared_pool_memory;
- for (int i = 0; i < iocp->shared_pool_size; i++) {
- iocp->shared_results[i] = iocp->available_results[i] = pni_write_result(NULL, mem, IOCP_WBUFSIZE);
- mem += IOCP_WBUFSIZE;
- }
- }
-}
-
-void pni_shared_pool_free(iocp_t *iocp)
-{
- for (int i = 0; i < iocp->shared_pool_size; i++) {
- write_result_t *result = iocp->shared_results[i];
- if (result->in_use)
- pipeline_log("Proton buffer pool leak\n");
- else
- free(result);
- }
- if (iocp->shared_pool_size) {
- free(iocp->shared_results);
- free(iocp->available_results);
- if (iocp->shared_pool_memory) {
- if (!VirtualFree(iocp->shared_pool_memory, 0, MEM_RELEASE)) {
- perror("write buffers release failed");
- }
- iocp->shared_pool_memory = NULL;
- }
- }
-}
-
-static void shared_pool_push(write_result_t *result)
-{
- iocp_t *iocp = result->base.iocpd->iocp;
- assert(iocp->shared_available_count < iocp->shared_pool_size);
- iocp->available_results[iocp->shared_available_count++] = result;
-}
-
-static write_result_t *shared_pool_pop(iocp_t *iocp)
-{
- return iocp->shared_available_count ? iocp->available_results[--iocp->shared_available_count] : NULL;
-}
-
-struct write_pipeline_t {
- iocpdesc_t *iocpd;
- size_t pending_count;
- write_result_t *primary;
- size_t reserved_count;
- size_t next_primary_index;
- size_t depth;
- bool is_writer;
-};
-
-#define write_pipeline_compare NULL
-#define write_pipeline_inspect NULL
-#define write_pipeline_hashcode NULL
-
-static void write_pipeline_initialize(void *object)
-{
- write_pipeline_t *pl = (write_pipeline_t *) object;
- pl->pending_count = 0;
- const char *pribuf = (const char *) malloc(IOCP_WBUFSIZE);
- pl->primary = pni_write_result(NULL, pribuf, IOCP_WBUFSIZE);
- pl->depth = 0;
- pl->is_writer = false;
-}
-
-static void write_pipeline_finalize(void *object)
-{
- write_pipeline_t *pl = (write_pipeline_t *) object;
- free((void *)pl->primary->buffer.start);
- free(pl->primary);
-}
-
-write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd)
-{
- static const pn_cid_t CID_write_pipeline = CID_pn_void;
- static const pn_class_t clazz = PN_CLASS(write_pipeline);
- write_pipeline_t *pipeline = (write_pipeline_t *) pn_class_new(&clazz, sizeof(write_pipeline_t));
- pipeline->iocpd = iocpd;
- pipeline->primary->base.iocpd = iocpd;
- return pipeline;
-}
-
-static void confirm_as_writer(write_pipeline_t *pl)
-{
- if (!pl->is_writer) {
- iocp_t *iocp = pl->iocpd->iocp;
- iocp->writer_count++;
- pl->is_writer = true;
- }
-}
-
-static void remove_as_writer(write_pipeline_t *pl)
-{
- if (!pl->is_writer)
- return;
- iocp_t *iocp = pl->iocpd->iocp;
- assert(iocp->writer_count);
- pl->is_writer = false;
- iocp->writer_count--;
-}
-
-/*
- * Optimal depth will depend on properties of the NIC, server, and driver. For now,
- * just distinguish between loopback interfaces and the rest. Optimizations in the
- * loopback stack allow decent performance with depth 1 and actually cause major
- * performance hiccups if set to large values.
- */
-static void set_depth(write_pipeline_t *pl)
-{
- pl->depth = 1;
- sockaddr_storage sa;
- socklen_t salen = sizeof(sa);
- char buf[INET6_ADDRSTRLEN];
- DWORD buflen = sizeof(buf);
-
- if (getsockname(pl->iocpd->socket,(sockaddr*) &sa, &salen) == 0 &&
- getnameinfo((sockaddr*) &sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0) {
- if ((sa.ss_family == AF_INET6 && strcmp(buf, "::1")) ||
- (sa.ss_family == AF_INET && strncmp(buf, "127.", 4))) {
- // not loopback
- pl->depth = IOCP_MAX_OWRITES;
- } else {
- iocp_t *iocp = pl->iocpd->iocp;
- if (iocp->loopback_bufsize) {
- const char *p = (const char *) realloc((void *) pl->primary->buffer.start, iocp->loopback_bufsize);
- if (p) {
- pl->primary->buffer.start = p;
- pl->primary->buffer.size = iocp->loopback_bufsize;
- }
- }
- }
- }
-}
-
-// Reserve as many buffers as possible for count bytes.
-size_t pni_write_pipeline_reserve(write_pipeline_t *pl, size_t count)
-{
- if (pl->primary->in_use)
- return 0; // I.e. io->wouldblock
- if (!pl->depth)
- set_depth(pl);
- if (pl->depth == 1) {
- // always use the primary
- pl->reserved_count = 1;
- pl->next_primary_index = 0;
- return 1;
- }
-
- iocp_t *iocp = pl->iocpd->iocp;
- confirm_as_writer(pl);
- size_t wanted = (count / IOCP_WBUFSIZE);
- if (count % IOCP_WBUFSIZE)
- wanted++;
- size_t pending = pl->pending_count;
- assert(pending < pl->depth);
- size_t bufs = pn_min(wanted, pl->depth - pending);
- // Can draw from shared pool or the primary... but share with others.
- size_t writers = iocp->writer_count;
- size_t shared_count = (iocp->shared_available_count + writers - 1) / writers;
- bufs = pn_min(bufs, shared_count + 1);
- pl->reserved_count = pending + bufs;
-
- if (bufs == wanted &&
- pl->reserved_count < (pl->depth / 2) &&
- iocp->shared_available_count > (2 * writers + bufs)) {
- // No shortage: keep the primary as spare for future use
- pl->next_primary_index = pl->reserved_count;
- } else if (bufs == 1) {
- pl->next_primary_index = pending;
- } else {
- // let approx 1/3 drain before replenishing
- pl->next_primary_index = ((pl->reserved_count + 2) / 3) - 1;
- if (pl->next_primary_index < pending)
- pl->next_primary_index = pending;
- }
- return bufs;
-}
-
-write_result_t *pni_write_pipeline_next(write_pipeline_t *pl)
-{
- size_t sz = pl->pending_count;
- if (sz >= pl->reserved_count)
- return NULL;
- write_result_t *result;
- if (sz == pl->next_primary_index) {
- result = pl->primary;
- } else {
- assert(pl->iocpd->iocp->shared_available_count > 0);
- result = shared_pool_pop(pl->iocpd->iocp);
- }
-
- result->in_use = true;
- pl->pending_count++;
- return result;
-}
-
-void pni_write_pipeline_return(write_pipeline_t *pl, write_result_t *result)
-{
- result->in_use = false;
- pl->pending_count--;
- pl->reserved_count = 0;
- if (result != pl->primary)
- shared_pool_push(result);
- if (pl->pending_count == 0)
- remove_as_writer(pl);
-}
-
-bool pni_write_pipeline_writable(write_pipeline_t *pl)
-{
- // Only writable if not full and we can guarantee a buffer:
- return pl->pending_count < pl->depth && !pl->primary->in_use;
-}
-
-size_t pni_write_pipeline_size(write_pipeline_t *pl)
-{
- return pl->pending_count;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/tools/cmake/Modules/WindowsC99SymbolCheck.py
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/WindowsC99SymbolCheck.py b/tools/cmake/Modules/WindowsC99SymbolCheck.py
index 8e81ad9..7c2c9f2 100644
--- a/tools/cmake/Modules/WindowsC99SymbolCheck.py
+++ b/tools/cmake/Modules/WindowsC99SymbolCheck.py
@@ -53,7 +53,7 @@ def symcheck(objfile):
m = re.search(r'UNDEF.*\b([a-zA-Z_]*snprintf)\b', line)
if m :
sym = m.group(1)
- if re.match(r'_*pn_i_v?snprintf', sym) is None :
+ if re.match(r'_*pni_v?snprintf', sym) is None :
raise Exception('Unsafe use of C99 violating function in ' + objfile + ' : ' + sym)
def main():
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[04/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
deleted file mode 100644
index cdecfd2..0000000
--- a/proton-c/src/transport/transport.c
+++ /dev/null
@@ -1,3018 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "engine/engine-internal.h"
-#include "framing/framing.h"
-#include "sasl/sasl-internal.h"
-#include "ssl/ssl-internal.h"
-
-#include "autodetect.h"
-#include "protocol.h"
-#include "dispatch_actions.h"
-#include "proton/event.h"
-#include "platform.h"
-#include "platform_fmt.h"
-#include "config.h"
-#include "log_private.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-static ssize_t transport_consume(pn_transport_t *transport);
-
-// delivery buffers
-
-/*
- * Call this any time anything happens that may affect channel_max:
- * i.e. when the app indicates a preference, or when we receive the
- * OPEN frame from the remote peer. And call it to do the final
- * calculation just before we communicate our limit to the remote
- * peer by sending our OPEN frame.
- */
-static void pni_calculate_channel_max(pn_transport_t *transport) {
- /*
- * The application cannot make the limit larger than
- * what this library will allow.
- */
- transport->channel_max = (PN_IMPL_CHANNEL_MAX < transport->local_channel_max)
- ? PN_IMPL_CHANNEL_MAX
- : transport->local_channel_max;
-
- /*
- * The remote peer's constraint is not valid until the
- * peer's open frame has been received.
- */
- if(transport->open_rcvd) {
- transport->channel_max = (transport->channel_max < transport->remote_channel_max)
- ? transport->channel_max
- : transport->remote_channel_max;
- }
-}
-
-void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next)
-{
- db->deliveries = pn_hash(PN_WEAKREF, 0, 0.75);
- db->next = next;
-}
-
-void pn_delivery_map_free(pn_delivery_map_t *db)
-{
- pn_free(db->deliveries);
-}
-
-static pn_delivery_t *pni_delivery_map_get(pn_delivery_map_t *db, pn_sequence_t id)
-{
- return (pn_delivery_t *) pn_hash_get(db->deliveries, id);
-}
-
-static void pn_delivery_state_init(pn_delivery_state_t *ds, pn_delivery_t *delivery, pn_sequence_t id)
-{
- ds->id = id;
- ds->sent = false;
- ds->init = true;
-}
-
-static pn_delivery_state_t *pni_delivery_map_push(pn_delivery_map_t *db, pn_delivery_t *delivery)
-{
- pn_delivery_state_t *ds = &delivery->state;
- pn_delivery_state_init(ds, delivery, db->next++);
- pn_hash_put(db->deliveries, ds->id, delivery);
- return ds;
-}
-
-void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery)
-{
- if (delivery->state.init) {
- delivery->state.init = false;
- delivery->state.sent = false;
- pn_hash_del(db->deliveries, delivery->state.id);
- }
-}
-
-static void pni_delivery_map_clear(pn_delivery_map_t *dm)
-{
- pn_hash_t *hash = dm->deliveries;
- for (pn_handle_t entry = pn_hash_head(hash);
- entry;
- entry = pn_hash_next(hash, entry))
- {
- pn_delivery_t *dlv = (pn_delivery_t *) pn_hash_value(hash, entry);
- pn_delivery_map_del(dm, dlv);
- }
- dm->next = 0;
-}
-
-static void pni_default_tracer(pn_transport_t *transport, const char *message)
-{
- fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
-}
-
-static ssize_t pn_io_layer_input_passthru(pn_transport_t *, unsigned int, const char *, size_t );
-static ssize_t pn_io_layer_output_passthru(pn_transport_t *, unsigned int, char *, size_t );
-
-static ssize_t pn_io_layer_input_error(pn_transport_t *, unsigned int, const char *, size_t );
-static ssize_t pn_io_layer_output_error(pn_transport_t *, unsigned int, char *, size_t );
-
-static ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-
-static ssize_t pn_input_read_amqp_header(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_input_read_amqp(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_output_write_amqp_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-static ssize_t pn_output_write_amqp(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-static void pn_error_amqp(pn_transport_t *transport, unsigned int layer);
-static pn_timestamp_t pn_tick_amqp(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now);
-
-static ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-
-const pn_io_layer_t amqp_header_layer = {
- pn_input_read_amqp_header,
- pn_output_write_amqp_header,
- NULL,
- pn_tick_amqp,
- NULL
-};
-
-const pn_io_layer_t amqp_write_header_layer = {
- pn_input_read_amqp,
- pn_output_write_amqp_header,
- NULL,
- pn_tick_amqp,
- NULL
-};
-
-const pn_io_layer_t amqp_read_header_layer = {
- pn_input_read_amqp_header,
- pn_output_write_amqp,
- pn_error_amqp,
- pn_tick_amqp,
- NULL
-};
-
-const pn_io_layer_t amqp_layer = {
- pn_input_read_amqp,
- pn_output_write_amqp,
- pn_error_amqp,
- pn_tick_amqp,
- NULL
-};
-
-const pn_io_layer_t pni_setup_layer = {
- pn_io_layer_input_setup,
- pn_io_layer_output_setup,
- NULL,
- NULL,
- NULL
-};
-
-const pn_io_layer_t pni_autodetect_layer = {
- pn_io_layer_input_autodetect,
- pn_io_layer_output_null,
- NULL,
- NULL,
- NULL
-};
-
-const pn_io_layer_t pni_passthru_layer = {
- pn_io_layer_input_passthru,
- pn_io_layer_output_passthru,
- NULL,
- NULL,
- NULL
-};
-
-const pn_io_layer_t pni_header_error_layer = {
- pn_io_layer_input_error,
- pn_output_write_amqp_header,
- NULL,
- NULL,
- NULL
-};
-
-const pn_io_layer_t pni_error_layer = {
- pn_io_layer_input_error,
- pn_io_layer_output_error,
- pn_error_amqp,
- NULL,
- NULL
-};
-
-/* Set up the transport protocol layers depending on what is configured */
-static void pn_io_layer_setup(pn_transport_t *transport, unsigned int layer)
-{
- assert(layer == 0);
- // Figure out if we are server or not
- if (transport->server) {
- transport->io_layers[layer++] = &pni_autodetect_layer;
- return;
- }
- if (transport->ssl) {
- transport->io_layers[layer++] = &ssl_layer;
- }
- if (transport->sasl) {
- transport->io_layers[layer++] = &sasl_header_layer;
- }
- transport->io_layers[layer++] = &amqp_header_layer;
-}
-
-ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
-{
- pn_io_layer_setup(transport, layer);
- return transport->io_layers[layer]->process_input(transport, layer, bytes, available);
-}
-
-ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
-{
- pn_io_layer_setup(transport, layer);
- return transport->io_layers[layer]->process_output(transport, layer, bytes, available);
-}
-
-void pn_set_error_layer(pn_transport_t *transport)
-{
- // Set every layer to the error layer in case we manually
- // pass through (happens from SASL to AMQP)
- for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
- transport->io_layers[layer] = &pni_error_layer;
- }
-}
-
-// Autodetect the layer by reading the protocol header
-ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
-{
- const char* error;
- bool eos = pn_transport_capacity(transport)==PN_EOS;
- if (eos && available==0) {
- pn_do_error(transport, "amqp:connection:framing-error", "No valid protocol header found");
- pn_set_error_layer(transport);
- return PN_EOS;
- }
- pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
- if (transport->trace & PN_TRACE_DRV)
- pn_transport_logf(transport, "%s detected", pni_protocol_name(protocol));
- switch (protocol) {
- case PNI_PROTOCOL_SSL:
- if (!(transport->allowed_layers & LAYER_SSL)) {
- error = "SSL protocol header not allowed (maybe detected twice)";
- break;
- }
- transport->present_layers |= LAYER_SSL;
- transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
- if (!transport->ssl) {
- pn_ssl(transport);
- }
- transport->io_layers[layer] = &ssl_layer;
- transport->io_layers[layer+1] = &pni_autodetect_layer;
- return ssl_layer.process_input(transport, layer, bytes, available);
- case PNI_PROTOCOL_AMQP_SSL:
- if (!(transport->allowed_layers & LAYER_AMQPSSL)) {
- error = "AMQP SSL protocol header not allowed (maybe detected twice)";
- break;
- }
- transport->present_layers |= LAYER_AMQPSSL;
- transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
- if (!transport->ssl) {
- pn_ssl(transport);
- }
- transport->io_layers[layer] = &ssl_layer;
- transport->io_layers[layer+1] = &pni_autodetect_layer;
- return 8;
- case PNI_PROTOCOL_AMQP_SASL:
- if (!(transport->allowed_layers & LAYER_AMQPSASL)) {
- error = "AMQP SASL protocol header not allowed (maybe detected twice)";
- break;
- }
- transport->present_layers |= LAYER_AMQPSASL;
- transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSSL;
- if (!transport->sasl) {
- pn_sasl(transport);
- }
- transport->io_layers[layer] = &sasl_write_header_layer;
- transport->io_layers[layer+1] = &pni_autodetect_layer;
- if (transport->trace & PN_TRACE_FRM)
- pn_transport_logf(transport, " <- %s", "SASL");
- pni_sasl_set_external_security(transport, pn_ssl_get_ssf((pn_ssl_t*)transport), pn_ssl_get_remote_subject((pn_ssl_t*)transport));
- return 8;
- case PNI_PROTOCOL_AMQP1:
- if (!(transport->allowed_layers & LAYER_AMQP1)) {
- error = "AMQP1.0 protocol header not allowed (maybe detected twice)";
- break;
- }
- transport->present_layers |= LAYER_AMQP1;
- transport->allowed_layers = LAYER_NONE;
- if (transport->auth_required && !pn_transport_is_authenticated(transport)) {
- pn_do_error(transport, "amqp:connection:policy-error",
- "Client skipped authentication - forbidden");
- pn_set_error_layer(transport);
- return 8;
- }
- if (transport->encryption_required && !pn_transport_is_encrypted(transport)) {
- pn_do_error(transport, "amqp:connection:policy-error",
- "Client connection unencryted - forbidden");
- pn_set_error_layer(transport);
- return 8;
- }
- transport->io_layers[layer] = &amqp_write_header_layer;
- if (transport->trace & PN_TRACE_FRM)
- pn_transport_logf(transport, " <- %s", "AMQP");
- return 8;
- case PNI_PROTOCOL_INSUFFICIENT:
- if (!eos) return 0;
- error = "End of input stream before protocol detection";
- break;
- case PNI_PROTOCOL_AMQP_OTHER:
- error = "Incompatible AMQP connection detected";
- break;
- case PNI_PROTOCOL_UNKNOWN:
- default:
- error = "Unknown protocol detected";
- break;
- }
- transport->io_layers[layer] = &pni_header_error_layer;
- char quoted[1024];
- pn_quote_data(quoted, 1024, bytes, available);
- pn_do_error(transport, "amqp:connection:framing-error",
- "%s: '%s'%s", error, quoted,
- !eos ? "" : " (connection aborted)");
- return 0;
-}
-
-// We don't know what the output should be - do nothing
-ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
-{
- return 0;
-}
-
-/** Pass through input handler */
-ssize_t pn_io_layer_input_passthru(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
-{
- if (layer+1<PN_IO_LAYER_CT)
- return transport->io_layers[layer+1]->process_input(transport, layer+1, data, available);
- return PN_EOS;
-}
-
-/** Pass through output handler */
-ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
-{
- if (layer+1<PN_IO_LAYER_CT)
- return transport->io_layers[layer+1]->process_output(transport, layer+1, data, available);
- return PN_EOS;
-}
-
-/** Input handler after detected error */
-ssize_t pn_io_layer_input_error(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
-{
- return PN_EOS;
-}
-
-/** Output handler after detected error */
-ssize_t pn_io_layer_output_error(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
-{
- return PN_EOS;
-}
-
-static void pn_transport_initialize(void *object)
-{
- pn_transport_t *transport = (pn_transport_t *)object;
- transport->freed = false;
- transport->output_buf = NULL;
- transport->output_size = PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
- transport->input_buf = NULL;
- transport->input_size = PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
- transport->tracer = pni_default_tracer;
- transport->sasl = NULL;
- transport->ssl = NULL;
-
- transport->scratch = pn_string(NULL);
- transport->args = pn_data(16);
- transport->output_args = pn_data(16);
- transport->frame = pn_buffer(PN_TRANSPORT_INITIAL_FRAME_SIZE);
- transport->input_frames_ct = 0;
- transport->output_frames_ct = 0;
-
- transport->connection = NULL;
- transport->context = pn_record();
-
- for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
- transport->io_layers[layer] = NULL;
- }
-
- transport->allowed_layers = LAYER_AMQP1 | LAYER_AMQPSASL | LAYER_AMQPSSL | LAYER_SSL;
- transport->present_layers = LAYER_NONE;
-
- // Defer setting up the layers until the first data arrives or is sent
- transport->io_layers[0] = &pni_setup_layer;
-
- transport->open_sent = false;
- transport->open_rcvd = false;
- transport->close_sent = false;
- transport->close_rcvd = false;
- transport->tail_closed = false;
- transport->head_closed = false;
- transport->remote_container = NULL;
- transport->remote_hostname = NULL;
- transport->local_max_frame = PN_DEFAULT_MAX_FRAME_SIZE;
- transport->remote_max_frame = (uint32_t) 0xffffffff;
-
- /*
- * We set the local limit on channels to 2^15, because
- * parts of the code use the topmost bit (of a short)
- * as a flag.
- * The peer that this transport connects to may also
- * place its own limit on max channel number, and the
- * application may also set a limit.
- * The maximum that we use will be the minimum of all
- * these constraints.
- */
- // There is no constraint yet from remote peer,
- // so set to max possible.
- transport->remote_channel_max = 65535;
- transport->local_channel_max = PN_IMPL_CHANNEL_MAX;
- transport->channel_max = transport->local_channel_max;
-
- transport->local_idle_timeout = 0;
- transport->dead_remote_deadline = 0;
- transport->last_bytes_input = 0;
- transport->remote_idle_timeout = 0;
- transport->keepalive_deadline = 0;
- transport->last_bytes_output = 0;
- transport->remote_offered_capabilities = pn_data(0);
- transport->remote_desired_capabilities = pn_data(0);
- transport->remote_properties = pn_data(0);
- transport->disp_data = pn_data(0);
- pn_condition_init(&transport->remote_condition);
- pn_condition_init(&transport->condition);
- transport->error = pn_error();
-
- transport->local_channels = pn_hash(PN_WEAKREF, 0, 0.75);
- transport->remote_channels = pn_hash(PN_WEAKREF, 0, 0.75);
-
- transport->bytes_input = 0;
- transport->bytes_output = 0;
-
- transport->input_pending = 0;
- transport->output_pending = 0;
-
- transport->done_processing = false;
-
- transport->posted_idle_timeout = false;
-
- transport->server = false;
- transport->halt = false;
- transport->auth_required = false;
- transport->authenticated = false;
- transport->encryption_required = false;
-
- transport->referenced = true;
-
- transport->trace =
- (pn_env_bool("PN_TRACE_RAW") ? PN_TRACE_RAW : PN_TRACE_OFF) |
- (pn_env_bool("PN_TRACE_FRM") ? PN_TRACE_FRM : PN_TRACE_OFF) |
- (pn_env_bool("PN_TRACE_DRV") ? PN_TRACE_DRV : PN_TRACE_OFF) |
- (pn_env_bool("PN_TRACE_EVT") ? PN_TRACE_EVT : PN_TRACE_OFF) ;
-}
-
-
-static pn_session_t *pni_channel_state(pn_transport_t *transport, uint16_t channel)
-{
- return (pn_session_t *) pn_hash_get(transport->remote_channels, channel);
-}
-
-static void pni_map_remote_channel(pn_session_t *session, uint16_t channel)
-{
- pn_transport_t *transport = session->connection->transport;
- pn_hash_put(transport->remote_channels, channel, session);
- session->state.remote_channel = channel;
- pn_ep_incref(&session->endpoint);
-}
-
-void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state);
-
-static void pni_unmap_remote_channel(pn_session_t *ssn)
-{
- // XXX: should really update link state also
- pni_delivery_map_clear(&ssn->state.incoming);
- pni_transport_unbind_handles(ssn->state.remote_handles, false);
- pn_transport_t *transport = ssn->connection->transport;
- uint16_t channel = ssn->state.remote_channel;
- ssn->state.remote_channel = -2;
- if (pn_hash_get(transport->remote_channels, channel)) {
- pn_ep_decref(&ssn->endpoint);
- }
- // note: may free the session:
- pn_hash_del(transport->remote_channels, channel);
-}
-
-static void pn_transport_incref(void *object)
-{
- pn_transport_t *transport = (pn_transport_t *) object;
- if (!transport->referenced) {
- transport->referenced = true;
- if (transport->connection) {
- pn_incref(transport->connection);
- } else {
- pn_object_incref(object);
- }
- } else {
- pn_object_incref(object);
- }
-}
-
-static void pn_transport_finalize(void *object);
-#define pn_transport_new pn_object_new
-#define pn_transport_refcount pn_object_refcount
-#define pn_transport_decref pn_object_decref
-#define pn_transport_reify pn_object_reify
-#define pn_transport_hashcode NULL
-#define pn_transport_compare NULL
-#define pn_transport_inspect NULL
-
-pn_transport_t *pn_transport(void)
-{
-#define pn_transport_free pn_object_free
- static const pn_class_t clazz = PN_METACLASS(pn_transport);
-#undef pn_transport_free
- pn_transport_t *transport =
- (pn_transport_t *) pn_class_new(&clazz, sizeof(pn_transport_t));
- if (!transport) return NULL;
-
- transport->output_buf = (char *) malloc(transport->output_size);
- if (!transport->output_buf) {
- pn_transport_free(transport);
- return NULL;
- }
-
- transport->input_buf = (char *) malloc(transport->input_size);
- if (!transport->input_buf) {
- pn_transport_free(transport);
- return NULL;
- }
-
- transport->capacity = 4*1024;
- transport->available = 0;
- transport->output = (char *) malloc(transport->capacity);
- if (!transport->output) {
- pn_transport_free(transport);
- return NULL;
- }
-
- return transport;
-}
-
-void pn_transport_set_server(pn_transport_t *transport)
-{
- assert(transport);
- transport->server = true;
-}
-
-const char *pn_transport_get_user(pn_transport_t *transport)
-{
- assert(transport);
- // Client - just return whatever we gave to sasl
- if (!transport->server) {
- if (transport->sasl) return pn_sasl_get_user((pn_sasl_t *)transport);
- return "anonymous";
- }
-
- // Server
- // Not finished authentication yet
- if (!(transport->present_layers & LAYER_AMQP1)) return 0;
- // We have SASL so it takes precedence
- if (transport->present_layers & LAYER_AMQPSASL) return pn_sasl_get_user((pn_sasl_t *)transport);
- // No SASL but we may have a SSL remote_subject
- if (transport->present_layers & (LAYER_AMQPSSL | LAYER_SSL)) return pn_ssl_get_remote_subject((pn_ssl_t *)transport);
- // otherwise it's just an unauthenticated anonymous connection
- return "anonymous";
-}
-
-void pn_transport_require_auth(pn_transport_t *transport, bool required)
-{
- assert(transport);
- transport->auth_required = required;
-}
-
-bool pn_transport_is_authenticated(pn_transport_t *transport)
-{
- return transport && transport->authenticated;
-}
-
-void pn_transport_require_encryption(pn_transport_t *transport, bool required)
-{
- assert(transport);
- transport->encryption_required = required;
-}
-
-bool pn_transport_is_encrypted(pn_transport_t *transport)
-{
- return transport && transport->ssl && pn_ssl_get_ssf((pn_ssl_t*)transport)>0;
-}
-
-void pn_transport_free(pn_transport_t *transport)
-{
- if (!transport) return;
- assert(!transport->freed);
- transport->freed = true;
- pn_decref(transport);
-}
-
-static void pn_transport_finalize(void *object)
-{
- pn_transport_t *transport = (pn_transport_t *) object;
-
- if (transport->referenced && transport->connection && pn_refcount(transport->connection) > 1) {
- pn_object_incref(transport);
- transport->referenced = false;
- pn_decref(transport->connection);
- return;
- }
-
- // once the application frees the transport, no further I/O
- // processing can be done to the connection:
- pn_transport_unbind(transport);
- // we may have posted events, so stay alive until they are processed
- if (pn_refcount(transport) > 0) return;
-
- pn_ssl_free(transport);
- pn_sasl_free(transport);
- free(transport->remote_container);
- free(transport->remote_hostname);
- pn_free(transport->remote_offered_capabilities);
- pn_free(transport->remote_desired_capabilities);
- pn_free(transport->remote_properties);
- pn_free(transport->disp_data);
- pn_condition_tini(&transport->remote_condition);
- pn_condition_tini(&transport->condition);
- pn_error_free(transport->error);
- pn_free(transport->local_channels);
- pn_free(transport->remote_channels);
- if (transport->input_buf) free(transport->input_buf);
- if (transport->output_buf) free(transport->output_buf);
- pn_free(transport->scratch);
- pn_data_free(transport->args);
- pn_data_free(transport->output_args);
- pn_buffer_free(transport->frame);
- pn_free(transport->context);
- free(transport->output);
-}
-
-static void pni_post_remote_open_events(pn_transport_t *transport, pn_connection_t *connection) {
- pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_REMOTE_OPEN);
- if (transport->remote_idle_timeout) {
- pn_collector_put(connection->collector, PN_OBJECT, transport, PN_TRANSPORT);
- }
-}
-
-int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
-{
- assert(transport);
- assert(connection);
-
- if (transport->connection) return PN_STATE_ERR;
- if (connection->transport) return PN_STATE_ERR;
-
- transport->connection = connection;
- connection->transport = transport;
-
- pn_incref(connection);
-
- pn_connection_bound(connection);
-
- // set the hostname/user/password
- if (pn_string_size(connection->auth_user)) {
- pn_sasl(transport);
- pni_sasl_set_user_password(transport, pn_string_get(connection->auth_user), pn_string_get(connection->auth_password));
- }
-
- if (pn_string_size(connection->hostname)) {
- if (transport->sasl) {
- pni_sasl_set_remote_hostname(transport, pn_string_get(connection->hostname));
- }
-
- // be sure not to overwrite a hostname already set by the user via
- // pn_ssl_set_peer_hostname() called before the bind
- if (transport->ssl) {
- size_t name_len = 0;
- pn_ssl_get_peer_hostname((pn_ssl_t*) transport, NULL, &name_len);
- if (name_len == 0) {
- pn_ssl_set_peer_hostname((pn_ssl_t*) transport, pn_string_get(connection->hostname));
- }
- }
- }
-
- if (transport->open_rcvd) {
- PN_SET_REMOTE(connection->endpoint.state, PN_REMOTE_ACTIVE);
- pni_post_remote_open_events(transport, connection);
- transport->halt = false;
- transport_consume(transport); // blech - testBindAfterOpen
- }
-
- return 0;
-}
-
-void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state)
-{
- for (pn_handle_t h = pn_hash_head(handles); h; h = pn_hash_next(handles, h)) {
- uintptr_t key = pn_hash_key(handles, h);
- pn_link_t *link = (pn_link_t *) pn_hash_value(handles, h);
- if (reset_state) {
- pn_link_unbound(link);
- }
- pn_ep_decref(&link->endpoint);
- pn_hash_del(handles, key);
- }
-}
-
-void pni_transport_unbind_channels(pn_hash_t *channels)
-{
- for (pn_handle_t h = pn_hash_head(channels); h; h = pn_hash_next(channels, h)) {
- uintptr_t key = pn_hash_key(channels, h);
- pn_session_t *ssn = (pn_session_t *) pn_hash_value(channels, h);
- pni_delivery_map_clear(&ssn->state.incoming);
- pni_delivery_map_clear(&ssn->state.outgoing);
- pni_transport_unbind_handles(ssn->state.local_handles, true);
- pni_transport_unbind_handles(ssn->state.remote_handles, true);
- pn_session_unbound(ssn);
- pn_ep_decref(&ssn->endpoint);
- pn_hash_del(channels, key);
- }
-}
-
-int pn_transport_unbind(pn_transport_t *transport)
-{
- assert(transport);
- if (!transport->connection) return 0;
-
-
- pn_connection_t *conn = transport->connection;
- transport->connection = NULL;
- bool was_referenced = transport->referenced;
-
- pn_collector_put(conn->collector, PN_OBJECT, conn, PN_CONNECTION_UNBOUND);
-
- // XXX: what happens if the endpoints are freed before we get here?
- pn_session_t *ssn = pn_session_head(conn, 0);
- while (ssn) {
- pni_delivery_map_clear(&ssn->state.incoming);
- pni_delivery_map_clear(&ssn->state.outgoing);
- ssn = pn_session_next(ssn, 0);
- }
-
- pn_endpoint_t *endpoint = conn->endpoint_head;
- while (endpoint) {
- pn_condition_clear(&endpoint->remote_condition);
- pn_modified(conn, endpoint, true);
- endpoint = endpoint->endpoint_next;
- }
-
- pni_transport_unbind_channels(transport->local_channels);
- pni_transport_unbind_channels(transport->remote_channels);
-
- pn_connection_unbound(conn);
- if (was_referenced) {
- pn_decref(conn);
- }
- return 0;
-}
-
-pn_error_t *pn_transport_error(pn_transport_t *transport)
-{
- assert(transport);
- if (pn_condition_is_set(&transport->condition)) {
- pn_error_format(transport->error, PN_ERR, "%s: %s",
- pn_condition_get_name(&transport->condition),
- pn_condition_get_description(&transport->condition));
- } else {
- pn_error_clear(transport->error);
- }
- return transport->error;
-}
-
-pn_condition_t *pn_transport_condition(pn_transport_t *transport)
-{
- assert(transport);
- return &transport->condition;
-}
-
-static void pni_map_remote_handle(pn_link_t *link, uint32_t handle)
-{
- link->state.remote_handle = handle;
- pn_hash_put(link->session->state.remote_handles, handle, link);
- pn_ep_incref(&link->endpoint);
-}
-
-static void pni_unmap_remote_handle(pn_link_t *link)
-{
- uintptr_t handle = link->state.remote_handle;
- link->state.remote_handle = -2;
- if (pn_hash_get(link->session->state.remote_handles, handle)) {
- pn_ep_decref(&link->endpoint);
- }
- // may delete link:
- pn_hash_del(link->session->state.remote_handles, handle);
-}
-
-static pn_link_t *pni_handle_state(pn_session_t *ssn, uint32_t handle)
-{
- return (pn_link_t *) pn_hash_get(ssn->state.remote_handles, handle);
-}
-
-bool pni_disposition_batchable(pn_disposition_t *disposition)
-{
- switch (disposition->type) {
- case PN_ACCEPTED:
- return true;
- case PN_RELEASED:
- return true;
- default:
- return false;
- }
-}
-
-static int pni_disposition_encode(pn_disposition_t *disposition, pn_data_t *data)
-{
- pn_condition_t *cond = &disposition->condition;
- switch (disposition->type) {
- case PN_RECEIVED:
- PN_RETURN_IF_ERROR(pn_data_put_list(data));
- pn_data_enter(data);
- PN_RETURN_IF_ERROR(pn_data_put_uint(data, disposition->section_number));
- PN_RETURN_IF_ERROR(pn_data_put_ulong(data, disposition->section_offset));
- pn_data_exit(data);
- return 0;
- case PN_ACCEPTED:
- case PN_RELEASED:
- return 0;
- case PN_REJECTED:
- return pn_data_fill(data, "[?DL[sSC]]", pn_condition_is_set(cond), ERROR,
- pn_condition_get_name(cond),
- pn_condition_get_description(cond),
- pn_condition_info(cond));
- case PN_MODIFIED:
- return pn_data_fill(data, "[ooC]",
- disposition->failed,
- disposition->undeliverable,
- disposition->annotations);
- default:
- return pn_data_copy(data, disposition->data);
- }
-}
-
-
-void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
- pn_data_t *args, const char *payload, size_t size)
-{
- if (transport->trace & PN_TRACE_FRM) {
- pn_string_format(transport->scratch, "%u %s ", ch, dir == OUT ? "->" : "<-");
- pn_inspect(args, transport->scratch);
-
- if (pn_data_size(args)==0) {
- pn_string_addf(transport->scratch, "(EMPTY FRAME)");
- }
-
- if (size) {
- char buf[1024];
- int e = pn_quote_data(buf, 1024, payload, size);
- pn_string_addf(transport->scratch, " (%" PN_ZU ") \"%s\"%s", size, buf,
- e == PN_OVERFLOW ? "... (truncated)" : "");
- }
-
- pn_transport_log(transport, pn_string_get(transport->scratch));
- }
-}
-
-int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...)
-{
- pn_buffer_t *frame_buf = transport->frame;
- va_list ap;
- va_start(ap, fmt);
- pn_data_clear(transport->output_args);
- int err = pn_data_vfill(transport->output_args, fmt, ap);
- va_end(ap);
- if (err) {
- pn_transport_logf(transport,
- "error posting frame: %s, %s: %s", fmt, pn_code(err),
- pn_error_text(pn_data_error(transport->output_args)));
- return PN_ERR;
- }
-
- pn_do_trace(transport, ch, OUT, transport->output_args, NULL, 0);
-
- encode_performatives:
- pn_buffer_clear( frame_buf );
- pn_rwbytes_t buf = pn_buffer_memory( frame_buf );
- buf.size = pn_buffer_available( frame_buf );
-
- ssize_t wr = pn_data_encode( transport->output_args, buf.start, buf.size );
- if (wr < 0) {
- if (wr == PN_OVERFLOW) {
- pn_buffer_ensure( frame_buf, pn_buffer_available( frame_buf ) * 2 );
- goto encode_performatives;
- }
- pn_transport_logf(transport,
- "error posting frame: %s", pn_code(wr));
- return PN_ERR;
- }
-
- pn_frame_t frame = {0,};
- frame.type = type;
- frame.channel = ch;
- frame.payload = buf.start;
- frame.size = wr;
- size_t n;
- while (!(n = pn_write_frame(transport->output + transport->available,
- transport->capacity - transport->available, frame))) {
- transport->capacity *= 2;
- transport->output = (char *) realloc(transport->output, transport->capacity);
- }
- transport->output_frames_ct += 1;
- if (transport->trace & PN_TRACE_RAW) {
- pn_string_set(transport->scratch, "RAW: \"");
- pn_quote(transport->scratch, transport->output + transport->available, n);
- pn_string_addf(transport->scratch, "\"");
- pn_transport_log(transport, pn_string_get(transport->scratch));
- }
- transport->available += n;
-
- return 0;
-}
-
-static int pni_post_amqp_transfer_frame(pn_transport_t *transport, uint16_t ch,
- uint32_t handle,
- pn_sequence_t id,
- pn_bytes_t *payload,
- const pn_bytes_t *tag,
- uint32_t message_format,
- bool settled,
- bool more,
- pn_sequence_t frame_limit,
- uint64_t code,
- pn_data_t* state)
-{
- bool more_flag = more;
- int framecount = 0;
- pn_buffer_t *frame = transport->frame;
-
- // create preformatives, assuming 'more' flag need not change
-
- compute_performatives:
- pn_data_clear(transport->output_args);
- int err = pn_data_fill(transport->output_args, "DL[IIzIoon?DLC]", TRANSFER,
- handle, id, tag->size, tag->start,
- message_format,
- settled, more_flag, (bool)code, code, state);
- if (err) {
- pn_transport_logf(transport,
- "error posting transfer frame: %s: %s", pn_code(err),
- pn_error_text(pn_data_error(transport->output_args)));
- return PN_ERR;
- }
-
- do { // send as many frames as possible without changing the 'more' flag...
-
- encode_performatives:
- pn_buffer_clear( frame );
- pn_rwbytes_t buf = pn_buffer_memory( frame );
- buf.size = pn_buffer_available( frame );
-
- ssize_t wr = pn_data_encode(transport->output_args, buf.start, buf.size);
- if (wr < 0) {
- if (wr == PN_OVERFLOW) {
- pn_buffer_ensure( frame, pn_buffer_available( frame ) * 2 );
- goto encode_performatives;
- }
- pn_transport_logf(transport, "error posting frame: %s", pn_code(wr));
- return PN_ERR;
- }
- buf.size = wr;
-
- // check if we need to break up the outbound frame
- size_t available = payload->size;
- if (transport->remote_max_frame) {
- if ((available + buf.size) > transport->remote_max_frame - 8) {
- available = transport->remote_max_frame - 8 - buf.size;
- if (more_flag == false) {
- more_flag = true;
- goto compute_performatives; // deal with flag change
- }
- } else if (more_flag == true && more == false) {
- // caller has no more, and this is the last frame
- more_flag = false;
- goto compute_performatives;
- }
- }
-
- if (pn_buffer_available( frame ) < (available + buf.size)) {
- // not enough room for payload - try again...
- pn_buffer_ensure( frame, available + buf.size );
- goto encode_performatives;
- }
-
- pn_do_trace(transport, ch, OUT, transport->output_args, payload->start, available);
-
- memmove( buf.start + buf.size, payload->start, available);
- payload->start += available;
- payload->size -= available;
- buf.size += available;
-
- pn_frame_t frame = {AMQP_FRAME_TYPE};
- frame.channel = ch;
- frame.payload = buf.start;
- frame.size = buf.size;
-
- size_t n;
- while (!(n = pn_write_frame(transport->output + transport->available,
- transport->capacity - transport->available, frame))) {
- transport->capacity *= 2;
- transport->output = (char *) realloc(transport->output, transport->capacity);
- }
- transport->output_frames_ct += 1;
- framecount++;
- if (transport->trace & PN_TRACE_RAW) {
- pn_string_set(transport->scratch, "RAW: \"");
- pn_quote(transport->scratch, transport->output + transport->available, n);
- pn_string_addf(transport->scratch, "\"");
- pn_transport_log(transport, pn_string_get(transport->scratch));
- }
- transport->available += n;
- } while (payload->size > 0 && framecount < frame_limit);
-
- return framecount;
-}
-
-static int pni_post_close(pn_transport_t *transport, pn_condition_t *cond)
-{
- if (!cond && transport->connection) {
- cond = pn_connection_condition(transport->connection);
- }
- const char *condition = NULL;
- const char *description = NULL;
- pn_data_t *info = NULL;
- if (pn_condition_is_set(cond)) {
- condition = pn_condition_get_name(cond);
- description = pn_condition_get_description(cond);
- info = pn_condition_info(cond);
- }
-
- return pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[?DL[sSC]]", CLOSE,
- (bool) condition, ERROR, condition, description, info);
-}
-
-static pn_collector_t *pni_transport_collector(pn_transport_t *transport)
-{
- if (transport->connection && transport->connection->collector) {
- return transport->connection->collector;
- } else {
- return NULL;
- }
-}
-
-static void pni_maybe_post_closed(pn_transport_t *transport)
-{
- pn_collector_t *collector = pni_transport_collector(transport);
- if (transport->head_closed && transport->tail_closed) {
- pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_CLOSED);
- }
-}
-
-static void pni_close_tail(pn_transport_t *transport)
-{
- if (!transport->tail_closed) {
- transport->tail_closed = true;
- pn_collector_t *collector = pni_transport_collector(transport);
- pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_TAIL_CLOSED);
- pni_maybe_post_closed(transport);
- }
-}
-
-int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- char buf[1024];
- if (fmt) {
- // XXX: result
- vsnprintf(buf, 1024, fmt, ap);
- } else {
- buf[0] = '\0';
- }
- va_end(ap);
- pn_condition_t *cond = &transport->condition;
- if (!pn_condition_is_set(cond)) {
- pn_condition_set_name(cond, condition);
- if (fmt) {
- pn_condition_set_description(cond, buf);
- }
- } else {
- const char *first = pn_condition_get_description(cond);
- if (first && fmt) {
- char extended[2048];
- snprintf(extended, 2048, "%s (%s)", first, buf);
- pn_condition_set_description(cond, extended);
- } else if (fmt) {
- pn_condition_set_description(cond, buf);
- }
- }
- pn_collector_t *collector = pni_transport_collector(transport);
- pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_ERROR);
- if (transport->trace & PN_TRACE_DRV) {
- pn_transport_logf(transport, "ERROR %s %s", condition, buf);
- }
-
- for (int i = 0; i<PN_IO_LAYER_CT; ++i) {
- if (transport->io_layers[i] && transport->io_layers[i]->handle_error)
- transport->io_layers[i]->handle_error(transport, i);
- }
-
- pni_close_tail(transport);
- return PN_ERR;
-}
-
-static char *pn_bytes_strdup(pn_bytes_t str)
-{
- return pn_strndup(str.start, str.size);
-}
-
-int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- pn_connection_t *conn = transport->connection;
- bool container_q, hostname_q, remote_channel_max_q, remote_max_frame_q;
- uint16_t remote_channel_max;
- uint32_t remote_max_frame;
- pn_bytes_t remote_container, remote_hostname;
- pn_data_clear(transport->remote_offered_capabilities);
- pn_data_clear(transport->remote_desired_capabilities);
- pn_data_clear(transport->remote_properties);
- int err = pn_data_scan(args, "D.[?S?S?I?HI..CCC]",
- &container_q, &remote_container,
- &hostname_q, &remote_hostname,
- &remote_max_frame_q, &remote_max_frame,
- &remote_channel_max_q, &remote_channel_max,
- &transport->remote_idle_timeout,
- transport->remote_offered_capabilities,
- transport->remote_desired_capabilities,
- transport->remote_properties);
- if (err) return err;
- /*
- * The default value is already stored in the variable.
- * But the scanner zeroes out values if it does not
- * find them in the args, so don't give the variable
- * directly to the scanner.
- */
- if (remote_channel_max_q) {
- transport->remote_channel_max = remote_channel_max;
- }
-
- if (remote_max_frame_q) {
- transport->remote_max_frame = remote_max_frame;
- }
-
- if (transport->remote_max_frame > 0) {
- if (transport->remote_max_frame < AMQP_MIN_MAX_FRAME_SIZE) {
- pn_transport_logf(transport, "Peer advertised bad max-frame (%u), forcing to %u",
- transport->remote_max_frame, AMQP_MIN_MAX_FRAME_SIZE);
- transport->remote_max_frame = AMQP_MIN_MAX_FRAME_SIZE;
- }
- }
- if (container_q) {
- transport->remote_container = pn_bytes_strdup(remote_container);
- } else {
- transport->remote_container = NULL;
- }
- if (hostname_q) {
- transport->remote_hostname = pn_bytes_strdup(remote_hostname);
- } else {
- transport->remote_hostname = NULL;
- }
-
- if (conn) {
- PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_ACTIVE);
- pni_post_remote_open_events(transport, conn);
- } else {
- transport->halt = true;
- }
- transport->open_rcvd = true;
- pni_calculate_channel_max(transport);
- return 0;
-}
-
-int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- bool reply;
- uint16_t remote_channel;
- pn_sequence_t next;
- int err = pn_data_scan(args, "D.[?HI]", &reply, &remote_channel, &next);
- if (err) return err;
-
- // AMQP 1.0 section 2.7.1 - if the peer doesn't honor our channel_max --
- // express our displeasure by closing the connection with a framing error.
- if (remote_channel > transport->channel_max) {
- pn_do_error(transport,
- "amqp:connection:framing-error",
- "remote channel %d is above negotiated channel_max %d.",
- remote_channel,
- transport->channel_max
- );
- return PN_TRANSPORT_ERROR;
- }
-
- pn_session_t *ssn;
- if (reply) {
- ssn = (pn_session_t *) pn_hash_get(transport->local_channels, remote_channel);
- } else {
- ssn = pn_session(transport->connection);
- }
- if (ssn == 0) {
- pn_do_error(transport,
- "amqp:connection:framing-error",
- "remote channel is above negotiated channel_max %d.",
- transport->channel_max
- );
- return PN_TRANSPORT_ERROR;
- }
- ssn->state.incoming_transfer_count = next;
- pni_map_remote_channel(ssn, channel);
- PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
- pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_OPEN);
- return 0;
-}
-
-pn_link_t *pn_find_link(pn_session_t *ssn, pn_bytes_t name, bool is_sender)
-{
- pn_endpoint_type_t type = is_sender ? SENDER : RECEIVER;
-
- for (size_t i = 0; i < pn_list_size(ssn->links); i++)
- {
- pn_link_t *link = (pn_link_t *) pn_list_get(ssn->links, i);
- if (link->endpoint.type == type &&
- // This function is used to locate the link object for an
- // incoming attach. If a link object of the same name is found
- // which is closed both locally and remotely, assume that is
- // no longer in use.
- !((link->endpoint.state & PN_LOCAL_CLOSED) && (link->endpoint.state & PN_REMOTE_CLOSED)) &&
- !strncmp(name.start, pn_string_get(link->name), name.size))
- {
- return link;
- }
- }
- return NULL;
-}
-
-static pn_expiry_policy_t symbol2policy(pn_bytes_t symbol)
-{
- if (!symbol.start)
- return PN_EXPIRE_WITH_SESSION;
-
- if (!strncmp(symbol.start, "link-detach", symbol.size))
- return PN_EXPIRE_WITH_LINK;
- if (!strncmp(symbol.start, "session-end", symbol.size))
- return PN_EXPIRE_WITH_SESSION;
- if (!strncmp(symbol.start, "connection-close", symbol.size))
- return PN_EXPIRE_WITH_CONNECTION;
- if (!strncmp(symbol.start, "never", symbol.size))
- return PN_EXPIRE_NEVER;
-
- return PN_EXPIRE_WITH_SESSION;
-}
-
-static pn_distribution_mode_t symbol2dist_mode(const pn_bytes_t symbol)
-{
- if (!symbol.start)
- return PN_DIST_MODE_UNSPECIFIED;
-
- if (!strncmp(symbol.start, "move", symbol.size))
- return PN_DIST_MODE_MOVE;
- if (!strncmp(symbol.start, "copy", symbol.size))
- return PN_DIST_MODE_COPY;
-
- return PN_DIST_MODE_UNSPECIFIED;
-}
-
-static const char *dist_mode2symbol(const pn_distribution_mode_t mode)
-{
- switch (mode)
- {
- case PN_DIST_MODE_COPY:
- return "copy";
- case PN_DIST_MODE_MOVE:
- return "move";
- default:
- return NULL;
- }
-}
-
-int pn_terminus_set_address_bytes(pn_terminus_t *terminus, pn_bytes_t address)
-{
- assert(terminus);
- return pn_string_setn(terminus->address, address.start, address.size);
-}
-
-int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- pn_bytes_t name;
- uint32_t handle;
- bool is_sender;
- pn_bytes_t source, target;
- pn_durability_t src_dr, tgt_dr;
- pn_bytes_t src_exp, tgt_exp;
- pn_seconds_t src_timeout, tgt_timeout;
- bool src_dynamic, tgt_dynamic;
- pn_sequence_t idc;
- pn_bytes_t dist_mode;
- bool snd_settle, rcv_settle;
- uint8_t snd_settle_mode, rcv_settle_mode;
- int err = pn_data_scan(args, "D.[SIo?B?BD.[SIsIo.s]D.[SIsIo]..I]", &name, &handle,
- &is_sender,
- &snd_settle, &snd_settle_mode,
- &rcv_settle, &rcv_settle_mode,
- &source, &src_dr, &src_exp, &src_timeout, &src_dynamic, &dist_mode,
- &target, &tgt_dr, &tgt_exp, &tgt_timeout, &tgt_dynamic,
- &idc);
- if (err) return err;
- char strbuf[128]; // avoid malloc for most link names
- char *strheap = (name.size >= sizeof(strbuf)) ? (char *) malloc(name.size + 1) : NULL;
- char *strname = strheap ? strheap : strbuf;
- strncpy(strname, name.start, name.size);
- strname[name.size] = '\0';
-
- pn_session_t *ssn = pni_channel_state(transport, channel);
- if (!ssn) {
- pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
- if (strheap) free(strheap);
- return PN_EOS;
- }
- pn_link_t *link = pn_find_link(ssn, name, is_sender);
- if (!link) {
- if (is_sender) {
- link = (pn_link_t *) pn_sender(ssn, strname);
- } else {
- link = (pn_link_t *) pn_receiver(ssn, strname);
- }
- }
-
- if (strheap) {
- free(strheap);
- }
-
- pni_map_remote_handle(link, handle);
- PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_ACTIVE);
- pn_terminus_t *rsrc = &link->remote_source;
- if (source.start || src_dynamic) {
- pn_terminus_set_type(rsrc, PN_SOURCE);
- pn_terminus_set_address_bytes(rsrc, source);
- pn_terminus_set_durability(rsrc, src_dr);
- pn_terminus_set_expiry_policy(rsrc, symbol2policy(src_exp));
- pn_terminus_set_timeout(rsrc, src_timeout);
- pn_terminus_set_dynamic(rsrc, src_dynamic);
- pn_terminus_set_distribution_mode(rsrc, symbol2dist_mode(dist_mode));
- } else {
- pn_terminus_set_type(rsrc, PN_UNSPECIFIED);
- }
- pn_terminus_t *rtgt = &link->remote_target;
- if (target.start || tgt_dynamic) {
- pn_terminus_set_type(rtgt, PN_TARGET);
- pn_terminus_set_address_bytes(rtgt, target);
- pn_terminus_set_durability(rtgt, tgt_dr);
- pn_terminus_set_expiry_policy(rtgt, symbol2policy(tgt_exp));
- pn_terminus_set_timeout(rtgt, tgt_timeout);
- pn_terminus_set_dynamic(rtgt, tgt_dynamic);
- } else {
- uint64_t code = 0;
- pn_data_clear(link->remote_target.capabilities);
- err = pn_data_scan(args, "D.[.....D..DL[C]...]", &code,
- link->remote_target.capabilities);
- if (err) return err;
- if (code == COORDINATOR) {
- pn_terminus_set_type(rtgt, PN_COORDINATOR);
- } else if (code == TARGET) {
- pn_terminus_set_type(rtgt, PN_TARGET);
- } else {
- pn_terminus_set_type(rtgt, PN_UNSPECIFIED);
- }
- }
-
- if (snd_settle)
- link->remote_snd_settle_mode = snd_settle_mode;
- if (rcv_settle)
- link->remote_rcv_settle_mode = rcv_settle_mode;
-
- pn_data_clear(link->remote_source.properties);
- pn_data_clear(link->remote_source.filter);
- pn_data_clear(link->remote_source.outcomes);
- pn_data_clear(link->remote_source.capabilities);
- pn_data_clear(link->remote_target.properties);
- pn_data_clear(link->remote_target.capabilities);
-
- err = pn_data_scan(args, "D.[.....D.[.....C.C.CC]D.[.....CC]",
- link->remote_source.properties,
- link->remote_source.filter,
- link->remote_source.outcomes,
- link->remote_source.capabilities,
- link->remote_target.properties,
- link->remote_target.capabilities);
- if (err) return err;
-
- pn_data_rewind(link->remote_source.properties);
- pn_data_rewind(link->remote_source.filter);
- pn_data_rewind(link->remote_source.outcomes);
- pn_data_rewind(link->remote_source.capabilities);
- pn_data_rewind(link->remote_target.properties);
- pn_data_rewind(link->remote_target.capabilities);
-
- if (!is_sender) {
- link->state.delivery_count = idc;
- }
-
- pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_OPEN);
- return 0;
-}
-
-static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link);
-
-// free the delivery
-static void pn_full_settle(pn_delivery_map_t *db, pn_delivery_t *delivery)
-{
- assert(!delivery->work);
- pn_clear_tpwork(delivery);
- pn_delivery_map_del(db, delivery);
- pn_incref(delivery);
- pn_decref(delivery);
-}
-
-int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- // XXX: multi transfer
- uint32_t handle;
- pn_bytes_t tag;
- bool id_present;
- pn_sequence_t id;
- bool settled;
- bool more;
- bool has_type;
- uint64_t type;
- pn_data_clear(transport->disp_data);
- int err = pn_data_scan(args, "D.[I?Iz.oo.D?LC]", &handle, &id_present, &id, &tag,
- &settled, &more, &has_type, &type, transport->disp_data);
- if (err) return err;
- pn_session_t *ssn = pni_channel_state(transport, channel);
- if (!ssn) {
- return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
- }
-
- if (!ssn->state.incoming_window) {
- return pn_do_error(transport, "amqp:session:window-violation", "incoming session window exceeded");
- }
-
- pn_link_t *link = pni_handle_state(ssn, handle);
- if (!link) {
- return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
- }
- pn_delivery_t *delivery;
- if (link->unsettled_tail && !link->unsettled_tail->done) {
- delivery = link->unsettled_tail;
- } else {
- pn_delivery_map_t *incoming = &ssn->state.incoming;
-
- if (!ssn->state.incoming_init) {
- incoming->next = id;
- ssn->state.incoming_init = true;
- ssn->incoming_deliveries++;
- }
-
- delivery = pn_delivery(link, pn_dtag(tag.start, tag.size));
- pn_delivery_state_t *state = pni_delivery_map_push(incoming, delivery);
- if (id_present && id != state->id) {
- return pn_do_error(transport, "amqp:session:invalid-field",
- "sequencing error, expected delivery-id %u, got %u",
- state->id, id);
- }
- if (has_type) {
- delivery->remote.type = type;
- pn_data_copy(delivery->remote.data, transport->disp_data);
- }
-
- link->state.delivery_count++;
- link->state.link_credit--;
- link->queued++;
-
- // XXX: need to fill in remote state: delivery->remote.state = ...;
- delivery->remote.settled = settled;
- if (settled) {
- delivery->updated = true;
- pn_work_update(transport->connection, delivery);
- }
- }
-
- pn_buffer_append(delivery->bytes, payload->start, payload->size);
- ssn->incoming_bytes += payload->size;
- delivery->done = !more;
-
- ssn->state.incoming_transfer_count++;
- ssn->state.incoming_window--;
-
- // XXX: need better policy for when to refresh window
- if (!ssn->state.incoming_window && (int32_t) link->state.local_handle >= 0) {
- pni_post_flow(transport, ssn, link);
- }
-
- pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
- return 0;
-}
-
-int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- pn_sequence_t onext, inext, delivery_count;
- uint32_t iwin, owin, link_credit;
- uint32_t handle;
- bool inext_init, handle_init, dcount_init, drain;
- int err = pn_data_scan(args, "D.[?IIII?I?II.o]", &inext_init, &inext, &iwin,
- &onext, &owin, &handle_init, &handle, &dcount_init,
- &delivery_count, &link_credit, &drain);
- if (err) return err;
-
- pn_session_t *ssn = pni_channel_state(transport, channel);
- if (!ssn) {
- return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
- }
-
- if (inext_init) {
- ssn->state.remote_incoming_window = inext + iwin - ssn->state.outgoing_transfer_count;
- } else {
- ssn->state.remote_incoming_window = iwin;
- }
-
- if (handle_init) {
- pn_link_t *link = pni_handle_state(ssn, handle);
- if (!link) {
- return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
- }
- if (link->endpoint.type == SENDER) {
- pn_sequence_t receiver_count;
- if (dcount_init) {
- receiver_count = delivery_count;
- } else {
- // our initial delivery count
- receiver_count = 0;
- }
- pn_sequence_t old = link->state.link_credit;
- link->state.link_credit = receiver_count + link_credit - link->state.delivery_count;
- link->credit += link->state.link_credit - old;
- link->drain = drain;
- pn_delivery_t *delivery = pn_link_current(link);
- if (delivery) pn_work_update(transport->connection, delivery);
- } else {
- pn_sequence_t delta = delivery_count - link->state.delivery_count;
- if (delta > 0) {
- link->state.delivery_count += delta;
- link->state.link_credit -= delta;
- link->credit -= delta;
- link->drained += delta;
- }
- }
-
- pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
- }
-
- return 0;
-}
-
-#define SCAN_ERROR_DEFAULT ("D.[D.[sSC]")
-#define SCAN_ERROR_DETACH ("D.[..D.[sSC]")
-#define SCAN_ERROR_DISP ("[D.[sSC]")
-
-static int pn_scan_error(pn_data_t *data, pn_condition_t *condition, const char *fmt)
-{
- pn_bytes_t cond;
- pn_bytes_t desc;
- pn_condition_clear(condition);
- int err = pn_data_scan(data, fmt, &cond, &desc, condition->info);
- if (err) return err;
- pn_string_setn(condition->name, cond.start, cond.size);
- pn_string_setn(condition->description, desc.start, desc.size);
- pn_data_rewind(condition->info);
- return 0;
-}
-
-int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- bool role;
- pn_sequence_t first, last;
- uint64_t type = 0;
- bool last_init, settled, type_init;
- pn_data_clear(transport->disp_data);
- int err = pn_data_scan(args, "D.[oI?IoD?LC]", &role, &first, &last_init,
- &last, &settled, &type_init, &type,
- transport->disp_data);
- if (err) return err;
- if (!last_init) last = first;
-
- pn_session_t *ssn = pni_channel_state(transport, channel);
- if (!ssn) {
- return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
- }
-
- pn_delivery_map_t *deliveries;
- if (role) {
- deliveries = &ssn->state.outgoing;
- } else {
- deliveries = &ssn->state.incoming;
- }
-
- pn_data_rewind(transport->disp_data);
- bool remote_data = (pn_data_next(transport->disp_data) &&
- pn_data_get_list(transport->disp_data) > 0);
-
- for (pn_sequence_t id = first; id <= last; id++) {
- pn_delivery_t *delivery = pni_delivery_map_get(deliveries, id);
- pn_disposition_t *remote = &delivery->remote;
- if (delivery) {
- if (type_init) remote->type = type;
- if (remote_data) {
- switch (type) {
- case PN_RECEIVED:
- pn_data_rewind(transport->disp_data);
- pn_data_next(transport->disp_data);
- pn_data_enter(transport->disp_data);
- if (pn_data_next(transport->disp_data))
- remote->section_number = pn_data_get_uint(transport->disp_data);
- if (pn_data_next(transport->disp_data))
- remote->section_offset = pn_data_get_ulong(transport->disp_data);
- break;
- case PN_ACCEPTED:
- break;
- case PN_REJECTED:
- err = pn_scan_error(transport->disp_data, &remote->condition, SCAN_ERROR_DISP);
- if (err) return err;
- break;
- case PN_RELEASED:
- break;
- case PN_MODIFIED:
- pn_data_rewind(transport->disp_data);
- pn_data_next(transport->disp_data);
- pn_data_enter(transport->disp_data);
- if (pn_data_next(transport->disp_data))
- remote->failed = pn_data_get_bool(transport->disp_data);
- if (pn_data_next(transport->disp_data))
- remote->undeliverable = pn_data_get_bool(transport->disp_data);
- pn_data_narrow(transport->disp_data);
- pn_data_clear(remote->data);
- pn_data_appendn(remote->annotations, transport->disp_data, 1);
- pn_data_widen(transport->disp_data);
- break;
- default:
- pn_data_copy(remote->data, transport->disp_data);
- break;
- }
- }
- remote->settled = settled;
- delivery->updated = true;
- pn_work_update(transport->connection, delivery);
-
- pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
- }
- }
-
- return 0;
-}
-
-int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- uint32_t handle;
- bool closed;
- int err = pn_data_scan(args, "D.[Io]", &handle, &closed);
- if (err) return err;
-
- pn_session_t *ssn = pni_channel_state(transport, channel);
- if (!ssn) {
- return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
- }
- pn_link_t *link = pni_handle_state(ssn, handle);
- if (!link) {
- return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
- }
-
- err = pn_scan_error(args, &link->endpoint.remote_condition, SCAN_ERROR_DETACH);
- if (err) return err;
-
- if (closed)
- {
- PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_CLOSED);
- pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_CLOSE);
- } else {
- pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_DETACH);
- }
-
- pni_unmap_remote_handle(link);
- return 0;
-}
-
-int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- pn_session_t *ssn = pni_channel_state(transport, channel);
- if (!ssn) {
- return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
- }
- int err = pn_scan_error(args, &ssn->endpoint.remote_condition, SCAN_ERROR_DEFAULT);
- if (err) return err;
- PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED);
- pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_CLOSE);
- pni_unmap_remote_channel(ssn);
- return 0;
-}
-
-int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- pn_connection_t *conn = transport->connection;
- int err = pn_scan_error(args, &transport->remote_condition, SCAN_ERROR_DEFAULT);
- if (err) return err;
- transport->close_rcvd = true;
- PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_CLOSED);
- pn_collector_put(transport->connection->collector, PN_OBJECT, conn, PN_CONNECTION_REMOTE_CLOSE);
- return 0;
-}
-
-// deprecated
-ssize_t pn_transport_input(pn_transport_t *transport, const char *bytes, size_t available)
-{
- if (!transport) return PN_ARG_ERR;
- if (available == 0) {
- return pn_transport_close_tail(transport);
- }
- const size_t original = available;
- ssize_t capacity = pn_transport_capacity(transport);
- if (capacity < 0) return capacity;
- while (available && capacity) {
- char *dest = pn_transport_tail(transport);
- assert(dest);
- size_t count = pn_min( (size_t)capacity, available );
- memmove( dest, bytes, count );
- available -= count;
- bytes += count;
- int rc = pn_transport_process( transport, count );
- if (rc < 0) return rc;
- capacity = pn_transport_capacity(transport);
- if (capacity < 0) return capacity;
- }
-
- return original - available;
-}
-
-// process pending input until none remaining or EOS
-static ssize_t transport_consume(pn_transport_t *transport)
-{
- // This allows whatever is driving the I/O to set the error
- // condition on the transport before doing pn_transport_close_head()
- // or pn_transport_close_tail(). This allows all transport errors to
- // flow to the app the same way, but provides cleaner error messages
- // since we don't try to look for a protocol header when, e.g. the
- // connection was refused.
- if (!transport->bytes_input && transport->tail_closed &&
- pn_condition_is_set(&transport->condition)) {
- pn_do_error(transport, NULL, NULL);
- return PN_EOS;
- }
-
- size_t consumed = 0;
-
- while (transport->input_pending || transport->tail_closed) {
- ssize_t n;
- n = transport->io_layers[0]->
- process_input( transport, 0,
- transport->input_buf + consumed,
- transport->input_pending );
- if (n > 0) {
- consumed += n;
- transport->input_pending -= n;
- } else if (n == 0) {
- break;
- } else {
- assert(n == PN_EOS);
- if (transport->trace & (PN_TRACE_RAW | PN_TRACE_FRM))
- pn_transport_log(transport, " <- EOS");
- transport->input_pending = 0; // XXX ???
- return n;
- }
- }
-
- if (transport->input_pending && consumed) {
- memmove( transport->input_buf, &transport->input_buf[consumed], transport->input_pending );
- }
-
- return consumed;
-}
-
-static int pni_process_conn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == CONNECTION)
- {
- if (!(endpoint->state & PN_LOCAL_UNINIT) && !transport->open_sent)
- {
- // as per the recommendation in the spec, advertise half our
- // actual timeout to the remote
- const pn_millis_t idle_timeout = transport->local_idle_timeout
- ? (transport->local_idle_timeout/2)
- : 0;
- pn_connection_t *connection = (pn_connection_t *) endpoint;
- const char *cid = pn_string_get(connection->container);
- pni_calculate_channel_max(transport);
- int err = pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[SS?I?H?InnCCC]", OPEN,
- cid ? cid : "",
- pn_string_get(connection->hostname),
- // if not zero, advertise our max frame size and idle timeout
- (bool)transport->local_max_frame, transport->local_max_frame,
- (bool)transport->channel_max, transport->channel_max,
- (bool)idle_timeout, idle_timeout,
- connection->offered_capabilities,
- connection->desired_capabilities,
- connection->properties);
- if (err) return err;
- transport->open_sent = true;
- }
- }
-
- return 0;
-}
-
-static uint16_t allocate_alias(pn_hash_t *aliases, uint32_t max_index, int * valid)
-{
- for (uint32_t i = 0; i <= max_index; i++) {
- if (!pn_hash_get(aliases, i)) {
- * valid = 1;
- return i;
- }
- }
-
- * valid = 0;
- return 0;
-}
-
-static size_t pni_session_outgoing_window(pn_session_t *ssn)
-{
- return ssn->outgoing_window;
-}
-
-static size_t pni_session_incoming_window(pn_session_t *ssn)
-{
- uint32_t size = ssn->connection->transport->local_max_frame;
- if (!size) {
- return 2147483647; // biggest legal value
- } else {
- return (ssn->incoming_capacity - ssn->incoming_bytes)/size;
- }
-}
-
-static int pni_map_local_channel(pn_session_t *ssn)
-{
- pn_transport_t *transport = ssn->connection->transport;
- pn_session_state_t *state = &ssn->state;
- int valid;
- uint16_t channel = allocate_alias(transport->local_channels, transport->channel_max, & valid);
- if (!valid) {
- return 0;
- }
- state->local_channel = channel;
- pn_hash_put(transport->local_channels, channel, ssn);
- pn_ep_incref(&ssn->endpoint);
- return 1;
-}
-
-static int pni_process_ssn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == SESSION && transport->open_sent)
- {
- pn_session_t *ssn = (pn_session_t *) endpoint;
- pn_session_state_t *state = &ssn->state;
- if (!(endpoint->state & PN_LOCAL_UNINIT) && state->local_channel == (uint16_t) -1)
- {
- if (! pni_map_local_channel(ssn)) {
- pn_transport_logf(transport, "unable to find an open available channel within limit of %d", transport->channel_max );
- return PN_ERR;
- }
- state->incoming_window = pni_session_incoming_window(ssn);
- state->outgoing_window = pni_session_outgoing_window(ssn);
- pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?HIII]", BEGIN,
- ((int16_t) state->remote_channel >= 0), state->remote_channel,
- state->outgoing_transfer_count,
- state->incoming_window,
- state->outgoing_window);
- }
- }
-
- return 0;
-}
-
-static const char *expiry_symbol(pn_expiry_policy_t policy)
-{
- switch (policy)
- {
- case PN_EXPIRE_WITH_LINK:
- return "link-detach";
- case PN_EXPIRE_WITH_SESSION:
- return NULL;
- case PN_EXPIRE_WITH_CONNECTION:
- return "connection-close";
- case PN_EXPIRE_NEVER:
- return "never";
- }
- return NULL;
-}
-
-static int pni_map_local_handle(pn_link_t *link) {
- pn_link_state_t *state = &link->state;
- pn_session_state_t *ssn_state = &link->session->state;
- int valid;
- // XXX TODO MICK: once changes are made to handle_max, change this hardcoded value to something reasonable.
- state->local_handle = allocate_alias(ssn_state->local_handles, 65536, & valid);
- if ( ! valid )
- return 0;
- pn_hash_put(ssn_state->local_handles, state->local_handle, link);
- pn_ep_incref(&link->endpoint);
- return 1;
-}
-
-static int pni_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (transport->open_sent && (endpoint->type == SENDER ||
- endpoint->type == RECEIVER))
- {
- pn_link_t *link = (pn_link_t *) endpoint;
- pn_session_state_t *ssn_state = &link->session->state;
- pn_link_state_t *state = &link->state;
- if (((int16_t) ssn_state->local_channel >= 0) &&
- !(endpoint->state & PN_LOCAL_UNINIT) && state->local_handle == (uint32_t) -1)
- {
- pni_map_local_handle(link);
- const pn_distribution_mode_t dist_mode = link->source.distribution_mode;
- if (link->target.type == PN_COORDINATOR) {
- int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
- "DL[SIoBB?DL[SIsIoC?sCnCC]DL[C]nnI]", ATTACH,
- pn_string_get(link->name),
- state->local_handle,
- endpoint->type == RECEIVER,
- link->snd_settle_mode,
- link->rcv_settle_mode,
- (bool) link->source.type, SOURCE,
- pn_string_get(link->source.address),
- link->source.durability,
- expiry_symbol(link->source.expiry_policy),
- link->source.timeout,
- link->source.dynamic,
- link->source.properties,
- (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
- link->source.filter,
- link->source.outcomes,
- link->source.capabilities,
- COORDINATOR, link->target.capabilities,
- 0);
- if (err) return err;
- } else {
- int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
- "DL[SIoBB?DL[SIsIoC?sCnCC]?DL[SIsIoCC]nnI]", ATTACH,
- pn_string_get(link->name),
- state->local_handle,
- endpoint->type == RECEIVER,
- link->snd_settle_mode,
- link->rcv_settle_mode,
- (bool) link->source.type, SOURCE,
- pn_string_get(link->source.address),
- link->source.durability,
- expiry_symbol(link->source.expiry_policy),
- link->source.timeout,
- link->source.dynamic,
- link->source.properties,
- (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
- link->source.filter,
- link->source.outcomes,
- link->source.capabilities,
- (bool) link->target.type, TARGET,
- pn_string_get(link->target.address),
- link->target.durability,
- expiry_symbol(link->target.expiry_policy),
- link->target.timeout,
- link->target.dynamic,
- link->target.properties,
- link->target.capabilities,
- 0);
- if (err) return err;
- }
- }
- }
-
- return 0;
-}
-
-static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link)
-{
- ssn->state.incoming_window = pni_session_incoming_window(ssn);
- ssn->state.outgoing_window = pni_session_outgoing_window(ssn);
- bool linkq = (bool) link;
- pn_link_state_t *state = &link->state;
- return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[?IIII?I?I?In?o]", FLOW,
- (int16_t) ssn->state.remote_channel >= 0, ssn->state.incoming_transfer_count,
- ssn->state.incoming_window,
- ssn->state.outgoing_transfer_count,
- ssn->state.outgoing_window,
- linkq, linkq ? state->local_handle : 0,
- linkq, linkq ? state->delivery_count : 0,
- linkq, linkq ? state->link_credit : 0,
- linkq, linkq ? link->drain : false);
-}
-
-static int pni_process_flow_receiver(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == RECEIVER && endpoint->state & PN_LOCAL_ACTIVE)
- {
- pn_link_t *rcv = (pn_link_t *) endpoint;
- pn_session_t *ssn = rcv->session;
- pn_link_state_t *state = &rcv->state;
- if ((int16_t) ssn->state.local_channel >= 0 &&
- (int32_t) state->local_handle >= 0 &&
- ((rcv->drain || state->link_credit != rcv->credit - rcv->queued) || !ssn->state.incoming_window)) {
- state->link_credit = rcv->credit - rcv->queued;
- return pni_post_flow(transport, ssn, rcv);
- }
- }
-
- return 0;
-}
-
-static int pni_flush_disp(pn_transport_t *transport, pn_session_t *ssn)
-{
- uint64_t code = ssn->state.disp_code;
- bool settled = ssn->state.disp_settled;
- if (ssn->state.disp) {
- int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[oIIo?DL[]]", DISPOSITION,
- ssn->state.disp_type, ssn->state.disp_first, ssn->state.disp_last,
- settled, (bool)code, code);
- if (err) return err;
- ssn->state.disp_type = 0;
- ssn->state.disp_code = 0;
- ssn->state.disp_settled = 0;
- ssn->state.disp_first = 0;
- ssn->state.disp_last = 0;
- ssn->state.disp = false;
- }
- return 0;
-}
-
-static int pni_post_disp(pn_transport_t *transport, pn_delivery_t *delivery)
-{
- pn_link_t *link = delivery->link;
- pn_session_t *ssn = link->session;
- pn_session_state_t *ssn_state = &ssn->state;
- pn_modified(transport->connection, &link->session->endpoint, false);
- pn_delivery_state_t *state = &delivery->state;
- assert(state->init);
- bool role = (link->endpoint.type == RECEIVER);
- uint64_t code = delivery->local.type;
-
- if (!code && !delivery->local.settled) {
- return 0;
- }
-
- if (!pni_disposition_batchable(&delivery->local)) {
- pn_data_clear(transport->disp_data);
- PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
- return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel,
- "DL[oIIo?DLC]", DISPOSITION,
- role, state->id, state->id, delivery->local.settled,
- (bool)code, code, transport->disp_data);
- }
-
- if (ssn_state->disp && code == ssn_state->disp_code &&
- delivery->local.settled == ssn_state->disp_settled &&
- ssn_state->disp_type == role) {
- if (state->id == ssn_state->disp_first - 1) {
- ssn_state->disp_first = state->id;
- return 0;
- } else if (state->id == ssn_state->disp_last + 1) {
- ssn_state->disp_last = state->id;
- return 0;
- }
- }
-
- if (ssn_state->disp) {
- int err = pni_flush_disp(transport, ssn);
- if (err) return err;
- }
-
- ssn_state->disp_type = role;
- ssn_state->disp_code = code;
- ssn_state->disp_settled = delivery->local.settled;
- ssn_state->disp_first = state->id;
- ssn_state->disp_last = state->id;
- ssn_state->disp = true;
-
- return 0;
-}
-
-static int pni_process_tpwork_sender(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
-{
- *settle = false;
- pn_link_t *link = delivery->link;
- pn_session_state_t *ssn_state = &link->session->state;
- pn_link_state_t *link_state = &link->state;
- bool xfr_posted = false;
- if ((int16_t) ssn_state->local_channel >= 0 && (int32_t) link_state->local_handle >= 0) {
- pn_delivery_state_t *state = &delivery->state;
- if (!state->sent && (delivery->done || pn_buffer_size(delivery->bytes) > 0) &&
- ssn_state->remote_incoming_window > 0 && link_state->link_credit > 0) {
- if (!state->init) {
- state = pni_delivery_map_push(&ssn_state->outgoing, delivery);
- }
-
- pn_bytes_t bytes = pn_buffer_bytes(delivery->bytes);
- size_t full_size = bytes.size;
- pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
- pn_data_clear(transport->disp_data);
- PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
- int count = pni_post_amqp_transfer_frame(transport,
- ssn_state->local_channel,
- link_state->local_handle,
- state->id, &bytes, &tag,
- 0, // message-format
- delivery->local.settled,
- !delivery->done,
- ssn_state->remote_incoming_window,
- delivery->local.type, transport->disp_data);
- if (count < 0) return count;
- xfr_posted = true;
- ssn_state->outgoing_transfer_count += count;
- ssn_state->remote_incoming_window -= count;
-
- int sent = full_size - bytes.size;
- pn_buffer_trim(delivery->bytes, sent, 0);
- link->session->outgoing_bytes -= sent;
- if (!pn_buffer_size(delivery->bytes) && delivery->done) {
- state->sent = true;
- link_state->delivery_count++;
- link_state->link_credit--;
- link->queued--;
- link->session->outgoing_deliveries--;
- }
-
- pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
- }
- }
-
- pn_delivery_state_t *state = delivery->state.init ? &delivery->state : NULL;
- if ((int16_t) ssn_state->local_channel >= 0 && !delivery->remote.settled
- && state && state->sent && !xfr_posted) {
- int err = pni_post_disp(transport, delivery);
- if (err) return err;
- }
-
- *settle = delivery->local.settled && state && state->sent;
- return 0;
-}
-
-static int pni_process_tpwork_receiver(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
-{
- *settle = false;
- pn_link_t *link = delivery->link;
- // XXX: need to prevent duplicate disposition sending
- pn_session_t *ssn = link->session;
- if ((int16_t) ssn->state.local_channel >= 0 && !delivery->remote.settled && delivery->state.init) {
- int err = pni_post_disp(transport, delivery);
- if (err) return err;
- }
-
- // XXX: need to centralize this policy and improve it
- if (!ssn->state.incoming_window) {
- int err = pni_post_flow(transport, ssn, link);
- if (err) return err;
- }
-
- *settle = delivery->local.settled;
- return 0;
-}
-
-static int pni_process_tpwork(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == CONNECTION && !transport->close_sent)
- {
- pn_connection_t *conn = (pn_connection_t *) endpoint;
- pn_delivery_t *delivery = conn->tpwork_head;
- while (delivery)
- {
- pn_delivery_t *tp_next = delivery->tpwork_next;
- bool settle = false;
-
- pn_link_t *link = delivery->link;
- pn_delivery_map_t *dm = NULL;
- if (pn_link_is_sender(link)) {
- dm = &link->session->state.outgoing;
- int err = pni_process_tpwork_sender(transport, delivery, &settle);
- if (err) return err;
- } else {
- dm = &link->session->state.incoming;
- int err = pni_process_tpwork_receiver(transport, delivery, &settle);
- if (err) return err;
- }
-
- if (settle) {
- pn_full_settle(dm, delivery);
- } else if (!pn_delivery_buffered(delivery)) {
- pn_clear_tpwork(delivery);
- }
-
- delivery = tp_next;
- }
- }
-
- return 0;
-}
-
-static int pni_process_flush_disp(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == SESSION) {
- pn_session_t *session = (pn_session_t *) endpoint;
- pn_session_state_t *state = &session->state;
- if ((int16_t) state->local_channel >= 0 && !transport->close_sent)
- {
- int err = pni_flush_disp(transport, session);
- if (err) return err;
- }
- }
-
- return 0;
-}
-
-static int pni_process_flow_sender(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == SENDER && endpoint->state & PN_LOCAL_ACTIVE)
- {
- pn_link_t *snd = (pn_link_t *) endpoint;
- pn_session_t *ssn = snd->session;
- pn_link_state_t *state = &snd->state;
- if ((int16_t) ssn->state.local_channel >= 0 &&
- (int32_t) state->local_handle >= 0 &&
- snd->drain && snd->drained) {
- pn_delivery_t *tail = snd->unsettled_tail;
- if (!tail || !pn_delivery_buffered(tail)) {
- state->delivery_count += state->link_credit;
- state->link_credit = 0;
- snd->drained = 0;
- return pni_post_flow(transport, ssn, snd);
- }
- }
- }
-
- return 0;
-}
-
-static void pni_unmap_local_handle(pn_link_t *link) {
- pn_link_state_t *state = &link->state;
- uintptr_t handle = state->local_handle;
- state->local_handle = -2;
- if (pn_hash_get(link->session->state.local_handles, handle)) {
- pn_ep_decref(&link->endpoint);
- }
- // may delete link
- pn_hash_del(link->session->state.local_handles, handle);
-}
-
-static int pni_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == SENDER || endpoint->type == RECEIVER)
- {
- pn_link_t *link = (pn_link_t *) endpoint;
- pn_session_t *session = link->session;
- pn_session_state_t *ssn_state = &session->state;
- pn_link_state_t *state = &link->state;
- if (((endpoint->state & PN_LOCAL_CLOSED) || link->detached) && (int32_t) state->local_handle >= 0 &&
- (int16_t) ssn_state->local_channel >= 0 && !transport->close_sent) {
- if (pn_link_is_sender(link) && pn_link_queued(link) &&
- (int32_t) state->remote_handle != -2 &&
- (int16_t) ssn_state->remote_channel != -2 &&
- !transport->close_rcvd) return 0;
-
- const char *name = NULL;
- const char *description = NULL;
- pn_data_t *info = NULL;
-
- if (pn_condition_is_set(&endpoint->condition)) {
- name = pn_condition_get_name(&endpoint->condition);
- description = pn_condition_get_description(&endpoint->condition);
- info = pn_condition_info(&endpoint->condition);
- }
-
- int err =
- pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
- "DL[Io?DL[sSC]]", DETACH, state->local_handle, !link->detached,
- (bool)name, ERROR, name, description, info);
- if (err) return err;
- pni_unmap_local_handle(link);
- }
-
- pn_clear_modified(transport->connection, endpoint);
- }
-
- return 0;
-}
-
-static bool pni_pointful_buffering(pn_transport_t *transport, pn_session_t *session)
-{
- if (transport->close_rcvd) return false;
- if (!transport->open_rcvd) return true;
-
- pn_connection_t *conn = transport->connection;
- pn_link_t *link = pn_link_head(conn, 0);
- while (link) {
- if (pn_link_is_sender(link) && pn_link_queued(link) > 0) {
- pn_session_t *ssn = link->session;
- if (session && session == ssn) {
- if ((int32_t) link->state.remote_handle != -2 &&
- (int16_t) session->state.remote_channel != -2) {
- return true;
- }
- }
- }
- link = pn_link_next(link, 0);
- }
-
- return false;
-}
-
-static void pni_unmap_local_channel(pn_session_t *ssn) {
- // XXX: should really update link state also
- pni_delivery_map_clear(&ssn->state.outgoing);
- pni_transport_unbind_handles(ssn->state.local_handles, false);
- pn_transport_t *transport = ssn->connection->transport;
- pn_session_state_t *state = &ssn->state;
- uintptr_t channel = state->local_channel;
- state->local_channel = -2;
- if (pn_hash_get(transport->local_channels, channel)) {
- pn_ep_decref(&ssn->endpoint);
- }
- // may delete session
- pn_hash_del(transport->local_channels, channel);
-}
-
-static int pni_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == SESSION)
- {
- pn_session_t *session = (pn_session_t *) endpoint;
- pn_session_state_t *state = &session->state;
- if (endpoint->state & PN_LOCAL_CLOSED && (int16_t) state->local_channel >= 0
- && !transport->close_sent)
- {
- if (pni_pointful_buffering(transport, session)) {
- return 0;
- }
-
- const char *name = NULL;
- const char *description = NULL;
- pn_data_t *info = NULL;
-
- if (pn_condition_is_set(&endpoint->condition)) {
- name = pn_condition_get_name(&endpoint->condition);
- description = pn_condition_get_description(&endpoint->condition);
- info = pn_condition_info(&endpoint->condition);
- }
-
- int err = pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?DL[sSC]]", END,
- (bool) name, ERROR, name, description, info);
- if (err) return err;
- pni_unmap_local_channel(session);
- }
-
- pn_clear_modified(transport->connection, endpoint);
- }
- return 0;
-}
-
-static int pni_process_conn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
- if (endpoint->type == CONNECTION)
- {
- if (endpoint->state & PN_LOCAL_CLOSED && !transport->close_sent) {
- if (pni_pointful_buffering(transport, NULL)) return 0;
- int err = pni_post_close(transport, NULL);
- if (err) return err;
- transport->close_sent = true;
- }
-
- pn_clear_modified(transport->connection, endpoint);
- }
- return 0;
-}
-
-static int pni_phase(pn_transport_t *transport, int (*phase)(pn_transport_t *, pn_endpoint_t *))
-{
- pn_connection_t *conn = transport->connection;
- pn_endpoint_t *endpoint = conn->transport_head;
- while (endpoint)
- {
- pn_endpoint_t *next = endpoint->transport_next;
- int err = phase(transport, endpoint);
- if (err) return err;
- endpoint = next;
- }
- return 0;
-}
-
-static int pni_process(pn_transport_t *transport)
-{
- int err;
- if ((err = pni_phase(transport, pni_process_conn_setup))) return err;
- if ((err = pni_phase(transport, pni_process_ssn_setup))) return err;
- if ((err = pni_phase(transport, pni_process_link_setup))) return err;
- if ((err = pni_phase(transport, pni_process_flow_receiver))) return err;
-
- // XXX: this has to happen two times because we might settle stuff
- // on the first pass and create space for more work to be done on the
- // second pass
- if ((err = pni_phase(transport, pni_process_tpwork))) return err;
- if ((err = pni_phase(transport, pni_process_tpwork))) return err;
-
- if ((err = pni_phase(transport, pni_process_flush_disp))) return err;
-
- if ((err = pni_phase(transport, pni_process_flow_sender))) return err;
- if ((err = pni_phase(transport, pni_process_link_teardown))) return err;
- if ((err = pni_phase(transport, pni_process_ssn_teardown))) return err;
- if ((err = pni_phase(transport, pni_process_conn_teardown))) return err;
-
- if (transport->connection->tpwork_head) {
- pn_modified(transport->connection, &transport->connection->endpoint, false);
- }
-
- return 0;
-}
-
-#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
-
-static void pn_error_amqp(pn_transport_t* transport, unsigned int layer)
-{
- if (!transport->close_sent) {
- if (!transport->open_sent) {
- pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[S]", OPEN, "");
- }
-
- pni_post_close(transport, &transport->condition);
- transport->close_sent = true;
- }
- transport->halt = true;
- transport->done_processing = true;
-}
-
-static ssize_t pn_input_read_amqp_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
-{
- bool eos = pn_transport_capacity(transport)==PN_EOS;
- pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
- switch (protocol) {
- case PNI_PROTOCOL_AMQP1:
- if (transport->io_layers[layer] == &amqp_read_header_layer) {
- transport->io_layers[layer] = &amqp_layer;
- } else {
- transport->io_layers[layer] = &amqp_write_header_layer;
- }
- if (transport->trace & PN_TRACE_FRM)
- pn_transport_logf(transport, " <- %s", "AMQP");
- return 8;
- case PNI_PROTOCOL_INSUFFICIENT:
- if (!eos) return 0;
- /* Fallthru */
- default:
- break;
- }
- char quoted[1024];
- pn_quote_data(quoted, 1024, bytes, available);
- pn_do_error(transport, "amqp:connection:framing-error",
- "%s header mismatch: %s ['%s']%s", "AMQP", pni_protocol_name(protocol), quoted,
- !eos ? "" : " (connection aborted)");
- return PN_EOS;
-}
-
-static ssize_t pn_input_read_amqp(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
-{
- if (transport->close_rcvd) {
- if (available > 0) {
- pn_do_error(transport, "amqp:connection:framing-error", "data after close");
- return PN_EOS;
- }
- }
-
- if (!transport->close_rcvd && !available) {
- pn_do_error(transport, "amqp:connection:framing-error", "connection aborted");
- return PN_EOS;
- }
-
-
- ssize_t n = pn_dispatcher_input(transport, bytes, available, true, &transport->halt);
- if (n < 0) {
- //return pn_error_set(transport->error, n, "dispatch error");
- return PN_EOS;
- } else if (transport->close_rcvd) {
- return PN_EOS;
- } else {
- return n;
- }
-}
-
-/* process AMQP related timer events */
-static pn_timestamp_t pn_tick_amqp(pn_transport_t* transport, unsigned int layer, pn_timestamp_t now)
-{
- pn_timestamp_t timeout = 0;
-
- if (transport->local_idle_timeout) {
- if (transport->dead_remote_deadline == 0 ||
- transport->last_bytes_input != transport->bytes_input) {
- transport->dead_remote_deadlin
<TRUNCATED>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[13/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/message.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/message.c b/proton-c/src/core/message.c
new file mode 100644
index 0000000..f2fb20e
--- /dev/null
+++ b/proton-c/src/core/message.c
@@ -0,0 +1,862 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "platform/platform_fmt.h"
+#include "protocol.h"
+#include "util.h"
+
+#include <proton/message.h>
+#include <proton/object.h>
+#include <proton/codec.h>
+#include <proton/error.h>
+#include <proton/parser.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+// message
+
+struct pn_message_t {
+ pn_timestamp_t expiry_time;
+ pn_timestamp_t creation_time;
+ pn_data_t *id;
+ pn_string_t *user_id;
+ pn_string_t *address;
+ pn_string_t *subject;
+ pn_string_t *reply_to;
+ pn_data_t *correlation_id;
+ pn_string_t *content_type;
+ pn_string_t *content_encoding;
+ pn_string_t *group_id;
+ pn_string_t *reply_to_group_id;
+
+ pn_data_t *data;
+ pn_data_t *instructions;
+ pn_data_t *annotations;
+ pn_data_t *properties;
+ pn_data_t *body;
+
+ pn_error_t *error;
+
+ pn_sequence_t group_sequence;
+ pn_millis_t ttl;
+ uint32_t delivery_count;
+
+ uint8_t priority;
+
+ bool durable;
+ bool first_acquirer;
+ bool inferred;
+};
+
+void pn_message_finalize(void *obj)
+{
+ pn_message_t *msg = (pn_message_t *) obj;
+ pn_free(msg->user_id);
+ pn_free(msg->address);
+ pn_free(msg->subject);
+ pn_free(msg->reply_to);
+ pn_free(msg->content_type);
+ pn_free(msg->content_encoding);
+ pn_free(msg->group_id);
+ pn_free(msg->reply_to_group_id);
+ pn_data_free(msg->id);
+ pn_data_free(msg->correlation_id);
+ pn_data_free(msg->data);
+ pn_data_free(msg->instructions);
+ pn_data_free(msg->annotations);
+ pn_data_free(msg->properties);
+ pn_data_free(msg->body);
+ pn_error_free(msg->error);
+}
+
+int pn_message_inspect(void *obj, pn_string_t *dst)
+{
+ pn_message_t *msg = (pn_message_t *) obj;
+ int err = pn_string_addf(dst, "Message{");
+ if (err) return err;
+
+ bool comma = false;
+
+ if (pn_string_get(msg->address)) {
+ err = pn_string_addf(dst, "address=");
+ if (err) return err;
+ err = pn_inspect(msg->address, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->durable) {
+ err = pn_string_addf(dst, "durable=%i, ", msg->durable);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->priority != PN_DEFAULT_PRIORITY) {
+ err = pn_string_addf(dst, "priority=%i, ", msg->priority);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->ttl) {
+ err = pn_string_addf(dst, "ttl=%" PRIu32 ", ", msg->ttl);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->first_acquirer) {
+ err = pn_string_addf(dst, "first_acquirer=%i, ", msg->first_acquirer);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->delivery_count) {
+ err = pn_string_addf(dst, "delivery_count=%" PRIu32 ", ", msg->delivery_count);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_data_size(msg->id)) {
+ err = pn_string_addf(dst, "id=");
+ if (err) return err;
+ err = pn_inspect(msg->id, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_string_get(msg->user_id)) {
+ err = pn_string_addf(dst, "user_id=");
+ if (err) return err;
+ err = pn_inspect(msg->user_id, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_string_get(msg->subject)) {
+ err = pn_string_addf(dst, "subject=");
+ if (err) return err;
+ err = pn_inspect(msg->subject, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_string_get(msg->reply_to)) {
+ err = pn_string_addf(dst, "reply_to=");
+ if (err) return err;
+ err = pn_inspect(msg->reply_to, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_data_size(msg->correlation_id)) {
+ err = pn_string_addf(dst, "correlation_id=");
+ if (err) return err;
+ err = pn_inspect(msg->correlation_id, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_string_get(msg->content_type)) {
+ err = pn_string_addf(dst, "content_type=");
+ if (err) return err;
+ err = pn_inspect(msg->content_type, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_string_get(msg->content_encoding)) {
+ err = pn_string_addf(dst, "content_encoding=");
+ if (err) return err;
+ err = pn_inspect(msg->content_encoding, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->expiry_time) {
+ err = pn_string_addf(dst, "expiry_time=%" PRIi64 ", ", msg->expiry_time);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->creation_time) {
+ err = pn_string_addf(dst, "creation_time=%" PRIi64 ", ", msg->creation_time);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_string_get(msg->group_id)) {
+ err = pn_string_addf(dst, "group_id=");
+ if (err) return err;
+ err = pn_inspect(msg->group_id, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->group_sequence) {
+ err = pn_string_addf(dst, "group_sequence=%" PRIi32 ", ", msg->group_sequence);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_string_get(msg->reply_to_group_id)) {
+ err = pn_string_addf(dst, "reply_to_group_id=");
+ if (err) return err;
+ err = pn_inspect(msg->reply_to_group_id, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (msg->inferred) {
+ err = pn_string_addf(dst, "inferred=%i, ", msg->inferred);
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_data_size(msg->instructions)) {
+ err = pn_string_addf(dst, "instructions=");
+ if (err) return err;
+ err = pn_inspect(msg->instructions, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_data_size(msg->annotations)) {
+ err = pn_string_addf(dst, "annotations=");
+ if (err) return err;
+ err = pn_inspect(msg->annotations, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_data_size(msg->properties)) {
+ err = pn_string_addf(dst, "properties=");
+ if (err) return err;
+ err = pn_inspect(msg->properties, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (pn_data_size(msg->body)) {
+ err = pn_string_addf(dst, "body=");
+ if (err) return err;
+ err = pn_inspect(msg->body, dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ comma = true;
+ }
+
+ if (comma) {
+ int err = pn_string_resize(dst, pn_string_size(dst) - 2);
+ if (err) return err;
+ }
+
+ return pn_string_addf(dst, "}");
+}
+
+#define pn_message_initialize NULL
+#define pn_message_hashcode NULL
+#define pn_message_compare NULL
+
+pn_message_t *pn_message()
+{
+ static const pn_class_t clazz = PN_CLASS(pn_message);
+ pn_message_t *msg = (pn_message_t *) pn_class_new(&clazz, sizeof(pn_message_t));
+ msg->durable = false;
+ msg->priority = PN_DEFAULT_PRIORITY;
+ msg->ttl = 0;
+ msg->first_acquirer = false;
+ msg->delivery_count = 0;
+ msg->id = pn_data(1);
+ msg->user_id = pn_string(NULL);
+ msg->address = pn_string(NULL);
+ msg->subject = pn_string(NULL);
+ msg->reply_to = pn_string(NULL);
+ msg->correlation_id = pn_data(1);
+ msg->content_type = pn_string(NULL);
+ msg->content_encoding = pn_string(NULL);
+ msg->expiry_time = 0;
+ msg->creation_time = 0;
+ msg->group_id = pn_string(NULL);
+ msg->group_sequence = 0;
+ msg->reply_to_group_id = pn_string(NULL);
+
+ msg->inferred = false;
+ msg->data = pn_data(16);
+ msg->instructions = pn_data(16);
+ msg->annotations = pn_data(16);
+ msg->properties = pn_data(16);
+ msg->body = pn_data(16);
+
+ msg->error = pn_error();
+ return msg;
+}
+
+void pn_message_free(pn_message_t *msg)
+{
+ pn_free(msg);
+}
+
+void pn_message_clear(pn_message_t *msg)
+{
+ msg->durable = false;
+ msg->priority = PN_DEFAULT_PRIORITY;
+ msg->ttl = 0;
+ msg->first_acquirer = false;
+ msg->delivery_count = 0;
+ pn_data_clear(msg->id);
+ pn_string_clear(msg->user_id);
+ pn_string_clear(msg->address);
+ pn_string_clear(msg->subject);
+ pn_string_clear(msg->reply_to);
+ pn_data_clear(msg->correlation_id);
+ pn_string_clear(msg->content_type);
+ pn_string_clear(msg->content_encoding);
+ msg->expiry_time = 0;
+ msg->creation_time = 0;
+ pn_string_clear(msg->group_id);
+ msg->group_sequence = 0;
+ pn_string_clear(msg->reply_to_group_id);
+ msg->inferred = false;
+ pn_data_clear(msg->data);
+ pn_data_clear(msg->instructions);
+ pn_data_clear(msg->annotations);
+ pn_data_clear(msg->properties);
+ pn_data_clear(msg->body);
+}
+
+int pn_message_errno(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_error_code(msg->error);
+}
+
+pn_error_t *pn_message_error(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->error;
+}
+
+bool pn_message_is_inferred(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->inferred;
+}
+
+int pn_message_set_inferred(pn_message_t *msg, bool inferred)
+{
+ assert(msg);
+ msg->inferred = inferred;
+ return 0;
+}
+
+bool pn_message_is_durable(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->durable;
+}
+int pn_message_set_durable(pn_message_t *msg, bool durable)
+{
+ assert(msg);
+ msg->durable = durable;
+ return 0;
+}
+
+
+uint8_t pn_message_get_priority(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->priority;
+}
+int pn_message_set_priority(pn_message_t *msg, uint8_t priority)
+{
+ assert(msg);
+ msg->priority = priority;
+ return 0;
+}
+
+pn_millis_t pn_message_get_ttl(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->ttl;
+}
+int pn_message_set_ttl(pn_message_t *msg, pn_millis_t ttl)
+{
+ assert(msg);
+ msg->ttl = ttl;
+ return 0;
+}
+
+bool pn_message_is_first_acquirer(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->first_acquirer;
+}
+int pn_message_set_first_acquirer(pn_message_t *msg, bool first)
+{
+ assert(msg);
+ msg->first_acquirer = first;
+ return 0;
+}
+
+uint32_t pn_message_get_delivery_count(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->delivery_count;
+}
+int pn_message_set_delivery_count(pn_message_t *msg, uint32_t count)
+{
+ assert(msg);
+ msg->delivery_count = count;
+ return 0;
+}
+
+pn_data_t *pn_message_id(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->id;
+}
+pn_atom_t pn_message_get_id(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_data_get_atom(msg->id);
+}
+int pn_message_set_id(pn_message_t *msg, pn_atom_t id)
+{
+ assert(msg);
+ pn_data_rewind(msg->id);
+ return pn_data_put_atom(msg->id, id);
+}
+
+static pn_bytes_t pn_string_get_bytes(pn_string_t *string)
+{
+ return pn_bytes(pn_string_size(string), (char *) pn_string_get(string));
+}
+
+static int pn_string_set_bytes(pn_string_t *string, pn_bytes_t bytes)
+{
+ return pn_string_setn(string, bytes.start, bytes.size);
+}
+
+pn_bytes_t pn_message_get_user_id(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get_bytes(msg->user_id);
+}
+int pn_message_set_user_id(pn_message_t *msg, pn_bytes_t user_id)
+{
+ assert(msg);
+ return pn_string_set_bytes(msg->user_id, user_id);
+}
+
+const char *pn_message_get_address(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get(msg->address);
+}
+int pn_message_set_address(pn_message_t *msg, const char *address)
+{
+ assert(msg);
+ return pn_string_set(msg->address, address);
+}
+
+const char *pn_message_get_subject(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get(msg->subject);
+}
+int pn_message_set_subject(pn_message_t *msg, const char *subject)
+{
+ assert(msg);
+ return pn_string_set(msg->subject, subject);
+}
+
+const char *pn_message_get_reply_to(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get(msg->reply_to);
+}
+int pn_message_set_reply_to(pn_message_t *msg, const char *reply_to)
+{
+ assert(msg);
+ return pn_string_set(msg->reply_to, reply_to);
+}
+
+pn_data_t *pn_message_correlation_id(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->correlation_id;
+}
+pn_atom_t pn_message_get_correlation_id(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_data_get_atom(msg->correlation_id);
+}
+int pn_message_set_correlation_id(pn_message_t *msg, pn_atom_t atom)
+{
+ assert(msg);
+ pn_data_rewind(msg->correlation_id);
+ return pn_data_put_atom(msg->correlation_id, atom);
+}
+
+const char *pn_message_get_content_type(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get(msg->content_type);
+}
+int pn_message_set_content_type(pn_message_t *msg, const char *type)
+{
+ assert(msg);
+ return pn_string_set(msg->content_type, type);
+}
+
+const char *pn_message_get_content_encoding(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get(msg->content_encoding);
+}
+int pn_message_set_content_encoding(pn_message_t *msg, const char *encoding)
+{
+ assert(msg);
+ return pn_string_set(msg->content_encoding, encoding);
+}
+
+pn_timestamp_t pn_message_get_expiry_time(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->expiry_time;
+}
+int pn_message_set_expiry_time(pn_message_t *msg, pn_timestamp_t time)
+{
+ assert(msg);
+ msg->expiry_time = time;
+ return 0;
+}
+
+pn_timestamp_t pn_message_get_creation_time(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->creation_time;
+}
+int pn_message_set_creation_time(pn_message_t *msg, pn_timestamp_t time)
+{
+ assert(msg);
+ msg->creation_time = time;
+ return 0;
+}
+
+const char *pn_message_get_group_id(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get(msg->group_id);
+}
+int pn_message_set_group_id(pn_message_t *msg, const char *group_id)
+{
+ assert(msg);
+ return pn_string_set(msg->group_id, group_id);
+}
+
+pn_sequence_t pn_message_get_group_sequence(pn_message_t *msg)
+{
+ assert(msg);
+ return msg->group_sequence;
+}
+int pn_message_set_group_sequence(pn_message_t *msg, pn_sequence_t n)
+{
+ assert(msg);
+ msg->group_sequence = n;
+ return 0;
+}
+
+const char *pn_message_get_reply_to_group_id(pn_message_t *msg)
+{
+ assert(msg);
+ return pn_string_get(msg->reply_to_group_id);
+}
+int pn_message_set_reply_to_group_id(pn_message_t *msg, const char *reply_to_group_id)
+{
+ assert(msg);
+ return pn_string_set(msg->reply_to_group_id, reply_to_group_id);
+}
+
+int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size)
+{
+ assert(msg && bytes && size);
+
+ pn_message_clear(msg);
+
+ while (size) {
+ pn_data_clear(msg->data);
+ ssize_t used = pn_data_decode(msg->data, bytes, size);
+ if (used < 0)
+ return pn_error_format(msg->error, used, "data error: %s",
+ pn_error_text(pn_data_error(msg->data)));
+ size -= used;
+ bytes += used;
+ bool scanned;
+ uint64_t desc;
+ int err = pn_data_scan(msg->data, "D?L.", &scanned, &desc);
+ if (err) return pn_error_format(msg->error, err, "data error: %s",
+ pn_error_text(pn_data_error(msg->data)));
+ if (!scanned) {
+ desc = 0;
+ }
+
+ pn_data_rewind(msg->data);
+ pn_data_next(msg->data);
+ pn_data_enter(msg->data);
+ pn_data_next(msg->data);
+
+ switch (desc) {
+ case HEADER:
+ err = pn_data_scan(msg->data, "D.[oBIoI]", &msg->durable, &msg->priority,
+ &msg->ttl, &msg->first_acquirer, &msg->delivery_count);
+ if (err) return pn_error_format(msg->error, err, "data error: %s",
+ pn_error_text(pn_data_error(msg->data)));
+ break;
+ case PROPERTIES:
+ {
+ pn_bytes_t user_id, address, subject, reply_to, ctype, cencoding,
+ group_id, reply_to_group_id;
+ pn_data_clear(msg->id);
+ pn_data_clear(msg->correlation_id);
+ err = pn_data_scan(msg->data, "D.[CzSSSCssttSIS]", msg->id,
+ &user_id, &address, &subject, &reply_to,
+ msg->correlation_id, &ctype, &cencoding,
+ &msg->expiry_time, &msg->creation_time, &group_id,
+ &msg->group_sequence, &reply_to_group_id);
+ if (err) return pn_error_format(msg->error, err, "data error: %s",
+ pn_error_text(pn_data_error(msg->data)));
+ err = pn_string_set_bytes(msg->user_id, user_id);
+ if (err) return pn_error_format(msg->error, err, "error setting user_id");
+ err = pn_string_setn(msg->address, address.start, address.size);
+ if (err) return pn_error_format(msg->error, err, "error setting address");
+ err = pn_string_setn(msg->subject, subject.start, subject.size);
+ if (err) return pn_error_format(msg->error, err, "error setting subject");
+ err = pn_string_setn(msg->reply_to, reply_to.start, reply_to.size);
+ if (err) return pn_error_format(msg->error, err, "error setting reply_to");
+ err = pn_string_setn(msg->content_type, ctype.start, ctype.size);
+ if (err) return pn_error_format(msg->error, err, "error setting content_type");
+ err = pn_string_setn(msg->content_encoding, cencoding.start,
+ cencoding.size);
+ if (err) return pn_error_format(msg->error, err, "error setting content_encoding");
+ err = pn_string_setn(msg->group_id, group_id.start, group_id.size);
+ if (err) return pn_error_format(msg->error, err, "error setting group_id");
+ err = pn_string_setn(msg->reply_to_group_id, reply_to_group_id.start,
+ reply_to_group_id.size);
+ if (err) return pn_error_format(msg->error, err, "error setting reply_to_group_id");
+ }
+ break;
+ case DELIVERY_ANNOTATIONS:
+ pn_data_narrow(msg->data);
+ err = pn_data_copy(msg->instructions, msg->data);
+ if (err) return err;
+ break;
+ case MESSAGE_ANNOTATIONS:
+ pn_data_narrow(msg->data);
+ err = pn_data_copy(msg->annotations, msg->data);
+ if (err) return err;
+ break;
+ case APPLICATION_PROPERTIES:
+ pn_data_narrow(msg->data);
+ err = pn_data_copy(msg->properties, msg->data);
+ if (err) return err;
+ break;
+ case DATA:
+ case AMQP_SEQUENCE:
+ case AMQP_VALUE:
+ pn_data_narrow(msg->data);
+ err = pn_data_copy(msg->body, msg->data);
+ if (err) return err;
+ break;
+ case FOOTER:
+ break;
+ default:
+ err = pn_data_copy(msg->body, msg->data);
+ if (err) return err;
+ break;
+ }
+ }
+
+ pn_data_clear(msg->data);
+ return 0;
+}
+
+int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size)
+{
+ if (!msg || !bytes || !size || !*size) return PN_ARG_ERR;
+ pn_data_clear(msg->data);
+ pn_message_data(msg, msg->data);
+ size_t remaining = *size;
+ ssize_t encoded = pn_data_encode(msg->data, bytes, remaining);
+ if (encoded < 0) {
+ if (encoded == PN_OVERFLOW) {
+ return encoded;
+ } else {
+ return pn_error_format(msg->error, encoded, "data error: %s",
+ pn_error_text(pn_data_error(msg->data)));
+ }
+ }
+ bytes += encoded;
+ remaining -= encoded;
+ *size -= remaining;
+ pn_data_clear(msg->data);
+ return 0;
+}
+
+int pn_message_data(pn_message_t *msg, pn_data_t *data)
+{
+ pn_data_clear(data);
+ int err = pn_data_fill(data, "DL[oB?IoI]", HEADER, msg->durable,
+ msg->priority, msg->ttl, msg->ttl, msg->first_acquirer,
+ msg->delivery_count);
+ if (err)
+ return pn_error_format(msg->error, err, "data error: %s",
+ pn_error_text(pn_data_error(data)));
+
+ if (pn_data_size(msg->instructions)) {
+ pn_data_put_described(data);
+ pn_data_enter(data);
+ pn_data_put_ulong(data, DELIVERY_ANNOTATIONS);
+ pn_data_rewind(msg->instructions);
+ err = pn_data_append(data, msg->instructions);
+ if (err)
+ return pn_error_format(msg->error, err, "data error: %s",
+ pn_error_text(pn_data_error(data)));
+ pn_data_exit(data);
+ }
+
+ if (pn_data_size(msg->annotations)) {
+ pn_data_put_described(data);
+ pn_data_enter(data);
+ pn_data_put_ulong(data, MESSAGE_ANNOTATIONS);
+ pn_data_rewind(msg->annotations);
+ err = pn_data_append(data, msg->annotations);
+ if (err)
+ return pn_error_format(msg->error, err, "data error: %s",
+ pn_error_text(pn_data_error(data)));
+ pn_data_exit(data);
+ }
+
+ err = pn_data_fill(data, "DL[CzSSSCssttSIS]", PROPERTIES,
+ msg->id,
+ pn_string_size(msg->user_id), pn_string_get(msg->user_id),
+ pn_string_get(msg->address),
+ pn_string_get(msg->subject),
+ pn_string_get(msg->reply_to),
+ msg->correlation_id,
+ pn_string_get(msg->content_type),
+ pn_string_get(msg->content_encoding),
+ msg->expiry_time,
+ msg->creation_time,
+ pn_string_get(msg->group_id),
+ msg->group_sequence,
+ pn_string_get(msg->reply_to_group_id));
+ if (err)
+ return pn_error_format(msg->error, err, "data error: %s",
+ pn_error_text(pn_data_error(data)));
+
+ if (pn_data_size(msg->properties)) {
+ pn_data_put_described(data);
+ pn_data_enter(data);
+ pn_data_put_ulong(data, APPLICATION_PROPERTIES);
+ pn_data_rewind(msg->properties);
+ err = pn_data_append(data, msg->properties);
+ if (err)
+ return pn_error_format(msg->error, err, "data error: %s",
+ pn_data_error(data));
+ pn_data_exit(data);
+ }
+
+ if (pn_data_size(msg->body)) {
+ pn_data_rewind(msg->body);
+ pn_data_next(msg->body);
+ pn_type_t body_type = pn_data_type(msg->body);
+ pn_data_rewind(msg->body);
+
+ pn_data_put_described(data);
+ pn_data_enter(data);
+ if (msg->inferred) {
+ switch (body_type) {
+ case PN_BINARY:
+ pn_data_put_ulong(data, DATA);
+ break;
+ case PN_LIST:
+ pn_data_put_ulong(data, AMQP_SEQUENCE);
+ break;
+ default:
+ pn_data_put_ulong(data, AMQP_VALUE);
+ break;
+ }
+ } else {
+ pn_data_put_ulong(data, AMQP_VALUE);
+ }
+ pn_data_append(data, msg->body);
+ }
+ return 0;
+}
+
+pn_data_t *pn_message_instructions(pn_message_t *msg)
+{
+ return msg ? msg->instructions : NULL;
+}
+
+pn_data_t *pn_message_annotations(pn_message_t *msg)
+{
+ return msg ? msg->annotations : NULL;
+}
+
+pn_data_t *pn_message_properties(pn_message_t *msg)
+{
+ return msg ? msg->properties : NULL;
+}
+
+pn_data_t *pn_message_body(pn_message_t *msg)
+{
+ return msg ? msg->body : NULL;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/iterator.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/iterator.c b/proton-c/src/core/object/iterator.c
new file mode 100644
index 0000000..61b3b8e
--- /dev/null
+++ b/proton-c/src/core/object/iterator.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_iterator_t {
+ pn_iterator_next_t next;
+ size_t size;
+ void *state;
+};
+
+static void pn_iterator_initialize(void *object)
+{
+ pn_iterator_t *it = (pn_iterator_t *) object;
+ it->next = NULL;
+ it->size = 0;
+ it->state = NULL;
+}
+
+static void pn_iterator_finalize(void *object)
+{
+ pn_iterator_t *it = (pn_iterator_t *) object;
+ free(it->state);
+}
+
+#define CID_pn_iterator CID_pn_object
+#define pn_iterator_hashcode NULL
+#define pn_iterator_compare NULL
+#define pn_iterator_inspect NULL
+
+pn_iterator_t *pn_iterator()
+{
+ static const pn_class_t clazz = PN_CLASS(pn_iterator);
+ pn_iterator_t *it = (pn_iterator_t *) pn_class_new(&clazz, sizeof(pn_iterator_t));
+ return it;
+}
+
+void *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next,
+ size_t size) {
+ assert(iterator);
+ assert(next);
+ iterator->next = next;
+ if (iterator->size < size) {
+ iterator->state = realloc(iterator->state, size);
+ }
+ return iterator->state;
+}
+
+void *pn_iterator_next(pn_iterator_t *iterator) {
+ assert(iterator);
+ if (iterator->next) {
+ void *result = iterator->next(iterator->state);
+ if (!result) iterator->next = NULL;
+ return result;
+ } else {
+ return NULL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/list.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/list.c b/proton-c/src/core/object/list.c
new file mode 100644
index 0000000..76c70d2
--- /dev/null
+++ b/proton-c/src/core/object/list.c
@@ -0,0 +1,267 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_list_t {
+ const pn_class_t *clazz;
+ size_t capacity;
+ size_t size;
+ void **elements;
+};
+
+size_t pn_list_size(pn_list_t *list)
+{
+ assert(list);
+ return list->size;
+}
+
+void *pn_list_get(pn_list_t *list, int index)
+{
+ assert(list); assert(list->size);
+ return list->elements[index % list->size];
+}
+
+void pn_list_set(pn_list_t *list, int index, void *value)
+{
+ assert(list); assert(list->size);
+ void *old = list->elements[index % list->size];
+ pn_class_decref(list->clazz, old);
+ list->elements[index % list->size] = value;
+ pn_class_incref(list->clazz, value);
+}
+
+static void pni_list_ensure(pn_list_t *list, size_t capacity)
+{
+ assert(list);
+ if (list->capacity < capacity) {
+ size_t newcap = list->capacity;
+ while (newcap < capacity) { newcap *= 2; }
+ list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
+ assert(list->elements);
+ list->capacity = newcap;
+ }
+}
+
+int pn_list_add(pn_list_t *list, void *value)
+{
+ assert(list);
+ pni_list_ensure(list, list->size + 1);
+ list->elements[list->size++] = value;
+ pn_class_incref(list->clazz, value);
+ return 0;
+}
+
+void *pn_list_pop(pn_list_t *list)
+{
+ assert(list);
+ if (list->size) {
+ return list->elements[--list->size];
+ } else {
+ return NULL;
+ }
+}
+
+ssize_t pn_list_index(pn_list_t *list, void *value)
+{
+ for (size_t i = 0; i < list->size; i++) {
+ if (pn_class_equals(list->clazz, list->elements[i], value)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+bool pn_list_remove(pn_list_t *list, void *value)
+{
+ assert(list);
+ ssize_t idx = pn_list_index(list, value);
+ if (idx < 0) {
+ return false;
+ } else {
+ pn_list_del(list, idx, 1);
+ }
+
+ return true;
+}
+
+void pn_list_del(pn_list_t *list, int index, int n)
+{
+ assert(list);
+ if (!list->size) { return; }
+ index %= list->size;
+
+ for (int i = 0; i < n; i++) {
+ pn_class_decref(list->clazz, list->elements[index + i]);
+ }
+
+ size_t slide = list->size - (index + n);
+ for (size_t i = 0; i < slide; i++) {
+ list->elements[index + i] = list->elements[index + n + i];
+ }
+
+ list->size -= n;
+}
+
+void pn_list_clear(pn_list_t *list)
+{
+ assert(list);
+ pn_list_del(list, 0, list->size);
+}
+
+void pn_list_minpush(pn_list_t *list, void *value)
+{
+ assert(list);
+ pn_list_add(list, value);
+ // we use one based indexing for the heap
+ void **heap = list->elements - 1;
+ int now = list->size;
+ while (now > 1 && pn_class_compare(list->clazz, heap[now/2], value) > 0) {
+ heap[now] = heap[now/2];
+ now /= 2;
+ }
+ heap[now] = value;
+}
+
+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;
+}
+
+typedef struct {
+ pn_list_t *list;
+ size_t index;
+} pni_list_iter_t;
+
+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;
+ }
+}
+
+void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
+{
+ pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
+ liter->list = list;
+ liter->index = 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);
+}
+
+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;
+}
+
+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;
+}
+
+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, "]");
+}
+
+#define pn_list_initialize NULL
+
+pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity)
+{
+ static const pn_class_t list_clazz = PN_CLASS(pn_list);
+
+ pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t));
+ list->clazz = clazz;
+ list->capacity = capacity ? capacity : 16;
+ list->elements = (void **) malloc(list->capacity * sizeof(void *));
+ list->size = 0;
+ return list;
+}
+
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/map.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/map.c b/proton-c/src/core/object/map.c
new file mode 100644
index 0000000..cd38f19
--- /dev/null
+++ b/proton-c/src/core/object/map.c
@@ -0,0 +1,461 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define PNI_ENTRY_FREE (0)
+#define PNI_ENTRY_LINK (1)
+#define PNI_ENTRY_TAIL (2)
+
+typedef struct {
+ void *key;
+ void *value;
+ size_t next;
+ uint8_t state;
+} pni_entry_t;
+
+struct pn_map_t {
+ const pn_class_t *key;
+ const pn_class_t *value;
+ pni_entry_t *entries;
+ size_t capacity;
+ size_t addressable;
+ size_t size;
+ uintptr_t (*hashcode)(void *key);
+ bool (*equals)(void *a, void *b);
+ float load_factor;
+};
+
+static void pn_map_finalize(void *object)
+{
+ pn_map_t *map = (pn_map_t *) object;
+
+ for (size_t i = 0; i < map->capacity; i++) {
+ if (map->entries[i].state != PNI_ENTRY_FREE) {
+ pn_class_decref(map->key, map->entries[i].key);
+ pn_class_decref(map->value, map->entries[i].value);
+ }
+ }
+
+ free(map->entries);
+}
+
+static uintptr_t pn_map_hashcode(void *object)
+{
+ pn_map_t *map = (pn_map_t *) object;
+
+ uintptr_t hashcode = 0;
+
+ for (size_t i = 0; i < map->capacity; i++) {
+ if (map->entries[i].state != PNI_ENTRY_FREE) {
+ void *key = map->entries[i].key;
+ void *value = map->entries[i].value;
+ hashcode += pn_hashcode(key) ^ pn_hashcode(value);
+ }
+ }
+
+ return hashcode;
+}
+
+static void pni_map_allocate(pn_map_t *map)
+{
+ map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t));
+ if (map->entries != NULL) {
+ for (size_t i = 0; i < map->capacity; i++) {
+ map->entries[i].key = NULL;
+ map->entries[i].value = NULL;
+ map->entries[i].next = 0;
+ map->entries[i].state = PNI_ENTRY_FREE;
+ }
+ }
+ map->size = 0;
+}
+
+static int pn_map_inspect(void *obj, pn_string_t *dst)
+{
+ assert(obj);
+ pn_map_t *map = (pn_map_t *) obj;
+ int err = pn_string_addf(dst, "{");
+ if (err) return err;
+ pn_handle_t entry = pn_map_head(map);
+ bool first = true;
+ while (entry) {
+ if (first) {
+ first = false;
+ } else {
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ }
+ err = pn_class_inspect(map->key, pn_map_key(map, entry), dst);
+ if (err) return err;
+ err = pn_string_addf(dst, ": ");
+ if (err) return err;
+ err = pn_class_inspect(map->value, pn_map_value(map, entry), dst);
+ if (err) return err;
+ entry = pn_map_next(map, entry);
+ }
+ return pn_string_addf(dst, "}");
+}
+
+#define pn_map_initialize NULL
+#define pn_map_compare NULL
+
+pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value,
+ size_t capacity, float load_factor)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_map);
+
+ pn_map_t *map = (pn_map_t *) pn_class_new(&clazz, sizeof(pn_map_t));
+ map->key = key;
+ map->value = value;
+ map->capacity = capacity ? capacity : 16;
+ map->addressable = (size_t) (map->capacity * 0.86);
+ if (!map->addressable) map->addressable = map->capacity;
+ map->load_factor = load_factor;
+ map->hashcode = pn_hashcode;
+ map->equals = pn_equals;
+ pni_map_allocate(map);
+ return map;
+}
+
+size_t pn_map_size(pn_map_t *map)
+{
+ assert(map);
+ return map->size;
+}
+
+static float pni_map_load(pn_map_t *map)
+{
+ return ((float) map->size) / ((float) map->addressable);
+}
+
+static bool pni_map_ensure(pn_map_t *map, size_t capacity)
+{
+ float load = pni_map_load(map);
+ if (capacity <= map->capacity && load <= map->load_factor) {
+ return false;
+ }
+
+ size_t oldcap = map->capacity;
+
+ while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
+ map->capacity *= 2;
+ map->addressable = (size_t) (0.86 * map->capacity);
+ }
+
+ pni_entry_t *entries = map->entries;
+ pni_map_allocate(map);
+
+ for (size_t i = 0; i < oldcap; i++) {
+ if (entries[i].state != PNI_ENTRY_FREE) {
+ void *key = entries[i].key;
+ void *value = entries[i].value;
+ pn_map_put(map, key, value);
+ }
+ }
+
+ for (size_t i = 0; i < oldcap; i++) {
+ if (entries[i].state != PNI_ENTRY_FREE) {
+ void *key = entries[i].key;
+ void *value = entries[i].value;
+ pn_class_decref(map->key, key);
+ pn_class_decref(map->value, value);
+ }
+ }
+
+ free(entries);
+ return true;
+}
+
+static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create)
+{
+ uintptr_t hashcode = map->hashcode(key);
+
+ pni_entry_t *entry = &map->entries[hashcode % map->addressable];
+ pni_entry_t *prev = NULL;
+
+ if (entry->state == PNI_ENTRY_FREE) {
+ if (create) {
+ entry->state = PNI_ENTRY_TAIL;
+ entry->key = key;
+ pn_class_incref(map->key, key);
+ map->size++;
+ return entry;
+ } else {
+ return NULL;
+ }
+ }
+
+ while (true) {
+ if (map->equals(entry->key, key)) {
+ if (pprev) *pprev = prev;
+ return entry;
+ }
+
+ if (entry->state == PNI_ENTRY_TAIL) {
+ break;
+ } else {
+ prev = entry;
+ entry = &map->entries[entry->next];
+ }
+ }
+
+ if (create) {
+ if (pni_map_ensure(map, map->size + 1)) {
+ // if we had to grow the table we need to start over
+ return pni_map_entry(map, key, pprev, create);
+ }
+
+ size_t empty = 0;
+ for (size_t i = 0; i < map->capacity; i++) {
+ size_t idx = map->capacity - i - 1;
+ if (map->entries[idx].state == PNI_ENTRY_FREE) {
+ empty = idx;
+ break;
+ }
+ }
+ entry->next = empty;
+ entry->state = PNI_ENTRY_LINK;
+ map->entries[empty].state = PNI_ENTRY_TAIL;
+ map->entries[empty].key = key;
+ pn_class_incref(map->key, key);
+ if (pprev) *pprev = entry;
+ map->size++;
+ return &map->entries[empty];
+ } else {
+ return NULL;
+ }
+}
+
+int pn_map_put(pn_map_t *map, void *key, void *value)
+{
+ assert(map);
+ pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
+ void *dref_val = entry->value;
+ entry->value = value;
+ pn_class_incref(map->value, value);
+ pn_class_decref(map->value, dref_val);
+ return 0;
+}
+
+void *pn_map_get(pn_map_t *map, void *key)
+{
+ assert(map);
+ pni_entry_t *entry = pni_map_entry(map, key, NULL, false);
+ return entry ? entry->value : NULL;
+}
+
+static void pni_map_rehash(pn_map_t *map, size_t index)
+{
+ //reinsert entries in chain starting at index
+ assert(map);
+ size_t i = index;
+ bool complete = false;
+ while (!complete) {
+ pni_entry_t *entry = &map->entries[i];
+ assert(entry);
+ assert(entry->state != PNI_ENTRY_FREE);
+ size_t current = i;
+ if (entry->state == PNI_ENTRY_TAIL) {
+ complete = true;
+ } else {
+ assert(entry->state == PNI_ENTRY_LINK);
+ i = entry->next;
+ }
+ uintptr_t hashcode = map->hashcode(entry->key);
+ pni_entry_t *reloc = &map->entries[hashcode % map->addressable];
+ if (reloc->state == PNI_ENTRY_FREE) {
+ //correct addressable slot is available, copy into that...
+ reloc->state = PNI_ENTRY_TAIL;
+ reloc->key = entry->key;
+ reloc->value = entry->value;
+ //...then free the current entry
+ entry->key = NULL;
+ entry->value = NULL;
+ entry->state = PNI_ENTRY_FREE;
+ entry->next = 0;
+ } else {
+ //iterate to end of chain...
+ while (reloc->state == PNI_ENTRY_LINK) {
+ reloc = &map->entries[reloc->next];
+ }
+ assert(reloc->state == PNI_ENTRY_TAIL);
+ //... and append current entry
+ reloc->state = PNI_ENTRY_LINK;
+ reloc->next = current;
+ entry->state = PNI_ENTRY_TAIL;
+ entry->next = 0;
+ }
+ }
+}
+
+void pn_map_del(pn_map_t *map, void *key)
+{
+ assert(map);
+ pni_entry_t *prev = NULL;
+ pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
+ if (entry) {
+ uint8_t orig_state = entry->state;
+ size_t orig_next = entry->next;
+
+ void *dref_key = entry->key;
+ void *dref_value = entry->value;
+ if (prev) {
+ prev->next = 0;
+ prev->state = PNI_ENTRY_TAIL;
+ }
+ entry->state = PNI_ENTRY_FREE;
+ entry->next = 0;
+ entry->key = NULL;
+ entry->value = NULL;
+ map->size--;
+
+ if (orig_state == PNI_ENTRY_LINK) {
+ pni_map_rehash(map, orig_next);
+ }
+
+ // do this last as it may trigger further deletions
+ pn_class_decref(map->key, dref_key);
+ pn_class_decref(map->value, dref_value);
+ }
+}
+
+pn_handle_t pn_map_head(pn_map_t *map)
+{
+ assert(map);
+ for (size_t i = 0; i < map->capacity; i++)
+ {
+ if (map->entries[i].state != PNI_ENTRY_FREE) {
+ return (pn_handle_t)(i + 1);
+ }
+ }
+
+ return 0;
+}
+
+pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry)
+{
+ for (size_t i = (size_t)entry; i < map->capacity; i++) {
+ if (map->entries[i].state != PNI_ENTRY_FREE) {
+ return (pn_handle_t)(i + 1);
+ }
+ }
+
+ return 0;
+}
+
+void *pn_map_key(pn_map_t *map, pn_handle_t entry)
+{
+ assert(map);
+ assert(entry);
+ return map->entries[(size_t)entry - 1].key;
+}
+
+void *pn_map_value(pn_map_t *map, pn_handle_t entry)
+{
+ assert(map);
+ assert(entry);
+ return map->entries[(size_t)entry - 1].value;
+}
+
+struct pn_hash_t {
+ pn_map_t map;
+};
+
+static uintptr_t pni_identity_hashcode(void *obj)
+{
+ return (uintptr_t ) obj;
+}
+
+static bool pni_identity_equals(void *a, void *b)
+{
+ return a == b;
+}
+
+#define CID_pni_uintptr CID_pn_void
+static const pn_class_t *pni_uintptr_reify(void *object);
+#define pni_uintptr_new NULL
+#define pni_uintptr_free NULL
+#define pni_uintptr_initialize NULL
+static void pni_uintptr_incref(void *object) {}
+static void pni_uintptr_decref(void *object) {}
+static int pni_uintptr_refcount(void *object) { return -1; }
+#define pni_uintptr_finalize NULL
+#define pni_uintptr_hashcode NULL
+#define pni_uintptr_compare NULL
+#define pni_uintptr_inspect NULL
+
+static const pn_class_t PN_UINTPTR[] = {PN_METACLASS(pni_uintptr)};
+
+static const pn_class_t *pni_uintptr_reify(void *object)
+{
+ return PN_UINTPTR;
+}
+
+pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor)
+{
+ pn_hash_t *hash = (pn_hash_t *) pn_map(PN_UINTPTR, clazz, capacity, load_factor);
+ hash->map.hashcode = pni_identity_hashcode;
+ hash->map.equals = pni_identity_equals;
+ return hash;
+}
+
+size_t pn_hash_size(pn_hash_t *hash)
+{
+ return pn_map_size(&hash->map);
+}
+
+int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value)
+{
+ return pn_map_put(&hash->map, (void *) key, value);
+}
+
+void *pn_hash_get(pn_hash_t *hash, uintptr_t key)
+{
+ return pn_map_get(&hash->map, (void *) key);
+}
+
+void pn_hash_del(pn_hash_t *hash, uintptr_t key)
+{
+ pn_map_del(&hash->map, (void *) key);
+}
+
+pn_handle_t pn_hash_head(pn_hash_t *hash)
+{
+ return pn_map_head(&hash->map);
+}
+
+pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry)
+{
+ return pn_map_next(&hash->map, entry);
+}
+
+uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry)
+{
+ return (uintptr_t) pn_map_key(&hash->map, entry);
+}
+
+void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry)
+{
+ return pn_map_value(&hash->map, entry);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/object.c b/proton-c/src/core/object/object.c
new file mode 100644
index 0000000..b0c1b33
--- /dev/null
+++ b/proton-c/src/core/object/object.c
@@ -0,0 +1,312 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define pn_object_initialize NULL
+#define pn_object_finalize NULL
+#define pn_object_inspect NULL
+uintptr_t pn_object_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
+
+const pn_class_t PN_OBJECT[] = {PN_CLASS(pn_object)};
+
+#define pn_void_initialize NULL
+static void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); }
+static void pn_void_incref(void *object) {}
+static void pn_void_decref(void *object) {}
+static int pn_void_refcount(void *object) { return -1; }
+#define pn_void_finalize NULL
+static void pn_void_free(void *object) { free(object); }
+static const pn_class_t *pn_void_reify(void *object) { return PN_VOID; }
+uintptr_t pn_void_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_void_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
+int pn_void_inspect(void *object, pn_string_t *dst) { return pn_string_addf(dst, "%p", object); }
+
+const pn_class_t PN_VOID[] = {PN_METACLASS(pn_void)};
+
+const char *pn_class_name(const pn_class_t *clazz)
+{
+ return clazz->name;
+}
+
+pn_cid_t pn_class_id(const pn_class_t *clazz)
+{
+ return clazz->cid;
+}
+
+void *pn_class_new(const pn_class_t *clazz, size_t size)
+{
+ assert(clazz);
+ void *object = clazz->newinst(clazz, size);
+ if (clazz->initialize) {
+ clazz->initialize(object);
+ }
+ return object;
+}
+
+void *pn_class_incref(const pn_class_t *clazz, void *object)
+{
+ assert(clazz);
+ if (object) {
+ clazz = clazz->reify(object);
+ clazz->incref(object);
+ }
+ return object;
+}
+
+int pn_class_refcount(const pn_class_t *clazz, void *object)
+{
+ assert(clazz);
+ clazz = clazz->reify(object);
+ return clazz->refcount(object);
+}
+
+int pn_class_decref(const pn_class_t *clazz, void *object)
+{
+ assert(clazz);
+
+ if (object) {
+ clazz = clazz->reify(object);
+ clazz->decref(object);
+ int rc = clazz->refcount(object);
+ if (rc == 0) {
+ if (clazz->finalize) {
+ clazz->finalize(object);
+ // check the refcount again in case the finalizer created a
+ // new reference
+ rc = clazz->refcount(object);
+ }
+ if (rc == 0) {
+ clazz->free(object);
+ return 0;
+ }
+ } else {
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+void pn_class_free(const pn_class_t *clazz, void *object)
+{
+ assert(clazz);
+ if (object) {
+ clazz = clazz->reify(object);
+ int rc = clazz->refcount(object);
+ assert(rc == 1 || rc == -1);
+ if (rc == 1) {
+ rc = pn_class_decref(clazz, object);
+ assert(rc == 0);
+ } else {
+ if (clazz->finalize) {
+ clazz->finalize(object);
+ }
+ clazz->free(object);
+ }
+ }
+}
+
+const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object)
+{
+ assert(clazz);
+ return clazz->reify(object);
+}
+
+uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object)
+{
+ assert(clazz);
+
+ if (!object) return 0;
+
+ clazz = clazz->reify(object);
+
+ if (clazz->hashcode) {
+ return clazz->hashcode(object);
+ } else {
+ return (uintptr_t) object;
+ }
+}
+
+intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b)
+{
+ assert(clazz);
+
+ if (a == b) return 0;
+
+ clazz = clazz->reify(a);
+
+ if (a && b && clazz->compare) {
+ return clazz->compare(a, b);
+ } else {
+ return (intptr_t) a - (intptr_t) b;
+ }
+}
+
+bool pn_class_equals(const pn_class_t *clazz, void *a, void *b)
+{
+ return pn_class_compare(clazz, a, b) == 0;
+}
+
+int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst)
+{
+ assert(clazz);
+
+ clazz = clazz->reify(object);
+
+ if (!pn_string_get(dst)) {
+ pn_string_set(dst, "");
+ }
+
+ if (object && clazz->inspect) {
+ return clazz->inspect(object, dst);
+ }
+
+ const char *name = clazz->name ? clazz->name : "<anon>";
+
+ return pn_string_addf(dst, "%s<%p>", name, object);
+}
+
+typedef struct {
+ const pn_class_t *clazz;
+ int refcount;
+} pni_head_t;
+
+#define pni_head(PTR) \
+ (((pni_head_t *) (PTR)) - 1)
+
+void *pn_object_new(const pn_class_t *clazz, size_t size)
+{
+ void *object = NULL;
+ pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size);
+ if (head != NULL) {
+ object = head + 1;
+ head->clazz = clazz;
+ head->refcount = 1;
+ }
+ return object;
+}
+
+const pn_class_t *pn_object_reify(void *object)
+{
+ if (object) {
+ return pni_head(object)->clazz;
+ } else {
+ return PN_OBJECT;
+ }
+}
+
+void pn_object_incref(void *object)
+{
+ if (object) {
+ pni_head(object)->refcount++;
+ }
+}
+
+int pn_object_refcount(void *object)
+{
+ assert(object);
+ return pni_head(object)->refcount;
+}
+
+void pn_object_decref(void *object)
+{
+ pni_head_t *head = pni_head(object);
+ assert(head->refcount > 0);
+ head->refcount--;
+}
+
+void pn_object_free(void *object)
+{
+ pni_head_t *head = pni_head(object);
+ free(head);
+}
+
+void *pn_incref(void *object)
+{
+ return pn_class_incref(PN_OBJECT, object);
+}
+
+int pn_decref(void *object)
+{
+ return pn_class_decref(PN_OBJECT, object);
+}
+
+int pn_refcount(void *object)
+{
+ return pn_class_refcount(PN_OBJECT, object);
+}
+
+void pn_free(void *object)
+{
+ pn_class_free(PN_OBJECT, object);
+}
+
+const pn_class_t *pn_class(void *object)
+{
+ return pn_class_reify(PN_OBJECT, object);
+}
+
+uintptr_t pn_hashcode(void *object)
+{
+ return pn_class_hashcode(PN_OBJECT, object);
+}
+
+intptr_t pn_compare(void *a, void *b)
+{
+ return pn_class_compare(PN_OBJECT, a, b);
+}
+
+bool pn_equals(void *a, void *b)
+{
+ return !pn_compare(a, b);
+}
+
+int pn_inspect(void *object, pn_string_t *dst)
+{
+ return pn_class_inspect(PN_OBJECT, object, dst);
+}
+
+#define pn_weakref_new NULL
+#define pn_weakref_initialize NULL
+#define pn_weakref_finalize NULL
+#define pn_weakref_free NULL
+
+static void pn_weakref_incref(void *object) {}
+static void pn_weakref_decref(void *object) {}
+static int pn_weakref_refcount(void *object) { return -1; }
+static const pn_class_t *pn_weakref_reify(void *object) {
+ return PN_WEAKREF;
+}
+static uintptr_t pn_weakref_hashcode(void *object) {
+ return pn_hashcode(object);
+}
+static intptr_t pn_weakref_compare(void *a, void *b) {
+ return pn_compare(a, b);
+}
+static int pn_weakref_inspect(void *object, pn_string_t *dst) {
+ return pn_inspect(object, dst);
+}
+
+const pn_class_t PN_WEAKREF[] = {PN_METACLASS(pn_weakref)};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/record.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/record.c b/proton-c/src/core/object/record.c
new file mode 100644
index 0000000..6f4fe0a
--- /dev/null
+++ b/proton-c/src/core/object/record.c
@@ -0,0 +1,153 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+typedef struct {
+ pn_handle_t key;
+ const pn_class_t *clazz;
+ void *value;
+} pni_field_t;
+
+struct pn_record_t {
+ size_t size;
+ size_t capacity;
+ pni_field_t *fields;
+};
+
+static void pn_record_initialize(void *object)
+{
+ pn_record_t *record = (pn_record_t *) object;
+ record->size = 0;
+ record->capacity = 0;
+ record->fields = NULL;
+}
+
+static void pn_record_finalize(void *object)
+{
+ pn_record_t *record = (pn_record_t *) object;
+ for (size_t i = 0; i < record->size; i++) {
+ pni_field_t *v = &record->fields[i];
+ pn_class_decref(v->clazz, v->value);
+ }
+ free(record->fields);
+}
+
+#define pn_record_hashcode NULL
+#define pn_record_compare NULL
+#define pn_record_inspect NULL
+
+pn_record_t *pn_record(void)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_record);
+ pn_record_t *record = (pn_record_t *) pn_class_new(&clazz, sizeof(pn_record_t));
+ pn_record_def(record, PN_LEGCTX, PN_VOID);
+ return record;
+}
+
+static pni_field_t *pni_record_find(pn_record_t *record, pn_handle_t key) {
+ for (size_t i = 0; i < record->size; i++) {
+ pni_field_t *field = &record->fields[i];
+ if (field->key == key) {
+ return field;
+ }
+ }
+ return NULL;
+}
+
+static pni_field_t *pni_record_create(pn_record_t *record) {
+ record->size++;
+ if (record->size > record->capacity) {
+ record->fields = (pni_field_t *) realloc(record->fields, record->size * sizeof(pni_field_t));
+ record->capacity = record->size;
+ }
+ pni_field_t *field = &record->fields[record->size - 1];
+ field->key = 0;
+ field->clazz = NULL;
+ field->value = NULL;
+ return field;
+}
+
+void pn_record_def(pn_record_t *record, pn_handle_t key, const pn_class_t *clazz)
+{
+ assert(record);
+ assert(clazz);
+
+ pni_field_t *field = pni_record_find(record, key);
+ if (field) {
+ assert(field->clazz == clazz);
+ } else {
+ field = pni_record_create(record);
+ field->key = key;
+ field->clazz = clazz;
+ }
+}
+
+bool pn_record_has(pn_record_t *record, pn_handle_t key)
+{
+ assert(record);
+ pni_field_t *field = pni_record_find(record, key);
+ if (field) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void *pn_record_get(pn_record_t *record, pn_handle_t key)
+{
+ assert(record);
+ pni_field_t *field = pni_record_find(record, key);
+ if (field) {
+ return field->value;
+ } else {
+ return NULL;
+ }
+}
+
+void pn_record_set(pn_record_t *record, pn_handle_t key, void *value)
+{
+ assert(record);
+
+ pni_field_t *field = pni_record_find(record, key);
+ if (field) {
+ void *old = field->value;
+ field->value = value;
+ pn_class_incref(field->clazz, value);
+ pn_class_decref(field->clazz, old);
+ }
+}
+
+void pn_record_clear(pn_record_t *record)
+{
+ assert(record);
+ for (size_t i = 0; i < record->size; i++) {
+ pni_field_t *field = &record->fields[i];
+ pn_class_decref(field->clazz, field->value);
+ field->key = 0;
+ field->clazz = NULL;
+ field->value = NULL;
+ }
+ record->size = 0;
+ pn_record_def(record, PN_LEGCTX, PN_VOID);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/string.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/string.c b/proton-c/src/core/object/string.c
new file mode 100644
index 0000000..13d0739
--- /dev/null
+++ b/proton-c/src/core/object/string.c
@@ -0,0 +1,269 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "platform/platform.h"
+
+#include <proton/error.h>
+#include <proton/object.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#define PNI_NULL_SIZE (-1)
+
+struct pn_string_t {
+ char *bytes;
+ ssize_t size; // PNI_NULL_SIZE (-1) means null
+ size_t capacity;
+};
+
+static void pn_string_finalize(void *object)
+{
+ pn_string_t *string = (pn_string_t *) object;
+ free(string->bytes);
+}
+
+static uintptr_t pn_string_hashcode(void *object)
+{
+ pn_string_t *string = (pn_string_t *) object;
+ if (string->size == PNI_NULL_SIZE) {
+ return 0;
+ }
+
+ uintptr_t hashcode = 1;
+ for (ssize_t i = 0; i < string->size; i++) {
+ hashcode = hashcode * 31 + string->bytes[i];
+ }
+ return hashcode;
+}
+
+static intptr_t pn_string_compare(void *oa, void *ob)
+{
+ pn_string_t *a = (pn_string_t *) oa;
+ pn_string_t *b = (pn_string_t *) ob;
+ if (a->size != b->size) {
+ return b->size - a->size;
+ }
+
+ if (a->size == PNI_NULL_SIZE) {
+ return 0;
+ } else {
+ return memcmp(a->bytes, b->bytes, a->size);
+ }
+}
+
+static int pn_string_inspect(void *obj, pn_string_t *dst)
+{
+ pn_string_t *str = (pn_string_t *) obj;
+ if (str->size == PNI_NULL_SIZE) {
+ return pn_string_addf(dst, "null");
+ }
+
+ int err = pn_string_addf(dst, "\"");
+
+ for (int i = 0; i < str->size; i++) {
+ uint8_t c = str->bytes[i];
+ if (isprint(c)) {
+ err = pn_string_addf(dst, "%c", c);
+ if (err) return err;
+ } else {
+ err = pn_string_addf(dst, "\\x%.2x", c);
+ if (err) return err;
+ }
+ }
+
+ return pn_string_addf(dst, "\"");
+}
+
+pn_string_t *pn_string(const char *bytes)
+{
+ return pn_stringn(bytes, bytes ? strlen(bytes) : 0);
+}
+
+#define pn_string_initialize NULL
+
+
+pn_string_t *pn_stringn(const char *bytes, size_t n)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_string);
+ pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, sizeof(pn_string_t));
+ string->capacity = n ? n * sizeof(char) : 16;
+ string->bytes = (char *) malloc(string->capacity);
+ pn_string_setn(string, bytes, n);
+ return string;
+}
+
+const char *pn_string_get(pn_string_t *string)
+{
+ assert(string);
+ if (string->size == PNI_NULL_SIZE) {
+ return NULL;
+ } else {
+ return string->bytes;
+ }
+}
+
+size_t pn_string_size(pn_string_t *string)
+{
+ assert(string);
+ if (string->size == PNI_NULL_SIZE) {
+ return 0;
+ } else {
+ return string->size;
+ }
+}
+
+int pn_string_set(pn_string_t *string, const char *bytes)
+{
+ return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
+}
+
+int pn_string_grow(pn_string_t *string, size_t capacity)
+{
+ bool grow = false;
+ while (string->capacity < (capacity*sizeof(char) + 1)) {
+ string->capacity *= 2;
+ grow = true;
+ }
+
+ if (grow) {
+ char *growed = (char *) realloc(string->bytes, string->capacity);
+ if (growed) {
+ string->bytes = growed;
+ } else {
+ return PN_ERR;
+ }
+ }
+
+ return 0;
+}
+
+int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
+{
+ int err = pn_string_grow(string, n);
+ if (err) return err;
+
+ if (bytes) {
+ memcpy(string->bytes, bytes, n*sizeof(char));
+ string->bytes[n] = '\0';
+ string->size = n;
+ } else {
+ string->size = PNI_NULL_SIZE;
+ }
+
+ return 0;
+}
+
+ssize_t pn_string_put(pn_string_t *string, char *dst)
+{
+ assert(string);
+ assert(dst);
+
+ if (string->size != PNI_NULL_SIZE) {
+ memcpy(dst, string->bytes, string->size + 1);
+ }
+
+ return string->size;
+}
+
+void pn_string_clear(pn_string_t *string)
+{
+ pn_string_set(string, NULL);
+}
+
+int pn_string_format(pn_string_t *string, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ int err = pn_string_vformat(string, format, ap);
+ va_end(ap);
+ return err;
+}
+
+int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
+{
+ pn_string_set(string, "");
+ return pn_string_vaddf(string, format, ap);
+}
+
+int pn_string_addf(pn_string_t *string, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ int err = pn_string_vaddf(string, format, ap);
+ va_end(ap);
+ return err;
+}
+
+int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap)
+{
+ va_list copy;
+
+ if (string->size == PNI_NULL_SIZE) {
+ return PN_ERR;
+ }
+
+ while (true) {
+ va_copy(copy, ap);
+ int err = pni_vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy);
+ va_end(copy);
+ if (err < 0) {
+ return err;
+ } else if ((size_t) err >= string->capacity - string->size) {
+ pn_string_grow(string, string->size + err);
+ } else {
+ string->size += err;
+ return 0;
+ }
+ }
+}
+
+char *pn_string_buffer(pn_string_t *string)
+{
+ assert(string);
+ return string->bytes;
+}
+
+size_t pn_string_capacity(pn_string_t *string)
+{
+ assert(string);
+ return string->capacity - 1;
+}
+
+int pn_string_resize(pn_string_t *string, size_t size)
+{
+ assert(string);
+ int err = pn_string_grow(string, size);
+ if (err) return err;
+ string->size = size;
+ string->bytes[size] = '\0';
+ return 0;
+}
+
+int pn_string_copy(pn_string_t *string, pn_string_t *src)
+{
+ assert(string);
+ return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[09/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/scanner.c
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/scanner.c b/proton-c/src/extra/scanner.c
new file mode 100644
index 0000000..beb7322
--- /dev/null
+++ b/proton-c/src/extra/scanner.c
@@ -0,0 +1,399 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "scanner.h"
+
+#include "platform/platform.h"
+
+#include <proton/error.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define ERROR_SIZE (1024)
+
+struct pn_scanner_t {
+ const char *input;
+ const char *position;
+ pn_token_t token;
+ char *atoms;
+ size_t size;
+ size_t capacity;
+ pn_error_t *error;
+};
+
+static const char *pni_token_type(pn_token_type_t type)
+{
+ switch (type)
+ {
+ case PN_TOK_LBRACE: return "LBRACE";
+ case PN_TOK_RBRACE: return "RBRACE";
+ case PN_TOK_LBRACKET: return "LBRACKET";
+ case PN_TOK_RBRACKET: return "RBRACKET";
+ case PN_TOK_EQUAL: return "EQUAL";
+ case PN_TOK_COMMA: return "COMMA";
+ case PN_TOK_POS: return "POS";
+ case PN_TOK_NEG: return "NEG";
+ case PN_TOK_DOT: return "DOT";
+ case PN_TOK_AT: return "AT";
+ case PN_TOK_DOLLAR: return "DOLLAR";
+ case PN_TOK_BINARY: return "BINARY";
+ case PN_TOK_STRING: return "STRING";
+ case PN_TOK_SYMBOL: return "SYMBOL";
+ case PN_TOK_ID: return "ID";
+ case PN_TOK_FLOAT: return "FLOAT";
+ case PN_TOK_INT: return "INT";
+ case PN_TOK_TRUE: return "TRUE";
+ case PN_TOK_FALSE: return "FALSE";
+ case PN_TOK_NULL: return "NULL";
+ case PN_TOK_EOS: return "EOS";
+ case PN_TOK_ERR: return "ERR";
+ default: return "<UNKNOWN>";
+ }
+}
+
+pn_scanner_t *pn_scanner()
+{
+ pn_scanner_t *scanner = (pn_scanner_t *) malloc(sizeof(pn_scanner_t));
+ if (scanner) {
+ scanner->input = NULL;
+ scanner->error = pn_error();
+ }
+ return scanner;
+}
+
+void pn_scanner_free(pn_scanner_t *scanner)
+{
+ if (scanner) {
+ pn_error_free(scanner->error);
+ free(scanner);
+ }
+}
+
+pn_token_t pn_scanner_token(pn_scanner_t *scanner)
+{
+ if (scanner) {
+ return scanner->token;
+ } else {
+ pn_token_t tok = {PN_TOK_ERR, 0, (size_t)0};
+ return tok;
+ }
+}
+
+void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col)
+{
+ *line = 1;
+ *col = 0;
+
+ for (const char *c = scanner->input; *c && c <= scanner->token.start; c++) {
+ if (*c == '\n') {
+ *line += 1;
+ *col = -1;
+ } else {
+ *col += 1;
+ }
+ }
+}
+
+int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int err = pn_scanner_verr(scanner, code, fmt, ap);
+ va_end(ap);
+ return err;
+}
+
+int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap)
+{
+ char error[ERROR_SIZE];
+
+ int line, col;
+ pn_scanner_line_info(scanner, &line, &col);
+ int size = scanner->token.size;
+ int ln = pni_snprintf(error, ERROR_SIZE,
+ "input line %i column %i %s:'%.*s': ", line, col,
+ pni_token_type(scanner->token.type),
+ size, scanner->token.start);
+ if (ln >= ERROR_SIZE) {
+ return pn_scanner_err(scanner, code, "error info truncated");
+ } else if (ln < 0) {
+ error[0] = '\0';
+ }
+
+ int n = pni_snprintf(error + ln, ERROR_SIZE - ln, fmt, ap);
+
+ if (n >= ERROR_SIZE - ln) {
+ return pn_scanner_err(scanner, code, "error info truncated");
+ } else if (n < 0) {
+ error[0] = '\0';
+ }
+
+ return pn_error_set(scanner->error, code, error);
+}
+
+int pn_scanner_errno(pn_scanner_t *scanner)
+{
+ return pn_error_code(scanner->error);
+}
+
+const char *pn_scanner_error(pn_scanner_t *scanner)
+{
+ return pn_error_text(scanner->error);
+}
+
+static void pni_scanner_emit(pn_scanner_t *scanner, pn_token_type_t type, const char *start, size_t size)
+{
+ scanner->token.type = type;
+ scanner->token.start = start;
+ scanner->token.size = size;
+}
+
+static int pni_scanner_quoted(pn_scanner_t *scanner, const char *str, int start,
+ pn_token_type_t type)
+{
+ bool escape = false;
+
+ for (int i = start; true; i++) {
+ char c = str[i];
+ if (escape) {
+ escape = false;
+ } else {
+ switch (c) {
+ case '\0':
+ case '"':
+ pni_scanner_emit(scanner, c ? type : PN_TOK_ERR,
+ str, c ? i + 1 : i);
+ return c ? 0 : pn_scanner_err(scanner, PN_ERR, "missmatched quote");
+ case '\\':
+ escape = true;
+ break;
+ }
+ }
+ }
+}
+
+static int pni_scanner_binary(pn_scanner_t *scanner, const char *str)
+{
+ return pni_scanner_quoted(scanner, str, 2, PN_TOK_BINARY);
+}
+
+static int pni_scanner_string(pn_scanner_t *scanner, const char *str)
+{
+ return pni_scanner_quoted(scanner, str, 1, PN_TOK_STRING);
+}
+
+static int pni_scanner_alpha_end(pn_scanner_t *scanner, const char *str, int start)
+{
+ for (int i = start; true; i++) {
+ char c = str[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
+ return i;
+ }
+ }
+}
+
+static int pni_scanner_alpha(pn_scanner_t *scanner, const char *str)
+{
+ int n = pni_scanner_alpha_end(scanner, str, 0);
+ pn_token_type_t type;
+ if (!strncmp(str, "true", n)) {
+ type = PN_TOK_TRUE;
+ } else if (!strncmp(str, "false", n)) {
+ type = PN_TOK_FALSE;
+ } else if (!strncmp(str, "null", n)) {
+ type = PN_TOK_NULL;
+ } else {
+ type = PN_TOK_ID;
+ }
+
+ pni_scanner_emit(scanner, type, str, n);
+ return 0;
+}
+
+static int pni_scanner_symbol(pn_scanner_t *scanner, const char *str)
+{
+ char c = str[1];
+
+ if (c == '"') {
+ return pni_scanner_quoted(scanner, str, 2, PN_TOK_SYMBOL);
+ } else {
+ int n = pni_scanner_alpha_end(scanner, str, 1);
+ pni_scanner_emit(scanner, PN_TOK_SYMBOL, str, n);
+ return 0;
+ }
+}
+
+static int pni_scanner_number(pn_scanner_t *scanner, const char *str)
+{
+ bool dot = false;
+ bool exp = false;
+
+ int i = 0;
+
+ if (str[i] == '+' || str[i] == '-') {
+ i++;
+ }
+
+ for ( ; true; i++) {
+ char c = str[i];
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ continue;
+ case '.':
+ if (dot) {
+ pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
+ return 0;
+ } else {
+ dot = true;
+ }
+ continue;
+ case 'e':
+ case 'E':
+ if (exp) {
+ pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
+ return 0;
+ } else {
+ dot = true;
+ exp = true;
+ if (str[i+1] == '+' || str[i+1] == '-') {
+ i++;
+ }
+ continue;
+ }
+ default:
+ if (dot || exp) {
+ pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
+ return 0;
+ } else {
+ pni_scanner_emit(scanner, PN_TOK_INT, str, i);
+ return 0;
+ }
+ }
+ }
+}
+
+static int pni_scanner_single(pn_scanner_t *scanner, const char *str, pn_token_type_t type)
+{
+ pni_scanner_emit(scanner, type, str, 1);
+ return 0;
+}
+
+int pn_scanner_start(pn_scanner_t *scanner, const char *input)
+{
+ if (!scanner || !input) return PN_ARG_ERR;
+ scanner->input = input;
+ scanner->position = input;
+ return pn_scanner_scan(scanner);
+}
+
+int pn_scanner_scan(pn_scanner_t *scanner)
+{
+ const char *str = scanner->position;
+ char n;
+
+ for (char c; true; str++) {
+ c = *str;
+ switch (c)
+ {
+ case '{':
+ return pni_scanner_single(scanner, str, PN_TOK_LBRACE);
+ case '}':
+ return pni_scanner_single(scanner, str, PN_TOK_RBRACE);
+ case'[':
+ return pni_scanner_single(scanner, str, PN_TOK_LBRACKET);
+ case ']':
+ return pni_scanner_single(scanner, str, PN_TOK_RBRACKET);
+ case '=':
+ return pni_scanner_single(scanner, str, PN_TOK_EQUAL);
+ case ',':
+ return pni_scanner_single(scanner, str, PN_TOK_COMMA);
+ case '.':
+ n = *(str+1);
+ if ((n >= '0' && n <= '9')) {
+ return pni_scanner_number(scanner, str);
+ } else {
+ return pni_scanner_single(scanner, str, PN_TOK_DOT);
+ }
+ case '@':
+ return pni_scanner_single(scanner, str, PN_TOK_AT);
+ case '$':
+ return pni_scanner_single(scanner, str, PN_TOK_DOLLAR);
+ case '-':
+ n = *(str+1);
+ if ((n >= '0' && n <= '9') || n == '.') {
+ return pni_scanner_number(scanner, str);
+ } else {
+ return pni_scanner_single(scanner, str, PN_TOK_NEG);
+ }
+ case '+':
+ n = *(str+1);
+ if ((n >= '0' && n <= '9') || n == '.') {
+ return pni_scanner_number(scanner, str);
+ } else {
+ return pni_scanner_single(scanner, str, PN_TOK_POS);
+ }
+ case ' ': case '\t': case '\r': case '\v': case '\f': case '\n':
+ break;
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ return pni_scanner_number(scanner, str);
+ case ':':
+ return pni_scanner_symbol(scanner, str);
+ case '"':
+ return pni_scanner_string(scanner, str);
+ case 'b':
+ if (str[1] == '"') {
+ return pni_scanner_binary(scanner, str);
+ }
+ case 'a': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
+ case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v':
+ case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q':
+ case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ return pni_scanner_alpha(scanner, str);
+ case '\0':
+ pni_scanner_emit(scanner, PN_TOK_EOS, str, 0);
+ return PN_EOS;
+ default:
+ pni_scanner_emit(scanner, PN_TOK_ERR, str, 1);
+ return pn_scanner_err(scanner, PN_ERR, "illegal character");
+ }
+ }
+}
+
+int pn_scanner_shift(pn_scanner_t *scanner)
+{
+ scanner->position = scanner->token.start + scanner->token.size;
+ int err = pn_scanner_scan(scanner);
+ if (err == PN_EOS) {
+ return 0;
+ } else {
+ return err;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/scanner.h
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/scanner.h b/proton-c/src/extra/scanner.h
new file mode 100644
index 0000000..218babe
--- /dev/null
+++ b/proton-c/src/extra/scanner.h
@@ -0,0 +1,74 @@
+#ifndef PROTON_SCANNER_H
+#define PROTON_SCANNER_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/import_export.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+typedef enum {
+ PN_TOK_LBRACE,
+ PN_TOK_RBRACE,
+ PN_TOK_LBRACKET,
+ PN_TOK_RBRACKET,
+ PN_TOK_EQUAL,
+ PN_TOK_COMMA,
+ PN_TOK_POS,
+ PN_TOK_NEG,
+ PN_TOK_DOT,
+ PN_TOK_AT,
+ PN_TOK_DOLLAR,
+ PN_TOK_BINARY,
+ PN_TOK_STRING,
+ PN_TOK_SYMBOL,
+ PN_TOK_ID,
+ PN_TOK_FLOAT,
+ PN_TOK_INT,
+ PN_TOK_TRUE,
+ PN_TOK_FALSE,
+ PN_TOK_NULL,
+ PN_TOK_EOS,
+ PN_TOK_ERR
+} pn_token_type_t;
+
+typedef struct pn_scanner_t pn_scanner_t;
+
+typedef struct {
+ pn_token_type_t type;
+ const char *start;
+ size_t size;
+} pn_token_t;
+
+PN_EXTERN pn_scanner_t *pn_scanner(void);
+PN_EXTERN void pn_scanner_free(pn_scanner_t *scanner);
+PN_EXTERN pn_token_t pn_scanner_token(pn_scanner_t *scanner);
+PN_EXTERN int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...);
+PN_EXTERN int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap);
+PN_EXTERN void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col);
+PN_EXTERN int pn_scanner_errno(pn_scanner_t *scanner);
+PN_EXTERN const char *pn_scanner_error(pn_scanner_t *scanner);
+PN_EXTERN int pn_scanner_start(pn_scanner_t *scanner, const char *input);
+PN_EXTERN int pn_scanner_scan(pn_scanner_t *scanner);
+PN_EXTERN int pn_scanner_shift(pn_scanner_t *scanner);
+
+#endif /* scanner.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/url.c b/proton-c/src/extra/url.c
new file mode 100644
index 0000000..c1ce628
--- /dev/null
+++ b/proton-c/src/extra/url.c
@@ -0,0 +1,272 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/url.h"
+#include "proton/object.h"
+
+#include "core/util.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+/** URL-encode src and append to dst. */
+static void pni_urlencode(pn_string_t *dst, const char* src) {
+ static const char *bad = "@:/";
+
+ if (!src) return;
+ const char *i = src;
+ const char *j = strpbrk(i, bad);
+ while (j) {
+ pn_string_addf(dst, "%.*s", (int)(j-i), i);
+ pn_string_addf(dst, "%%%02X", (int)*j);
+ i = j + 1;
+ j = strpbrk(i, bad);
+ }
+ pn_string_addf(dst, "%s", i);
+}
+
+// Low level url parser
+static void pni_urldecode(const char *src, char *dst)
+{
+ const char *in = src;
+ char *out = dst;
+ while (*in != '\0')
+ {
+ if ('%' == *in)
+ {
+ if ((in[1] != '\0') && (in[2] != '\0'))
+ {
+ char esc[3];
+ esc[0] = in[1];
+ esc[1] = in[2];
+ esc[2] = '\0';
+ unsigned long d = strtoul(esc, NULL, 16);
+ *out = (char)d;
+ in += 3;
+ out++;
+ }
+ else
+ {
+ *out = *in;
+ in++;
+ out++;
+ }
+ }
+ else
+ {
+ *out = *in;
+ in++;
+ out++;
+ }
+ }
+ *out = '\0';
+}
+
+void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path)
+{
+ if (!url) return;
+
+ char *slash = strchr(url, '/');
+
+ if (slash && slash>url) {
+ char *scheme_end = strstr(slash-1, "://");
+
+ if (scheme_end && scheme_end<slash) {
+ *scheme_end = '\0';
+ *scheme = url;
+ url = scheme_end + 3;
+ slash = strchr(url, '/');
+ }
+ }
+
+ if (slash) {
+ *slash = '\0';
+ *path = slash + 1;
+ }
+
+ char *at = strchr(url, '@');
+ if (at) {
+ *at = '\0';
+ char *up = url;
+ *user = up;
+ url = at + 1;
+ char *colon = strchr(up, ':');
+ if (colon) {
+ *colon = '\0';
+ *pass = colon + 1;
+ }
+ }
+
+ *host = url;
+ char *open = (*url == '[') ? url : 0;
+ if (open) {
+ char *close = strchr(open, ']');
+ if (close) {
+ *host = open + 1;
+ *close = '\0';
+ url = close + 1;
+ }
+ }
+
+ char *colon = strchr(url, ':');
+ if (colon) {
+ *colon = '\0';
+ *port = colon + 1;
+ }
+
+ if (*user) pni_urldecode(*user, *user);
+ if (*pass) pni_urldecode(*pass, *pass);
+}
+
+struct pn_url_t {
+ char *scheme;
+ char *username;
+ char *password;
+ char *host;
+ char *port;
+ char *path;
+ pn_string_t *str;
+};
+
+/** Internal use only, returns the pn_string_t. Public function is pn_url_str() */
+static pn_string_t *pn_url_string(pn_url_t* url)
+{
+ pn_url_str(url); /* Make sure str is up to date */
+ return url->str;
+}
+
+static void pn_url_finalize(void *object)
+{
+ pn_url_t *url = (pn_url_t *) object;
+ pn_url_clear(url);
+ pn_free(url->str);
+}
+
+static uintptr_t pn_url_hashcode(void *object)
+{
+ pn_url_t *url = (pn_url_t *) object;
+ return pn_hashcode(pn_url_string(url));
+}
+
+static intptr_t pn_url_compare(void *oa, void *ob)
+{
+ pn_url_t *a = (pn_url_t *) oa;
+ pn_url_t *b = (pn_url_t *) ob;
+ return pn_compare(pn_url_string(a), pn_url_string(b));
+}
+
+
+static int pn_url_inspect(void *obj, pn_string_t *dst)
+{
+ pn_url_t *url = (pn_url_t *) obj;
+ int err = 0;
+ err = pn_string_addf(dst, "Url("); if (err) return err;
+ err = pn_inspect(pn_url_string(url), dst); if (err) return err;
+ return pn_string_addf(dst, ")");
+}
+
+#define pn_url_initialize NULL
+
+
+pn_url_t *pn_url() {
+ static const pn_class_t clazz = PN_CLASS(pn_url);
+ pn_url_t *url = (pn_url_t*) pn_class_new(&clazz, sizeof(pn_url_t));
+ if (!url) return NULL;
+ memset(url, 0, sizeof(*url));
+ url->str = pn_string(NULL);
+ return url;
+}
+
+/** Parse a string URL as a pn_url_t.
+ *@param[in] url A URL string.
+ *@return The parsed pn_url_t or NULL if url is not a valid URL string.
+ */
+pn_url_t *pn_url_parse(const char *str) {
+ if (!str || !*str) /* Empty string or NULL is illegal. */
+ return NULL;
+
+ pn_url_t *url = pn_url();
+ char *str2 = pn_strdup(str);
+ pni_parse_url(str2, &url->scheme, &url->username, &url->password, &url->host, &url->port, &url->path);
+ url->scheme = pn_strdup(url->scheme);
+ url->username = pn_strdup(url->username);
+ url->password = pn_strdup(url->password);
+ url->host = (url->host && !*url->host) ? NULL : pn_strdup(url->host);
+ url->port = pn_strdup(url->port);
+ url->path = pn_strdup(url->path);
+
+ free(str2);
+ return url;
+}
+
+/** Free a URL */
+void pn_url_free(pn_url_t *url) { pn_free(url); }
+
+/** Clear the contents of the URL. */
+void pn_url_clear(pn_url_t *url) {
+ pn_url_set_scheme(url, NULL);
+ pn_url_set_username(url, NULL);
+ pn_url_set_password(url, NULL);
+ pn_url_set_host(url, NULL);
+ pn_url_set_port(url, NULL);
+ pn_url_set_path(url, NULL);
+ pn_string_clear(url->str);
+}
+
+/** Return the string form of a URL. */
+const char *pn_url_str(pn_url_t *url) {
+ if (pn_string_get(url->str) == NULL) {
+ pn_string_set(url->str, "");
+ if (url->scheme) pn_string_addf(url->str, "%s://", url->scheme);
+ if (url->username) pni_urlencode(url->str, url->username);
+ if (url->password) {
+ pn_string_addf(url->str, ":");
+ pni_urlencode(url->str, url->password);
+ }
+ if (url->username || url->password) pn_string_addf(url->str, "@");
+ if (url->host) {
+ if (strchr(url->host, ':')) pn_string_addf(url->str, "[%s]", url->host);
+ else pn_string_addf(url->str, "%s", url->host);
+ }
+ if (url->port) pn_string_addf(url->str, ":%s", url->port);
+ if (url->path) pn_string_addf(url->str, "/%s", url->path);
+ }
+ return pn_string_get(url->str);
+}
+
+const char *pn_url_get_scheme(pn_url_t *url) { return url->scheme; }
+const char *pn_url_get_username(pn_url_t *url) { return url->username; }
+const char *pn_url_get_password(pn_url_t *url) { return url->password; }
+const char *pn_url_get_host(pn_url_t *url) { return url->host; }
+const char *pn_url_get_port(pn_url_t *url) { return url->port; }
+const char *pn_url_get_path(pn_url_t *url) { return url->path; }
+
+#define SET(part) free(url->part); url->part = pn_strdup(part); pn_string_clear(url->str)
+void pn_url_set_scheme(pn_url_t *url, const char *scheme) { SET(scheme); }
+void pn_url_set_username(pn_url_t *url, const char *username) { SET(username); }
+void pn_url_set_password(pn_url_t *url, const char *password) { SET(password); }
+void pn_url_set_host(pn_url_t *url, const char *host) { SET(host); }
+void pn_url_set_port(pn_url_t *url, const char *port) { SET(port); }
+void pn_url_set_path(pn_url_t *url, const char *path) { SET(path); }
+
+
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/framing/framing.c
----------------------------------------------------------------------
diff --git a/proton-c/src/framing/framing.c b/proton-c/src/framing/framing.c
deleted file mode 100644
index 09bf4bb..0000000
--- a/proton-c/src/framing/framing.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "framing.h"
-
-// TODO: These are near duplicates of code in codec.c - they should be
-// deduplicated.
-static inline void pn_i_write16(char *bytes, uint16_t value)
-{
- bytes[0] = 0xFF & (value >> 8);
- bytes[1] = 0xFF & (value );
-}
-
-
-static inline void pn_i_write32(char *bytes, uint32_t value)
-{
- bytes[0] = 0xFF & (value >> 24);
- bytes[1] = 0xFF & (value >> 16);
- bytes[2] = 0xFF & (value >> 8);
- bytes[3] = 0xFF & (value );
-}
-
-static inline uint16_t pn_i_read16(const char *bytes)
-{
- uint16_t a = (uint8_t) bytes[0];
- uint16_t b = (uint8_t) bytes[1];
- uint16_t r = a << 8
- | b;
- return r;
-}
-
-static inline uint32_t pn_i_read32(const char *bytes)
-{
- uint32_t a = (uint8_t) bytes[0];
- uint32_t b = (uint8_t) bytes[1];
- uint32_t c = (uint8_t) bytes[2];
- uint32_t d = (uint8_t) bytes[3];
- uint32_t r = a << 24
- | b << 16
- | c << 8
- | d;
- return r;
-}
-
-
-ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max)
-{
- if (available < AMQP_HEADER_SIZE) return 0;
- uint32_t size = pn_i_read32(&bytes[0]);
- if (max && size > max) return PN_ERR;
- if (available < size) return 0;
- unsigned int doff = 4 * (uint8_t)bytes[4];
- if (doff < AMQP_HEADER_SIZE || doff > size) return PN_ERR;
-
- frame->size = size - doff;
- frame->ex_size = doff - AMQP_HEADER_SIZE;
- frame->type = bytes[5];
- frame->channel = pn_i_read16(&bytes[6]);
- frame->extended = bytes + AMQP_HEADER_SIZE;
- frame->payload = bytes + doff;
-
- return size;
-}
-
-size_t pn_write_frame(char *bytes, size_t available, pn_frame_t frame)
-{
- size_t size = AMQP_HEADER_SIZE + frame.ex_size + frame.size;
- if (size <= available)
- {
- pn_i_write32(&bytes[0], size);
- int doff = (frame.ex_size + AMQP_HEADER_SIZE - 1)/4 + 1;
- bytes[4] = doff;
- bytes[5] = frame.type;
- pn_i_write16(&bytes[6], frame.channel);
-
- memmove(bytes + AMQP_HEADER_SIZE, frame.extended, frame.ex_size);
- memmove(bytes + 4*doff, frame.payload, frame.size);
- return size;
- } else {
- return 0;
- }
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/framing/framing.h
----------------------------------------------------------------------
diff --git a/proton-c/src/framing/framing.h b/proton-c/src/framing/framing.h
deleted file mode 100644
index 6033867..0000000
--- a/proton-c/src/framing/framing.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef PROTON_FRAMING_H
-#define PROTON_FRAMING_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <proton/type_compat.h>
-#include <proton/error.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define AMQP_HEADER_SIZE (8)
-#define AMQP_MIN_MAX_FRAME_SIZE ((uint32_t)512) // minimum allowable max-frame
-
-typedef struct {
- uint8_t type;
- uint16_t channel;
- size_t ex_size;
- const char *extended;
- size_t size;
- const char *payload;
-} pn_frame_t;
-
-ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max);
-size_t pn_write_frame(char *bytes, size_t size, pn_frame_t frame);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* framing.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/handlers/iohandler.c
----------------------------------------------------------------------
diff --git a/proton-c/src/handlers/iohandler.c b/proton-c/src/handlers/iohandler.c
index 9154884..db18c0c 100644
--- a/proton-c/src/handlers/iohandler.c
+++ b/proton-c/src/handlers/iohandler.c
@@ -19,8 +19,11 @@
*
*/
+#include "reactor/io.h"
+#include "reactor/reactor.h"
+#include "reactor/selector.h"
+
#include <proton/handlers.h>
-#include <proton/selector.h>
#include <proton/transport.h>
#include <assert.h>
@@ -62,7 +65,7 @@ static void pn_iodispatch(pn_iohandler_t *handler, pn_event_t *event, pn_event_t
pn_record_t *record = pn_reactor_attachments(reactor);
pn_selector_t *selector = (pn_selector_t *) pn_record_get(record, PN_SELECTOR);
if (!selector) {
- selector = pn_io_selector(pn_reactor_io(reactor));
+ selector = pn_io_selector(pni_reactor_io(reactor));
pn_record_def(record, PN_SELECTOR, PN_OBJECT);
pn_record_set(record, PN_SELECTOR, selector);
pn_decref(selector);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/libqpid-proton-core.pc.in
----------------------------------------------------------------------
diff --git a/proton-c/src/libqpid-proton-core.pc.in b/proton-c/src/libqpid-proton-core.pc.in
new file mode 100644
index 0000000..ff99108
--- /dev/null
+++ b/proton-c/src/libqpid-proton-core.pc.in
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: Proton Core
+Description: Qpid Proton C core protocol library
+Version: @PN_VERSION@
+URL: http://qpid.apache.org/proton/
+Libs: -L${libdir} -lqpid-proton-core
+Cflags: -I${includedir}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/log.c
----------------------------------------------------------------------
diff --git a/proton-c/src/log.c b/proton-c/src/log.c
deleted file mode 100644
index b92a99a..0000000
--- a/proton-c/src/log.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <proton/log.h>
-#include <proton/object.h>
-#include <stdio.h>
-#include "util.h"
-
-
-static void stderr_logger(const char *message) {
- fprintf(stderr, "%s\n", message);
-}
-
-static pn_logger_t logger = stderr_logger;
-static int enabled_env = -1; /* Set from environment variable. */
-static int enabled_call = -1; /* set by pn_log_enable */
-
-void pn_log_enable(bool value) {
- enabled_call = value;
-}
-
-bool pn_log_enabled(void) {
- if (enabled_call != -1) return enabled_call; /* Takes precedence */
- if (enabled_env == -1)
- enabled_env = pn_env_bool("PN_TRACE_LOG");
- return enabled_env;
-}
-
-void pn_log_logger(pn_logger_t new_logger) {
- logger = new_logger;
- if (!logger) pn_log_enable(false);
-}
-
-void pn_vlogf_impl(const char *fmt, va_list ap) {
- pn_string_t *msg = pn_string("");
- pn_string_vformat(msg, fmt, ap);
- fprintf(stderr, "%s\n", pn_string_get(msg));
-}
-
-/**@internal
- *
- * Note: We check pn_log_enabled() in the pn_logf macro *before* calling
- * pn_logf_impl because evaluating the arguments to that call could have
- * side-effects with performance impact (e.g. calling functions to construct
- * complicated messages.) It is important that a disabled log statement results
- * in nothing more than a call to pn_log_enabled().
- */
-void pn_logf_impl(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- pn_vlogf_impl(fmt, ap);
- va_end(ap);
-}
-
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/log_private.h
----------------------------------------------------------------------
diff --git a/proton-c/src/log_private.h b/proton-c/src/log_private.h
deleted file mode 100644
index 4725045..0000000
--- a/proton-c/src/log_private.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef LOG_PRIVATE_H
-#define LOG_PRIVATE_H
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**@file
- *
- * Log messages that are not associated with a transport.
- */
-
-#include <proton/log.h>
-#include <stdarg.h>
-
-/** Log a printf style message */
-#define pn_logf(...) \
- do { \
- if (pn_log_enabled()) \
- pn_logf_impl(__VA_ARGS__); \
- } while(0)
-
-/** va_list version of pn_logf */
-#define pn_vlogf(fmt, ap) \
- do { \
- if (pn_log_enabled()) \
- pn_vlogf_impl(fmt, ap); \
- } while(0)
-
-/** Return true if logging is enabled. */
-bool pn_log_enabled(void);
-
-/**@internal*/
-void pn_logf_impl(const char* fmt, ...);
-/**@internal*/
-void pn_vlogf_impl(const char *fmt, va_list ap);
-
-
-
-#endif
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/message/message.c
----------------------------------------------------------------------
diff --git a/proton-c/src/message/message.c b/proton-c/src/message/message.c
deleted file mode 100644
index 15d9c6c..0000000
--- a/proton-c/src/message/message.c
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/message.h>
-#include <proton/object.h>
-#include <proton/codec.h>
-#include <proton/error.h>
-#include <proton/parser.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include "protocol.h"
-#include "util.h"
-#include "platform_fmt.h"
-
-// message
-
-struct pn_message_t {
- pn_timestamp_t expiry_time;
- pn_timestamp_t creation_time;
- pn_data_t *id;
- pn_string_t *user_id;
- pn_string_t *address;
- pn_string_t *subject;
- pn_string_t *reply_to;
- pn_data_t *correlation_id;
- pn_string_t *content_type;
- pn_string_t *content_encoding;
- pn_string_t *group_id;
- pn_string_t *reply_to_group_id;
-
- pn_data_t *data;
- pn_data_t *instructions;
- pn_data_t *annotations;
- pn_data_t *properties;
- pn_data_t *body;
-
- pn_error_t *error;
-
- pn_sequence_t group_sequence;
- pn_millis_t ttl;
- uint32_t delivery_count;
-
- uint8_t priority;
-
- bool durable;
- bool first_acquirer;
- bool inferred;
-};
-
-void pn_message_finalize(void *obj)
-{
- pn_message_t *msg = (pn_message_t *) obj;
- pn_free(msg->user_id);
- pn_free(msg->address);
- pn_free(msg->subject);
- pn_free(msg->reply_to);
- pn_free(msg->content_type);
- pn_free(msg->content_encoding);
- pn_free(msg->group_id);
- pn_free(msg->reply_to_group_id);
- pn_data_free(msg->id);
- pn_data_free(msg->correlation_id);
- pn_data_free(msg->data);
- pn_data_free(msg->instructions);
- pn_data_free(msg->annotations);
- pn_data_free(msg->properties);
- pn_data_free(msg->body);
- pn_error_free(msg->error);
-}
-
-int pn_message_inspect(void *obj, pn_string_t *dst)
-{
- pn_message_t *msg = (pn_message_t *) obj;
- int err = pn_string_addf(dst, "Message{");
- if (err) return err;
-
- bool comma = false;
-
- if (pn_string_get(msg->address)) {
- err = pn_string_addf(dst, "address=");
- if (err) return err;
- err = pn_inspect(msg->address, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (msg->durable) {
- err = pn_string_addf(dst, "durable=%i, ", msg->durable);
- if (err) return err;
- comma = true;
- }
-
- if (msg->priority != PN_DEFAULT_PRIORITY) {
- err = pn_string_addf(dst, "priority=%i, ", msg->priority);
- if (err) return err;
- comma = true;
- }
-
- if (msg->ttl) {
- err = pn_string_addf(dst, "ttl=%" PRIu32 ", ", msg->ttl);
- if (err) return err;
- comma = true;
- }
-
- if (msg->first_acquirer) {
- err = pn_string_addf(dst, "first_acquirer=%i, ", msg->first_acquirer);
- if (err) return err;
- comma = true;
- }
-
- if (msg->delivery_count) {
- err = pn_string_addf(dst, "delivery_count=%" PRIu32 ", ", msg->delivery_count);
- if (err) return err;
- comma = true;
- }
-
- if (pn_data_size(msg->id)) {
- err = pn_string_addf(dst, "id=");
- if (err) return err;
- err = pn_inspect(msg->id, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_string_get(msg->user_id)) {
- err = pn_string_addf(dst, "user_id=");
- if (err) return err;
- err = pn_inspect(msg->user_id, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_string_get(msg->subject)) {
- err = pn_string_addf(dst, "subject=");
- if (err) return err;
- err = pn_inspect(msg->subject, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_string_get(msg->reply_to)) {
- err = pn_string_addf(dst, "reply_to=");
- if (err) return err;
- err = pn_inspect(msg->reply_to, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_data_size(msg->correlation_id)) {
- err = pn_string_addf(dst, "correlation_id=");
- if (err) return err;
- err = pn_inspect(msg->correlation_id, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_string_get(msg->content_type)) {
- err = pn_string_addf(dst, "content_type=");
- if (err) return err;
- err = pn_inspect(msg->content_type, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_string_get(msg->content_encoding)) {
- err = pn_string_addf(dst, "content_encoding=");
- if (err) return err;
- err = pn_inspect(msg->content_encoding, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (msg->expiry_time) {
- err = pn_string_addf(dst, "expiry_time=%" PRIi64 ", ", msg->expiry_time);
- if (err) return err;
- comma = true;
- }
-
- if (msg->creation_time) {
- err = pn_string_addf(dst, "creation_time=%" PRIi64 ", ", msg->creation_time);
- if (err) return err;
- comma = true;
- }
-
- if (pn_string_get(msg->group_id)) {
- err = pn_string_addf(dst, "group_id=");
- if (err) return err;
- err = pn_inspect(msg->group_id, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (msg->group_sequence) {
- err = pn_string_addf(dst, "group_sequence=%" PRIi32 ", ", msg->group_sequence);
- if (err) return err;
- comma = true;
- }
-
- if (pn_string_get(msg->reply_to_group_id)) {
- err = pn_string_addf(dst, "reply_to_group_id=");
- if (err) return err;
- err = pn_inspect(msg->reply_to_group_id, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (msg->inferred) {
- err = pn_string_addf(dst, "inferred=%i, ", msg->inferred);
- if (err) return err;
- comma = true;
- }
-
- if (pn_data_size(msg->instructions)) {
- err = pn_string_addf(dst, "instructions=");
- if (err) return err;
- err = pn_inspect(msg->instructions, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_data_size(msg->annotations)) {
- err = pn_string_addf(dst, "annotations=");
- if (err) return err;
- err = pn_inspect(msg->annotations, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_data_size(msg->properties)) {
- err = pn_string_addf(dst, "properties=");
- if (err) return err;
- err = pn_inspect(msg->properties, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (pn_data_size(msg->body)) {
- err = pn_string_addf(dst, "body=");
- if (err) return err;
- err = pn_inspect(msg->body, dst);
- if (err) return err;
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- comma = true;
- }
-
- if (comma) {
- int err = pn_string_resize(dst, pn_string_size(dst) - 2);
- if (err) return err;
- }
-
- return pn_string_addf(dst, "}");
-}
-
-#define pn_message_initialize NULL
-#define pn_message_hashcode NULL
-#define pn_message_compare NULL
-
-pn_message_t *pn_message()
-{
- static const pn_class_t clazz = PN_CLASS(pn_message);
- pn_message_t *msg = (pn_message_t *) pn_class_new(&clazz, sizeof(pn_message_t));
- msg->durable = false;
- msg->priority = PN_DEFAULT_PRIORITY;
- msg->ttl = 0;
- msg->first_acquirer = false;
- msg->delivery_count = 0;
- msg->id = pn_data(1);
- msg->user_id = pn_string(NULL);
- msg->address = pn_string(NULL);
- msg->subject = pn_string(NULL);
- msg->reply_to = pn_string(NULL);
- msg->correlation_id = pn_data(1);
- msg->content_type = pn_string(NULL);
- msg->content_encoding = pn_string(NULL);
- msg->expiry_time = 0;
- msg->creation_time = 0;
- msg->group_id = pn_string(NULL);
- msg->group_sequence = 0;
- msg->reply_to_group_id = pn_string(NULL);
-
- msg->inferred = false;
- msg->data = pn_data(16);
- msg->instructions = pn_data(16);
- msg->annotations = pn_data(16);
- msg->properties = pn_data(16);
- msg->body = pn_data(16);
-
- msg->error = pn_error();
- return msg;
-}
-
-void pn_message_free(pn_message_t *msg)
-{
- pn_free(msg);
-}
-
-void pn_message_clear(pn_message_t *msg)
-{
- msg->durable = false;
- msg->priority = PN_DEFAULT_PRIORITY;
- msg->ttl = 0;
- msg->first_acquirer = false;
- msg->delivery_count = 0;
- pn_data_clear(msg->id);
- pn_string_clear(msg->user_id);
- pn_string_clear(msg->address);
- pn_string_clear(msg->subject);
- pn_string_clear(msg->reply_to);
- pn_data_clear(msg->correlation_id);
- pn_string_clear(msg->content_type);
- pn_string_clear(msg->content_encoding);
- msg->expiry_time = 0;
- msg->creation_time = 0;
- pn_string_clear(msg->group_id);
- msg->group_sequence = 0;
- pn_string_clear(msg->reply_to_group_id);
- msg->inferred = false;
- pn_data_clear(msg->data);
- pn_data_clear(msg->instructions);
- pn_data_clear(msg->annotations);
- pn_data_clear(msg->properties);
- pn_data_clear(msg->body);
-}
-
-int pn_message_errno(pn_message_t *msg)
-{
- assert(msg);
- return pn_error_code(msg->error);
-}
-
-pn_error_t *pn_message_error(pn_message_t *msg)
-{
- assert(msg);
- return msg->error;
-}
-
-bool pn_message_is_inferred(pn_message_t *msg)
-{
- assert(msg);
- return msg->inferred;
-}
-
-int pn_message_set_inferred(pn_message_t *msg, bool inferred)
-{
- assert(msg);
- msg->inferred = inferred;
- return 0;
-}
-
-bool pn_message_is_durable(pn_message_t *msg)
-{
- assert(msg);
- return msg->durable;
-}
-int pn_message_set_durable(pn_message_t *msg, bool durable)
-{
- assert(msg);
- msg->durable = durable;
- return 0;
-}
-
-
-uint8_t pn_message_get_priority(pn_message_t *msg)
-{
- assert(msg);
- return msg->priority;
-}
-int pn_message_set_priority(pn_message_t *msg, uint8_t priority)
-{
- assert(msg);
- msg->priority = priority;
- return 0;
-}
-
-pn_millis_t pn_message_get_ttl(pn_message_t *msg)
-{
- assert(msg);
- return msg->ttl;
-}
-int pn_message_set_ttl(pn_message_t *msg, pn_millis_t ttl)
-{
- assert(msg);
- msg->ttl = ttl;
- return 0;
-}
-
-bool pn_message_is_first_acquirer(pn_message_t *msg)
-{
- assert(msg);
- return msg->first_acquirer;
-}
-int pn_message_set_first_acquirer(pn_message_t *msg, bool first)
-{
- assert(msg);
- msg->first_acquirer = first;
- return 0;
-}
-
-uint32_t pn_message_get_delivery_count(pn_message_t *msg)
-{
- assert(msg);
- return msg->delivery_count;
-}
-int pn_message_set_delivery_count(pn_message_t *msg, uint32_t count)
-{
- assert(msg);
- msg->delivery_count = count;
- return 0;
-}
-
-pn_data_t *pn_message_id(pn_message_t *msg)
-{
- assert(msg);
- return msg->id;
-}
-pn_atom_t pn_message_get_id(pn_message_t *msg)
-{
- assert(msg);
- return pn_data_get_atom(msg->id);
-}
-int pn_message_set_id(pn_message_t *msg, pn_atom_t id)
-{
- assert(msg);
- pn_data_rewind(msg->id);
- return pn_data_put_atom(msg->id, id);
-}
-
-static pn_bytes_t pn_string_get_bytes(pn_string_t *string)
-{
- return pn_bytes(pn_string_size(string), (char *) pn_string_get(string));
-}
-
-static int pn_string_set_bytes(pn_string_t *string, pn_bytes_t bytes)
-{
- return pn_string_setn(string, bytes.start, bytes.size);
-}
-
-pn_bytes_t pn_message_get_user_id(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get_bytes(msg->user_id);
-}
-int pn_message_set_user_id(pn_message_t *msg, pn_bytes_t user_id)
-{
- assert(msg);
- return pn_string_set_bytes(msg->user_id, user_id);
-}
-
-const char *pn_message_get_address(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get(msg->address);
-}
-int pn_message_set_address(pn_message_t *msg, const char *address)
-{
- assert(msg);
- return pn_string_set(msg->address, address);
-}
-
-const char *pn_message_get_subject(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get(msg->subject);
-}
-int pn_message_set_subject(pn_message_t *msg, const char *subject)
-{
- assert(msg);
- return pn_string_set(msg->subject, subject);
-}
-
-const char *pn_message_get_reply_to(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get(msg->reply_to);
-}
-int pn_message_set_reply_to(pn_message_t *msg, const char *reply_to)
-{
- assert(msg);
- return pn_string_set(msg->reply_to, reply_to);
-}
-
-pn_data_t *pn_message_correlation_id(pn_message_t *msg)
-{
- assert(msg);
- return msg->correlation_id;
-}
-pn_atom_t pn_message_get_correlation_id(pn_message_t *msg)
-{
- assert(msg);
- return pn_data_get_atom(msg->correlation_id);
-}
-int pn_message_set_correlation_id(pn_message_t *msg, pn_atom_t atom)
-{
- assert(msg);
- pn_data_rewind(msg->correlation_id);
- return pn_data_put_atom(msg->correlation_id, atom);
-}
-
-const char *pn_message_get_content_type(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get(msg->content_type);
-}
-int pn_message_set_content_type(pn_message_t *msg, const char *type)
-{
- assert(msg);
- return pn_string_set(msg->content_type, type);
-}
-
-const char *pn_message_get_content_encoding(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get(msg->content_encoding);
-}
-int pn_message_set_content_encoding(pn_message_t *msg, const char *encoding)
-{
- assert(msg);
- return pn_string_set(msg->content_encoding, encoding);
-}
-
-pn_timestamp_t pn_message_get_expiry_time(pn_message_t *msg)
-{
- assert(msg);
- return msg->expiry_time;
-}
-int pn_message_set_expiry_time(pn_message_t *msg, pn_timestamp_t time)
-{
- assert(msg);
- msg->expiry_time = time;
- return 0;
-}
-
-pn_timestamp_t pn_message_get_creation_time(pn_message_t *msg)
-{
- assert(msg);
- return msg->creation_time;
-}
-int pn_message_set_creation_time(pn_message_t *msg, pn_timestamp_t time)
-{
- assert(msg);
- msg->creation_time = time;
- return 0;
-}
-
-const char *pn_message_get_group_id(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get(msg->group_id);
-}
-int pn_message_set_group_id(pn_message_t *msg, const char *group_id)
-{
- assert(msg);
- return pn_string_set(msg->group_id, group_id);
-}
-
-pn_sequence_t pn_message_get_group_sequence(pn_message_t *msg)
-{
- assert(msg);
- return msg->group_sequence;
-}
-int pn_message_set_group_sequence(pn_message_t *msg, pn_sequence_t n)
-{
- assert(msg);
- msg->group_sequence = n;
- return 0;
-}
-
-const char *pn_message_get_reply_to_group_id(pn_message_t *msg)
-{
- assert(msg);
- return pn_string_get(msg->reply_to_group_id);
-}
-int pn_message_set_reply_to_group_id(pn_message_t *msg, const char *reply_to_group_id)
-{
- assert(msg);
- return pn_string_set(msg->reply_to_group_id, reply_to_group_id);
-}
-
-int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size)
-{
- assert(msg && bytes && size);
-
- pn_message_clear(msg);
-
- while (size) {
- pn_data_clear(msg->data);
- ssize_t used = pn_data_decode(msg->data, bytes, size);
- if (used < 0)
- return pn_error_format(msg->error, used, "data error: %s",
- pn_error_text(pn_data_error(msg->data)));
- size -= used;
- bytes += used;
- bool scanned;
- uint64_t desc;
- int err = pn_data_scan(msg->data, "D?L.", &scanned, &desc);
- if (err) return pn_error_format(msg->error, err, "data error: %s",
- pn_error_text(pn_data_error(msg->data)));
- if (!scanned) {
- desc = 0;
- }
-
- pn_data_rewind(msg->data);
- pn_data_next(msg->data);
- pn_data_enter(msg->data);
- pn_data_next(msg->data);
-
- switch (desc) {
- case HEADER:
- err = pn_data_scan(msg->data, "D.[oBIoI]", &msg->durable, &msg->priority,
- &msg->ttl, &msg->first_acquirer, &msg->delivery_count);
- if (err) return pn_error_format(msg->error, err, "data error: %s",
- pn_error_text(pn_data_error(msg->data)));
- break;
- case PROPERTIES:
- {
- pn_bytes_t user_id, address, subject, reply_to, ctype, cencoding,
- group_id, reply_to_group_id;
- pn_data_clear(msg->id);
- pn_data_clear(msg->correlation_id);
- err = pn_data_scan(msg->data, "D.[CzSSSCssttSIS]", msg->id,
- &user_id, &address, &subject, &reply_to,
- msg->correlation_id, &ctype, &cencoding,
- &msg->expiry_time, &msg->creation_time, &group_id,
- &msg->group_sequence, &reply_to_group_id);
- if (err) return pn_error_format(msg->error, err, "data error: %s",
- pn_error_text(pn_data_error(msg->data)));
- err = pn_string_set_bytes(msg->user_id, user_id);
- if (err) return pn_error_format(msg->error, err, "error setting user_id");
- err = pn_string_setn(msg->address, address.start, address.size);
- if (err) return pn_error_format(msg->error, err, "error setting address");
- err = pn_string_setn(msg->subject, subject.start, subject.size);
- if (err) return pn_error_format(msg->error, err, "error setting subject");
- err = pn_string_setn(msg->reply_to, reply_to.start, reply_to.size);
- if (err) return pn_error_format(msg->error, err, "error setting reply_to");
- err = pn_string_setn(msg->content_type, ctype.start, ctype.size);
- if (err) return pn_error_format(msg->error, err, "error setting content_type");
- err = pn_string_setn(msg->content_encoding, cencoding.start,
- cencoding.size);
- if (err) return pn_error_format(msg->error, err, "error setting content_encoding");
- err = pn_string_setn(msg->group_id, group_id.start, group_id.size);
- if (err) return pn_error_format(msg->error, err, "error setting group_id");
- err = pn_string_setn(msg->reply_to_group_id, reply_to_group_id.start,
- reply_to_group_id.size);
- if (err) return pn_error_format(msg->error, err, "error setting reply_to_group_id");
- }
- break;
- case DELIVERY_ANNOTATIONS:
- pn_data_narrow(msg->data);
- err = pn_data_copy(msg->instructions, msg->data);
- if (err) return err;
- break;
- case MESSAGE_ANNOTATIONS:
- pn_data_narrow(msg->data);
- err = pn_data_copy(msg->annotations, msg->data);
- if (err) return err;
- break;
- case APPLICATION_PROPERTIES:
- pn_data_narrow(msg->data);
- err = pn_data_copy(msg->properties, msg->data);
- if (err) return err;
- break;
- case DATA:
- case AMQP_SEQUENCE:
- case AMQP_VALUE:
- pn_data_narrow(msg->data);
- err = pn_data_copy(msg->body, msg->data);
- if (err) return err;
- break;
- case FOOTER:
- break;
- default:
- err = pn_data_copy(msg->body, msg->data);
- if (err) return err;
- break;
- }
- }
-
- pn_data_clear(msg->data);
- return 0;
-}
-
-int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size)
-{
- if (!msg || !bytes || !size || !*size) return PN_ARG_ERR;
- pn_data_clear(msg->data);
- pn_message_data(msg, msg->data);
- size_t remaining = *size;
- ssize_t encoded = pn_data_encode(msg->data, bytes, remaining);
- if (encoded < 0) {
- if (encoded == PN_OVERFLOW) {
- return encoded;
- } else {
- return pn_error_format(msg->error, encoded, "data error: %s",
- pn_error_text(pn_data_error(msg->data)));
- }
- }
- bytes += encoded;
- remaining -= encoded;
- *size -= remaining;
- pn_data_clear(msg->data);
- return 0;
-}
-
-int pn_message_data(pn_message_t *msg, pn_data_t *data)
-{
- pn_data_clear(data);
- int err = pn_data_fill(data, "DL[oB?IoI]", HEADER, msg->durable,
- msg->priority, msg->ttl, msg->ttl, msg->first_acquirer,
- msg->delivery_count);
- if (err)
- return pn_error_format(msg->error, err, "data error: %s",
- pn_error_text(pn_data_error(data)));
-
- if (pn_data_size(msg->instructions)) {
- pn_data_put_described(data);
- pn_data_enter(data);
- pn_data_put_ulong(data, DELIVERY_ANNOTATIONS);
- pn_data_rewind(msg->instructions);
- err = pn_data_append(data, msg->instructions);
- if (err)
- return pn_error_format(msg->error, err, "data error: %s",
- pn_error_text(pn_data_error(data)));
- pn_data_exit(data);
- }
-
- if (pn_data_size(msg->annotations)) {
- pn_data_put_described(data);
- pn_data_enter(data);
- pn_data_put_ulong(data, MESSAGE_ANNOTATIONS);
- pn_data_rewind(msg->annotations);
- err = pn_data_append(data, msg->annotations);
- if (err)
- return pn_error_format(msg->error, err, "data error: %s",
- pn_error_text(pn_data_error(data)));
- pn_data_exit(data);
- }
-
- err = pn_data_fill(data, "DL[CzSSSCssttSIS]", PROPERTIES,
- msg->id,
- pn_string_size(msg->user_id), pn_string_get(msg->user_id),
- pn_string_get(msg->address),
- pn_string_get(msg->subject),
- pn_string_get(msg->reply_to),
- msg->correlation_id,
- pn_string_get(msg->content_type),
- pn_string_get(msg->content_encoding),
- msg->expiry_time,
- msg->creation_time,
- pn_string_get(msg->group_id),
- msg->group_sequence,
- pn_string_get(msg->reply_to_group_id));
- if (err)
- return pn_error_format(msg->error, err, "data error: %s",
- pn_error_text(pn_data_error(data)));
-
- if (pn_data_size(msg->properties)) {
- pn_data_put_described(data);
- pn_data_enter(data);
- pn_data_put_ulong(data, APPLICATION_PROPERTIES);
- pn_data_rewind(msg->properties);
- err = pn_data_append(data, msg->properties);
- if (err)
- return pn_error_format(msg->error, err, "data error: %s",
- pn_data_error(data));
- pn_data_exit(data);
- }
-
- if (pn_data_size(msg->body)) {
- pn_data_rewind(msg->body);
- pn_data_next(msg->body);
- pn_type_t body_type = pn_data_type(msg->body);
- pn_data_rewind(msg->body);
-
- pn_data_put_described(data);
- pn_data_enter(data);
- if (msg->inferred) {
- switch (body_type) {
- case PN_BINARY:
- pn_data_put_ulong(data, DATA);
- break;
- case PN_LIST:
- pn_data_put_ulong(data, AMQP_SEQUENCE);
- break;
- default:
- pn_data_put_ulong(data, AMQP_VALUE);
- break;
- }
- } else {
- pn_data_put_ulong(data, AMQP_VALUE);
- }
- pn_data_append(data, msg->body);
- }
- return 0;
-}
-
-pn_data_t *pn_message_instructions(pn_message_t *msg)
-{
- return msg ? msg->instructions : NULL;
-}
-
-pn_data_t *pn_message_annotations(pn_message_t *msg)
-{
- return msg ? msg->annotations : NULL;
-}
-
-pn_data_t *pn_message_properties(pn_message_t *msg)
-{
- return msg ? msg->properties : NULL;
-}
-
-pn_data_t *pn_message_body(pn_message_t *msg)
-{
- return msg ? msg->body : NULL;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/messenger.c b/proton-c/src/messenger/messenger.c
index 64be017..264a733 100644
--- a/proton-c/src/messenger/messenger.c
+++ b/proton-c/src/messenger/messenger.c
@@ -27,7 +27,6 @@
#include <proton/object.h>
#include <proton/sasl.h>
#include <proton/session.h>
-#include <proton/selector.h>
#include <assert.h>
#include <ctype.h>
@@ -35,14 +34,17 @@
#include <string.h>
#include <stdio.h>
-#include "util.h"
-#include "platform.h"
-#include "platform_fmt.h"
+#include "core/log_private.h"
+#include "core/util.h"
+#include "platform/platform.h" // pn_i_getpid, pn_i_now, pni_snprintf
+#include "platform/platform_fmt.h"
#include "store.h"
-#include "transform.h"
#include "subscription.h"
-#include "selectable.h"
-#include "log_private.h"
+#include "transform.h"
+
+#include "reactor/io.h"
+#include "reactor/selectable.h"
+#include "reactor/selector.h"
typedef struct pn_link_ctx_t pn_link_ctx_t;
@@ -980,7 +982,7 @@ static void pn_condition_report(const char *pfx, pn_condition_t *condition)
pn_condition_redirect_port(condition));
} else if (pn_condition_is_set(condition)) {
char error[1024];
- snprintf(error, 1024, "(%s) %s",
+ pni_snprintf(error, 1024, "(%s) %s",
pn_condition_get_name(condition),
pn_condition_get_description(condition));
pn_error_report(pfx, error);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/store.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/store.c b/proton-c/src/messenger/store.c
index bdd7e24..44f24f1 100644
--- a/proton-c/src/messenger/store.c
+++ b/proton-c/src/messenger/store.c
@@ -28,7 +28,7 @@
#endif
#include <stdlib.h>
#include <string.h>
-#include "util.h"
+#include "core/util.h"
#include "store.h"
typedef struct pni_stream_t pni_stream_t;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/store.h
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/store.h b/proton-c/src/messenger/store.h
index 2ca243b..22bb94e 100644
--- a/proton-c/src/messenger/store.h
+++ b/proton-c/src/messenger/store.h
@@ -22,7 +22,7 @@
*
*/
-#include "buffer.h"
+#include "core/buffer.h"
typedef struct pni_store_t pni_store_t;
typedef struct pni_entry_t pni_entry_t;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/transform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/transform.h b/proton-c/src/messenger/transform.h
index c9350ef..3288f6c 100644
--- a/proton-c/src/messenger/transform.h
+++ b/proton-c/src/messenger/transform.h
@@ -22,8 +22,9 @@
*
*/
+#include "core/buffer.h"
+
#include <proton/object.h>
-#include "buffer.h"
typedef struct pn_transform_t pn_transform_t;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/iterator.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/iterator.c b/proton-c/src/object/iterator.c
deleted file mode 100644
index 61b3b8e..0000000
--- a/proton-c/src/object/iterator.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-struct pn_iterator_t {
- pn_iterator_next_t next;
- size_t size;
- void *state;
-};
-
-static void pn_iterator_initialize(void *object)
-{
- pn_iterator_t *it = (pn_iterator_t *) object;
- it->next = NULL;
- it->size = 0;
- it->state = NULL;
-}
-
-static void pn_iterator_finalize(void *object)
-{
- pn_iterator_t *it = (pn_iterator_t *) object;
- free(it->state);
-}
-
-#define CID_pn_iterator CID_pn_object
-#define pn_iterator_hashcode NULL
-#define pn_iterator_compare NULL
-#define pn_iterator_inspect NULL
-
-pn_iterator_t *pn_iterator()
-{
- static const pn_class_t clazz = PN_CLASS(pn_iterator);
- pn_iterator_t *it = (pn_iterator_t *) pn_class_new(&clazz, sizeof(pn_iterator_t));
- return it;
-}
-
-void *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next,
- size_t size) {
- assert(iterator);
- assert(next);
- iterator->next = next;
- if (iterator->size < size) {
- iterator->state = realloc(iterator->state, size);
- }
- return iterator->state;
-}
-
-void *pn_iterator_next(pn_iterator_t *iterator) {
- assert(iterator);
- if (iterator->next) {
- void *result = iterator->next(iterator->state);
- if (!result) iterator->next = NULL;
- return result;
- } else {
- return NULL;
- }
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/list.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/list.c b/proton-c/src/object/list.c
deleted file mode 100644
index 76c70d2..0000000
--- a/proton-c/src/object/list.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-struct pn_list_t {
- const pn_class_t *clazz;
- size_t capacity;
- size_t size;
- void **elements;
-};
-
-size_t pn_list_size(pn_list_t *list)
-{
- assert(list);
- return list->size;
-}
-
-void *pn_list_get(pn_list_t *list, int index)
-{
- assert(list); assert(list->size);
- return list->elements[index % list->size];
-}
-
-void pn_list_set(pn_list_t *list, int index, void *value)
-{
- assert(list); assert(list->size);
- void *old = list->elements[index % list->size];
- pn_class_decref(list->clazz, old);
- list->elements[index % list->size] = value;
- pn_class_incref(list->clazz, value);
-}
-
-static void pni_list_ensure(pn_list_t *list, size_t capacity)
-{
- assert(list);
- if (list->capacity < capacity) {
- size_t newcap = list->capacity;
- while (newcap < capacity) { newcap *= 2; }
- list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
- assert(list->elements);
- list->capacity = newcap;
- }
-}
-
-int pn_list_add(pn_list_t *list, void *value)
-{
- assert(list);
- pni_list_ensure(list, list->size + 1);
- list->elements[list->size++] = value;
- pn_class_incref(list->clazz, value);
- return 0;
-}
-
-void *pn_list_pop(pn_list_t *list)
-{
- assert(list);
- if (list->size) {
- return list->elements[--list->size];
- } else {
- return NULL;
- }
-}
-
-ssize_t pn_list_index(pn_list_t *list, void *value)
-{
- for (size_t i = 0; i < list->size; i++) {
- if (pn_class_equals(list->clazz, list->elements[i], value)) {
- return i;
- }
- }
-
- return -1;
-}
-
-bool pn_list_remove(pn_list_t *list, void *value)
-{
- assert(list);
- ssize_t idx = pn_list_index(list, value);
- if (idx < 0) {
- return false;
- } else {
- pn_list_del(list, idx, 1);
- }
-
- return true;
-}
-
-void pn_list_del(pn_list_t *list, int index, int n)
-{
- assert(list);
- if (!list->size) { return; }
- index %= list->size;
-
- for (int i = 0; i < n; i++) {
- pn_class_decref(list->clazz, list->elements[index + i]);
- }
-
- size_t slide = list->size - (index + n);
- for (size_t i = 0; i < slide; i++) {
- list->elements[index + i] = list->elements[index + n + i];
- }
-
- list->size -= n;
-}
-
-void pn_list_clear(pn_list_t *list)
-{
- assert(list);
- pn_list_del(list, 0, list->size);
-}
-
-void pn_list_minpush(pn_list_t *list, void *value)
-{
- assert(list);
- pn_list_add(list, value);
- // we use one based indexing for the heap
- void **heap = list->elements - 1;
- int now = list->size;
- while (now > 1 && pn_class_compare(list->clazz, heap[now/2], value) > 0) {
- heap[now] = heap[now/2];
- now /= 2;
- }
- heap[now] = value;
-}
-
-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;
-}
-
-typedef struct {
- pn_list_t *list;
- size_t index;
-} pni_list_iter_t;
-
-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;
- }
-}
-
-void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
-{
- pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
- liter->list = list;
- liter->index = 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);
-}
-
-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;
-}
-
-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;
-}
-
-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, "]");
-}
-
-#define pn_list_initialize NULL
-
-pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity)
-{
- static const pn_class_t list_clazz = PN_CLASS(pn_list);
-
- pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t));
- list->clazz = clazz;
- list->capacity = capacity ? capacity : 16;
- list->elements = (void **) malloc(list->capacity * sizeof(void *));
- list->size = 0;
- return list;
-}
-
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/map.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/map.c b/proton-c/src/object/map.c
deleted file mode 100644
index cd38f19..0000000
--- a/proton-c/src/object/map.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define PNI_ENTRY_FREE (0)
-#define PNI_ENTRY_LINK (1)
-#define PNI_ENTRY_TAIL (2)
-
-typedef struct {
- void *key;
- void *value;
- size_t next;
- uint8_t state;
-} pni_entry_t;
-
-struct pn_map_t {
- const pn_class_t *key;
- const pn_class_t *value;
- pni_entry_t *entries;
- size_t capacity;
- size_t addressable;
- size_t size;
- uintptr_t (*hashcode)(void *key);
- bool (*equals)(void *a, void *b);
- float load_factor;
-};
-
-static void pn_map_finalize(void *object)
-{
- pn_map_t *map = (pn_map_t *) object;
-
- for (size_t i = 0; i < map->capacity; i++) {
- if (map->entries[i].state != PNI_ENTRY_FREE) {
- pn_class_decref(map->key, map->entries[i].key);
- pn_class_decref(map->value, map->entries[i].value);
- }
- }
-
- free(map->entries);
-}
-
-static uintptr_t pn_map_hashcode(void *object)
-{
- pn_map_t *map = (pn_map_t *) object;
-
- uintptr_t hashcode = 0;
-
- for (size_t i = 0; i < map->capacity; i++) {
- if (map->entries[i].state != PNI_ENTRY_FREE) {
- void *key = map->entries[i].key;
- void *value = map->entries[i].value;
- hashcode += pn_hashcode(key) ^ pn_hashcode(value);
- }
- }
-
- return hashcode;
-}
-
-static void pni_map_allocate(pn_map_t *map)
-{
- map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t));
- if (map->entries != NULL) {
- for (size_t i = 0; i < map->capacity; i++) {
- map->entries[i].key = NULL;
- map->entries[i].value = NULL;
- map->entries[i].next = 0;
- map->entries[i].state = PNI_ENTRY_FREE;
- }
- }
- map->size = 0;
-}
-
-static int pn_map_inspect(void *obj, pn_string_t *dst)
-{
- assert(obj);
- pn_map_t *map = (pn_map_t *) obj;
- int err = pn_string_addf(dst, "{");
- if (err) return err;
- pn_handle_t entry = pn_map_head(map);
- bool first = true;
- while (entry) {
- if (first) {
- first = false;
- } else {
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- }
- err = pn_class_inspect(map->key, pn_map_key(map, entry), dst);
- if (err) return err;
- err = pn_string_addf(dst, ": ");
- if (err) return err;
- err = pn_class_inspect(map->value, pn_map_value(map, entry), dst);
- if (err) return err;
- entry = pn_map_next(map, entry);
- }
- return pn_string_addf(dst, "}");
-}
-
-#define pn_map_initialize NULL
-#define pn_map_compare NULL
-
-pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value,
- size_t capacity, float load_factor)
-{
- static const pn_class_t clazz = PN_CLASS(pn_map);
-
- pn_map_t *map = (pn_map_t *) pn_class_new(&clazz, sizeof(pn_map_t));
- map->key = key;
- map->value = value;
- map->capacity = capacity ? capacity : 16;
- map->addressable = (size_t) (map->capacity * 0.86);
- if (!map->addressable) map->addressable = map->capacity;
- map->load_factor = load_factor;
- map->hashcode = pn_hashcode;
- map->equals = pn_equals;
- pni_map_allocate(map);
- return map;
-}
-
-size_t pn_map_size(pn_map_t *map)
-{
- assert(map);
- return map->size;
-}
-
-static float pni_map_load(pn_map_t *map)
-{
- return ((float) map->size) / ((float) map->addressable);
-}
-
-static bool pni_map_ensure(pn_map_t *map, size_t capacity)
-{
- float load = pni_map_load(map);
- if (capacity <= map->capacity && load <= map->load_factor) {
- return false;
- }
-
- size_t oldcap = map->capacity;
-
- while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
- map->capacity *= 2;
- map->addressable = (size_t) (0.86 * map->capacity);
- }
-
- pni_entry_t *entries = map->entries;
- pni_map_allocate(map);
-
- for (size_t i = 0; i < oldcap; i++) {
- if (entries[i].state != PNI_ENTRY_FREE) {
- void *key = entries[i].key;
- void *value = entries[i].value;
- pn_map_put(map, key, value);
- }
- }
-
- for (size_t i = 0; i < oldcap; i++) {
- if (entries[i].state != PNI_ENTRY_FREE) {
- void *key = entries[i].key;
- void *value = entries[i].value;
- pn_class_decref(map->key, key);
- pn_class_decref(map->value, value);
- }
- }
-
- free(entries);
- return true;
-}
-
-static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create)
-{
- uintptr_t hashcode = map->hashcode(key);
-
- pni_entry_t *entry = &map->entries[hashcode % map->addressable];
- pni_entry_t *prev = NULL;
-
- if (entry->state == PNI_ENTRY_FREE) {
- if (create) {
- entry->state = PNI_ENTRY_TAIL;
- entry->key = key;
- pn_class_incref(map->key, key);
- map->size++;
- return entry;
- } else {
- return NULL;
- }
- }
-
- while (true) {
- if (map->equals(entry->key, key)) {
- if (pprev) *pprev = prev;
- return entry;
- }
-
- if (entry->state == PNI_ENTRY_TAIL) {
- break;
- } else {
- prev = entry;
- entry = &map->entries[entry->next];
- }
- }
-
- if (create) {
- if (pni_map_ensure(map, map->size + 1)) {
- // if we had to grow the table we need to start over
- return pni_map_entry(map, key, pprev, create);
- }
-
- size_t empty = 0;
- for (size_t i = 0; i < map->capacity; i++) {
- size_t idx = map->capacity - i - 1;
- if (map->entries[idx].state == PNI_ENTRY_FREE) {
- empty = idx;
- break;
- }
- }
- entry->next = empty;
- entry->state = PNI_ENTRY_LINK;
- map->entries[empty].state = PNI_ENTRY_TAIL;
- map->entries[empty].key = key;
- pn_class_incref(map->key, key);
- if (pprev) *pprev = entry;
- map->size++;
- return &map->entries[empty];
- } else {
- return NULL;
- }
-}
-
-int pn_map_put(pn_map_t *map, void *key, void *value)
-{
- assert(map);
- pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
- void *dref_val = entry->value;
- entry->value = value;
- pn_class_incref(map->value, value);
- pn_class_decref(map->value, dref_val);
- return 0;
-}
-
-void *pn_map_get(pn_map_t *map, void *key)
-{
- assert(map);
- pni_entry_t *entry = pni_map_entry(map, key, NULL, false);
- return entry ? entry->value : NULL;
-}
-
-static void pni_map_rehash(pn_map_t *map, size_t index)
-{
- //reinsert entries in chain starting at index
- assert(map);
- size_t i = index;
- bool complete = false;
- while (!complete) {
- pni_entry_t *entry = &map->entries[i];
- assert(entry);
- assert(entry->state != PNI_ENTRY_FREE);
- size_t current = i;
- if (entry->state == PNI_ENTRY_TAIL) {
- complete = true;
- } else {
- assert(entry->state == PNI_ENTRY_LINK);
- i = entry->next;
- }
- uintptr_t hashcode = map->hashcode(entry->key);
- pni_entry_t *reloc = &map->entries[hashcode % map->addressable];
- if (reloc->state == PNI_ENTRY_FREE) {
- //correct addressable slot is available, copy into that...
- reloc->state = PNI_ENTRY_TAIL;
- reloc->key = entry->key;
- reloc->value = entry->value;
- //...then free the current entry
- entry->key = NULL;
- entry->value = NULL;
- entry->state = PNI_ENTRY_FREE;
- entry->next = 0;
- } else {
- //iterate to end of chain...
- while (reloc->state == PNI_ENTRY_LINK) {
- reloc = &map->entries[reloc->next];
- }
- assert(reloc->state == PNI_ENTRY_TAIL);
- //... and append current entry
- reloc->state = PNI_ENTRY_LINK;
- reloc->next = current;
- entry->state = PNI_ENTRY_TAIL;
- entry->next = 0;
- }
- }
-}
-
-void pn_map_del(pn_map_t *map, void *key)
-{
- assert(map);
- pni_entry_t *prev = NULL;
- pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
- if (entry) {
- uint8_t orig_state = entry->state;
- size_t orig_next = entry->next;
-
- void *dref_key = entry->key;
- void *dref_value = entry->value;
- if (prev) {
- prev->next = 0;
- prev->state = PNI_ENTRY_TAIL;
- }
- entry->state = PNI_ENTRY_FREE;
- entry->next = 0;
- entry->key = NULL;
- entry->value = NULL;
- map->size--;
-
- if (orig_state == PNI_ENTRY_LINK) {
- pni_map_rehash(map, orig_next);
- }
-
- // do this last as it may trigger further deletions
- pn_class_decref(map->key, dref_key);
- pn_class_decref(map->value, dref_value);
- }
-}
-
-pn_handle_t pn_map_head(pn_map_t *map)
-{
- assert(map);
- for (size_t i = 0; i < map->capacity; i++)
- {
- if (map->entries[i].state != PNI_ENTRY_FREE) {
- return (pn_handle_t)(i + 1);
- }
- }
-
- return 0;
-}
-
-pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry)
-{
- for (size_t i = (size_t)entry; i < map->capacity; i++) {
- if (map->entries[i].state != PNI_ENTRY_FREE) {
- return (pn_handle_t)(i + 1);
- }
- }
-
- return 0;
-}
-
-void *pn_map_key(pn_map_t *map, pn_handle_t entry)
-{
- assert(map);
- assert(entry);
- return map->entries[(size_t)entry - 1].key;
-}
-
-void *pn_map_value(pn_map_t *map, pn_handle_t entry)
-{
- assert(map);
- assert(entry);
- return map->entries[(size_t)entry - 1].value;
-}
-
-struct pn_hash_t {
- pn_map_t map;
-};
-
-static uintptr_t pni_identity_hashcode(void *obj)
-{
- return (uintptr_t ) obj;
-}
-
-static bool pni_identity_equals(void *a, void *b)
-{
- return a == b;
-}
-
-#define CID_pni_uintptr CID_pn_void
-static const pn_class_t *pni_uintptr_reify(void *object);
-#define pni_uintptr_new NULL
-#define pni_uintptr_free NULL
-#define pni_uintptr_initialize NULL
-static void pni_uintptr_incref(void *object) {}
-static void pni_uintptr_decref(void *object) {}
-static int pni_uintptr_refcount(void *object) { return -1; }
-#define pni_uintptr_finalize NULL
-#define pni_uintptr_hashcode NULL
-#define pni_uintptr_compare NULL
-#define pni_uintptr_inspect NULL
-
-static const pn_class_t PN_UINTPTR[] = {PN_METACLASS(pni_uintptr)};
-
-static const pn_class_t *pni_uintptr_reify(void *object)
-{
- return PN_UINTPTR;
-}
-
-pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor)
-{
- pn_hash_t *hash = (pn_hash_t *) pn_map(PN_UINTPTR, clazz, capacity, load_factor);
- hash->map.hashcode = pni_identity_hashcode;
- hash->map.equals = pni_identity_equals;
- return hash;
-}
-
-size_t pn_hash_size(pn_hash_t *hash)
-{
- return pn_map_size(&hash->map);
-}
-
-int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value)
-{
- return pn_map_put(&hash->map, (void *) key, value);
-}
-
-void *pn_hash_get(pn_hash_t *hash, uintptr_t key)
-{
- return pn_map_get(&hash->map, (void *) key);
-}
-
-void pn_hash_del(pn_hash_t *hash, uintptr_t key)
-{
- pn_map_del(&hash->map, (void *) key);
-}
-
-pn_handle_t pn_hash_head(pn_hash_t *hash)
-{
- return pn_map_head(&hash->map);
-}
-
-pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry)
-{
- return pn_map_next(&hash->map, entry);
-}
-
-uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry)
-{
- return (uintptr_t) pn_map_key(&hash->map, entry);
-}
-
-void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry)
-{
- return pn_map_value(&hash->map, entry);
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[06/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/selectable.h b/proton-c/src/reactor/selectable.h
new file mode 100644
index 0000000..7a5b80b
--- /dev/null
+++ b/proton-c/src/reactor/selectable.h
@@ -0,0 +1,36 @@
+#ifndef _PROTON_SRC_SELECTABLE_H
+#define _PROTON_SRC_SELECTABLE_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include <proton/selectable.h>
+
+void *pni_selectable_get_context(pn_selectable_t *selectable);
+void pni_selectable_set_context(pn_selectable_t *selectable, void *context);
+int pni_selectable_get_index(pn_selectable_t *selectable);
+void pni_selectable_set_index(pn_selectable_t *selectable, int index);
+
+#endif /* selectable.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/selector.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/selector.h b/proton-c/src/reactor/selector.h
new file mode 100644
index 0000000..2a1e31f
--- /dev/null
+++ b/proton-c/src/reactor/selector.h
@@ -0,0 +1,53 @@
+#ifndef PROTON_SELECTOR_H
+#define PROTON_SELECTOR_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/selectable.h>
+#include <proton/type_compat.h>
+
+#define PN_READABLE (1)
+#define PN_WRITABLE (2)
+#define PN_EXPIRED (4)
+#define PN_ERROR (8)
+
+/**
+ * A ::pn_selector_t provides a selection mechanism that allows
+ * efficient monitoring of a large number of Proton connections and
+ * listeners.
+ *
+ * External (non-Proton) sockets may also be monitored, either solely
+ * for event notification (read, write, and timer) or event
+ * notification and use with pn_io_t interfaces.
+ */
+typedef struct pn_selector_t pn_selector_t;
+
+pn_selector_t *pni_selector(void);
+void pn_selector_free(pn_selector_t *selector);
+void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable);
+void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable);
+void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable);
+size_t pn_selector_size(pn_selector_t *selector);
+int pn_selector_select(pn_selector_t *select, int timeout);
+pn_selectable_t *pn_selector_next(pn_selector_t *select, int *events);
+
+#endif /* selector.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/cyrus_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/cyrus_sasl.c b/proton-c/src/sasl/cyrus_sasl.c
index dfc13d0..0d81489 100644
--- a/proton-c/src/sasl/cyrus_sasl.c
+++ b/proton-c/src/sasl/cyrus_sasl.c
@@ -19,10 +19,10 @@
*
*/
-#include "config.h"
+#include "core/config.h"
+#include "core/engine-internal.h"
#include "sasl-internal.h"
-#include "engine/engine-internal.h"
#include <sasl/sasl.h>
#include <pthread.h>
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/none_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/none_sasl.c b/proton-c/src/sasl/none_sasl.c
index d1ee67f..0408a8f 100644
--- a/proton-c/src/sasl/none_sasl.c
+++ b/proton-c/src/sasl/none_sasl.c
@@ -21,7 +21,7 @@
#include "sasl-internal.h"
-#include "engine/engine-internal.h"
+#include "core/engine-internal.h"
static const char ANONYMOUS[] = "ANONYMOUS";
static const char EXTERNAL[] = "EXTERNAL";
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/sasl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl-internal.h b/proton-c/src/sasl/sasl-internal.h
index 063cd0d..2873777 100644
--- a/proton-c/src/sasl/sasl-internal.h
+++ b/proton-c/src/sasl/sasl-internal.h
@@ -22,11 +22,12 @@
#ifndef PROTON_SASL_INTERNAL_H
#define PROTON_SASL_INTERNAL_H 1
-#include "buffer.h"
+#include "core/buffer.h"
+#include "core/engine-internal.h"
+
#include "proton/types.h"
#include "proton/sasl.h"
-#include "engine/engine-internal.h"
// SASL APIs used by transport code
void pn_sasl_free(pn_transport_t *transport);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 47dc76c..c917d58 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -21,13 +21,14 @@
#include "sasl-internal.h"
-#include "dispatch_actions.h"
-#include "engine/engine-internal.h"
+#include "core/autodetect.h"
+#include "core/dispatch_actions.h"
+#include "core/engine-internal.h"
+#include "core/util.h"
#include "protocol.h"
+
#include "proton/ssl.h"
#include "proton/types.h"
-#include "util.h"
-#include "transport/autodetect.h"
#include <assert.h>
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/scanner.c
----------------------------------------------------------------------
diff --git a/proton-c/src/scanner.c b/proton-c/src/scanner.c
deleted file mode 100644
index 9a058e9..0000000
--- a/proton-c/src/scanner.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/scanner.h>
-#include <proton/error.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "platform.h"
-
-#define ERROR_SIZE (1024)
-
-struct pn_scanner_t {
- const char *input;
- const char *position;
- pn_token_t token;
- char *atoms;
- size_t size;
- size_t capacity;
- pn_error_t *error;
-};
-
-static const char *pni_token_type(pn_token_type_t type)
-{
- switch (type)
- {
- case PN_TOK_LBRACE: return "LBRACE";
- case PN_TOK_RBRACE: return "RBRACE";
- case PN_TOK_LBRACKET: return "LBRACKET";
- case PN_TOK_RBRACKET: return "RBRACKET";
- case PN_TOK_EQUAL: return "EQUAL";
- case PN_TOK_COMMA: return "COMMA";
- case PN_TOK_POS: return "POS";
- case PN_TOK_NEG: return "NEG";
- case PN_TOK_DOT: return "DOT";
- case PN_TOK_AT: return "AT";
- case PN_TOK_DOLLAR: return "DOLLAR";
- case PN_TOK_BINARY: return "BINARY";
- case PN_TOK_STRING: return "STRING";
- case PN_TOK_SYMBOL: return "SYMBOL";
- case PN_TOK_ID: return "ID";
- case PN_TOK_FLOAT: return "FLOAT";
- case PN_TOK_INT: return "INT";
- case PN_TOK_TRUE: return "TRUE";
- case PN_TOK_FALSE: return "FALSE";
- case PN_TOK_NULL: return "NULL";
- case PN_TOK_EOS: return "EOS";
- case PN_TOK_ERR: return "ERR";
- default: return "<UNKNOWN>";
- }
-}
-
-pn_scanner_t *pn_scanner()
-{
- pn_scanner_t *scanner = (pn_scanner_t *) malloc(sizeof(pn_scanner_t));
- if (scanner) {
- scanner->input = NULL;
- scanner->error = pn_error();
- }
- return scanner;
-}
-
-void pn_scanner_free(pn_scanner_t *scanner)
-{
- if (scanner) {
- pn_error_free(scanner->error);
- free(scanner);
- }
-}
-
-pn_token_t pn_scanner_token(pn_scanner_t *scanner)
-{
- if (scanner) {
- return scanner->token;
- } else {
- pn_token_t tok = {PN_TOK_ERR, 0, (size_t)0};
- return tok;
- }
-}
-
-void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col)
-{
- *line = 1;
- *col = 0;
-
- for (const char *c = scanner->input; *c && c <= scanner->token.start; c++) {
- if (*c == '\n') {
- *line += 1;
- *col = -1;
- } else {
- *col += 1;
- }
- }
-}
-
-int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- int err = pn_scanner_verr(scanner, code, fmt, ap);
- va_end(ap);
- return err;
-}
-
-int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap)
-{
- char error[ERROR_SIZE];
-
- int line, col;
- pn_scanner_line_info(scanner, &line, &col);
- int size = scanner->token.size;
- int ln = snprintf(error, ERROR_SIZE,
- "input line %i column %i %s:'%.*s': ", line, col,
- pni_token_type(scanner->token.type),
- size, scanner->token.start);
- if (ln >= ERROR_SIZE) {
- return pn_scanner_err(scanner, code, "error info truncated");
- } else if (ln < 0) {
- error[0] = '\0';
- }
-
- int n = snprintf(error + ln, ERROR_SIZE - ln, fmt, ap);
-
- if (n >= ERROR_SIZE - ln) {
- return pn_scanner_err(scanner, code, "error info truncated");
- } else if (n < 0) {
- error[0] = '\0';
- }
-
- return pn_error_set(scanner->error, code, error);
-}
-
-int pn_scanner_errno(pn_scanner_t *scanner)
-{
- return pn_error_code(scanner->error);
-}
-
-const char *pn_scanner_error(pn_scanner_t *scanner)
-{
- return pn_error_text(scanner->error);
-}
-
-static void pni_scanner_emit(pn_scanner_t *scanner, pn_token_type_t type, const char *start, size_t size)
-{
- scanner->token.type = type;
- scanner->token.start = start;
- scanner->token.size = size;
-}
-
-static int pni_scanner_quoted(pn_scanner_t *scanner, const char *str, int start,
- pn_token_type_t type)
-{
- bool escape = false;
-
- for (int i = start; true; i++) {
- char c = str[i];
- if (escape) {
- escape = false;
- } else {
- switch (c) {
- case '\0':
- case '"':
- pni_scanner_emit(scanner, c ? type : PN_TOK_ERR,
- str, c ? i + 1 : i);
- return c ? 0 : pn_scanner_err(scanner, PN_ERR, "missmatched quote");
- case '\\':
- escape = true;
- break;
- }
- }
- }
-}
-
-static int pni_scanner_binary(pn_scanner_t *scanner, const char *str)
-{
- return pni_scanner_quoted(scanner, str, 2, PN_TOK_BINARY);
-}
-
-static int pni_scanner_string(pn_scanner_t *scanner, const char *str)
-{
- return pni_scanner_quoted(scanner, str, 1, PN_TOK_STRING);
-}
-
-static int pni_scanner_alpha_end(pn_scanner_t *scanner, const char *str, int start)
-{
- for (int i = start; true; i++) {
- char c = str[i];
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
- return i;
- }
- }
-}
-
-static int pni_scanner_alpha(pn_scanner_t *scanner, const char *str)
-{
- int n = pni_scanner_alpha_end(scanner, str, 0);
- pn_token_type_t type;
- if (!strncmp(str, "true", n)) {
- type = PN_TOK_TRUE;
- } else if (!strncmp(str, "false", n)) {
- type = PN_TOK_FALSE;
- } else if (!strncmp(str, "null", n)) {
- type = PN_TOK_NULL;
- } else {
- type = PN_TOK_ID;
- }
-
- pni_scanner_emit(scanner, type, str, n);
- return 0;
-}
-
-static int pni_scanner_symbol(pn_scanner_t *scanner, const char *str)
-{
- char c = str[1];
-
- if (c == '"') {
- return pni_scanner_quoted(scanner, str, 2, PN_TOK_SYMBOL);
- } else {
- int n = pni_scanner_alpha_end(scanner, str, 1);
- pni_scanner_emit(scanner, PN_TOK_SYMBOL, str, n);
- return 0;
- }
-}
-
-static int pni_scanner_number(pn_scanner_t *scanner, const char *str)
-{
- bool dot = false;
- bool exp = false;
-
- int i = 0;
-
- if (str[i] == '+' || str[i] == '-') {
- i++;
- }
-
- for ( ; true; i++) {
- char c = str[i];
- switch (c) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6':
- case '7': case '8': case '9':
- continue;
- case '.':
- if (dot) {
- pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
- return 0;
- } else {
- dot = true;
- }
- continue;
- case 'e':
- case 'E':
- if (exp) {
- pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
- return 0;
- } else {
- dot = true;
- exp = true;
- if (str[i+1] == '+' || str[i+1] == '-') {
- i++;
- }
- continue;
- }
- default:
- if (dot || exp) {
- pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
- return 0;
- } else {
- pni_scanner_emit(scanner, PN_TOK_INT, str, i);
- return 0;
- }
- }
- }
-}
-
-static int pni_scanner_single(pn_scanner_t *scanner, const char *str, pn_token_type_t type)
-{
- pni_scanner_emit(scanner, type, str, 1);
- return 0;
-}
-
-int pn_scanner_start(pn_scanner_t *scanner, const char *input)
-{
- if (!scanner || !input) return PN_ARG_ERR;
- scanner->input = input;
- scanner->position = input;
- return pn_scanner_scan(scanner);
-}
-
-int pn_scanner_scan(pn_scanner_t *scanner)
-{
- const char *str = scanner->position;
- char n;
-
- for (char c; true; str++) {
- c = *str;
- switch (c)
- {
- case '{':
- return pni_scanner_single(scanner, str, PN_TOK_LBRACE);
- case '}':
- return pni_scanner_single(scanner, str, PN_TOK_RBRACE);
- case'[':
- return pni_scanner_single(scanner, str, PN_TOK_LBRACKET);
- case ']':
- return pni_scanner_single(scanner, str, PN_TOK_RBRACKET);
- case '=':
- return pni_scanner_single(scanner, str, PN_TOK_EQUAL);
- case ',':
- return pni_scanner_single(scanner, str, PN_TOK_COMMA);
- case '.':
- n = *(str+1);
- if ((n >= '0' && n <= '9')) {
- return pni_scanner_number(scanner, str);
- } else {
- return pni_scanner_single(scanner, str, PN_TOK_DOT);
- }
- case '@':
- return pni_scanner_single(scanner, str, PN_TOK_AT);
- case '$':
- return pni_scanner_single(scanner, str, PN_TOK_DOLLAR);
- case '-':
- n = *(str+1);
- if ((n >= '0' && n <= '9') || n == '.') {
- return pni_scanner_number(scanner, str);
- } else {
- return pni_scanner_single(scanner, str, PN_TOK_NEG);
- }
- case '+':
- n = *(str+1);
- if ((n >= '0' && n <= '9') || n == '.') {
- return pni_scanner_number(scanner, str);
- } else {
- return pni_scanner_single(scanner, str, PN_TOK_POS);
- }
- case ' ': case '\t': case '\r': case '\v': case '\f': case '\n':
- break;
- case '0': case '1': case '2': case '3': case '4': case '5': case '6':
- case '7': case '8': case '9':
- return pni_scanner_number(scanner, str);
- case ':':
- return pni_scanner_symbol(scanner, str);
- case '"':
- return pni_scanner_string(scanner, str);
- case 'b':
- if (str[1] == '"') {
- return pni_scanner_binary(scanner, str);
- }
- case 'a': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
- case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o':
- case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v':
- case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
- case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q':
- case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- return pni_scanner_alpha(scanner, str);
- case '\0':
- pni_scanner_emit(scanner, PN_TOK_EOS, str, 0);
- return PN_EOS;
- default:
- pni_scanner_emit(scanner, PN_TOK_ERR, str, 1);
- return pn_scanner_err(scanner, PN_ERR, "illegal character");
- }
- }
-}
-
-int pn_scanner_shift(pn_scanner_t *scanner)
-{
- scanner->position = scanner->token.start + scanner->token.size;
- int err = pn_scanner_scan(scanner);
- if (err == PN_EOS) {
- return 0;
- } else {
- return err;
- }
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/selectable.c
----------------------------------------------------------------------
diff --git a/proton-c/src/selectable.c b/proton-c/src/selectable.c
deleted file mode 100644
index 88a60f7..0000000
--- a/proton-c/src/selectable.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/error.h>
-#include <proton/io.h>
-#include "selectable.h"
-#include <stdlib.h>
-#include <assert.h>
-
-pn_selectables_t *pn_selectables(void)
-{
- return pn_iterator();
-}
-
-pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables)
-{
- return (pn_selectable_t *) pn_iterator_next(selectables);
-}
-
-void pn_selectables_free(pn_selectables_t *selectables)
-{
- pn_free(selectables);
-}
-
-struct pn_selectable_t {
- pn_socket_t fd;
- int index;
- pn_record_t *attachments;
- void (*readable)(pn_selectable_t *);
- void (*writable)(pn_selectable_t *);
- void (*error)(pn_selectable_t *);
- void (*expired)(pn_selectable_t *);
- void (*release) (pn_selectable_t *);
- void (*finalize)(pn_selectable_t *);
- pn_collector_t *collector;
- pn_timestamp_t deadline;
- bool reading;
- bool writing;
- bool registered;
- bool terminal;
-};
-
-void pn_selectable_initialize(pn_selectable_t *sel)
-{
- sel->fd = PN_INVALID_SOCKET;
- sel->index = -1;
- sel->attachments = pn_record();
- sel->readable = NULL;
- sel->writable = NULL;
- sel->error = NULL;
- sel->expired = NULL;
- sel->release = NULL;
- sel->finalize = NULL;
- sel->collector = NULL;
- sel->deadline = 0;
- sel->reading = false;
- sel->writing = false;
- sel->registered = false;
- sel->terminal = false;
-}
-
-void pn_selectable_finalize(pn_selectable_t *sel)
-{
- if (sel->finalize) {
- sel->finalize(sel);
- }
- pn_decref(sel->attachments);
- pn_decref(sel->collector);
-}
-
-#define pn_selectable_hashcode NULL
-#define pn_selectable_inspect NULL
-#define pn_selectable_compare NULL
-
-PN_CLASSDEF(pn_selectable)
-
-pn_selectable_t *pn_selectable(void)
-{
- return pn_selectable_new();
-}
-
-bool pn_selectable_is_reading(pn_selectable_t *sel) {
- assert(sel);
- return sel->reading;
-}
-
-void pn_selectable_set_reading(pn_selectable_t *sel, bool reading) {
- assert(sel);
- sel->reading = reading;
-}
-
-bool pn_selectable_is_writing(pn_selectable_t *sel) {
- assert(sel);
- return sel->writing;
-}
-
-void pn_selectable_set_writing(pn_selectable_t *sel, bool writing) {
- assert(sel);
- sel->writing = writing;
-}
-
-pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *sel) {
- assert(sel);
- return sel->deadline;
-}
-
-void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline) {
- assert(sel);
- sel->deadline = deadline;
-}
-
-void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *)) {
- assert(sel);
- sel->readable = readable;
-}
-
-void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *)) {
- assert(sel);
- sel->writable = writable;
-}
-
-void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *)) {
- assert(sel);
- sel->error = error;
-}
-
-void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *)) {
- assert(sel);
- sel->expired = expired;
-}
-
-void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *)) {
- assert(sel);
- sel->release = release;
-}
-
-void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *)) {
- assert(sel);
- sel->finalize = finalize;
-}
-
-pn_record_t *pn_selectable_attachments(pn_selectable_t *sel) {
- return sel->attachments;
-}
-
-void *pni_selectable_get_context(pn_selectable_t *selectable)
-{
- assert(selectable);
- return pn_record_get(selectable->attachments, PN_LEGCTX);
-}
-
-void pni_selectable_set_context(pn_selectable_t *selectable, void *context)
-{
- assert(selectable);
- pn_record_set(selectable->attachments, PN_LEGCTX, context);
-}
-
-int pni_selectable_get_index(pn_selectable_t *selectable)
-{
- assert(selectable);
- return selectable->index;
-}
-
-void pni_selectable_set_index(pn_selectable_t *selectable, int index)
-{
- assert(selectable);
- selectable->index = index;
-}
-
-pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable)
-{
- assert(selectable);
- return selectable->fd;
-}
-
-void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd)
-{
- assert(selectable);
- selectable->fd = fd;
-}
-
-void pn_selectable_readable(pn_selectable_t *selectable)
-{
- assert(selectable);
- if (selectable->readable) {
- selectable->readable(selectable);
- }
-}
-
-void pn_selectable_writable(pn_selectable_t *selectable)
-{
- assert(selectable);
- if (selectable->writable) {
- selectable->writable(selectable);
- }
-}
-
-void pn_selectable_error(pn_selectable_t *selectable)
-{
- assert(selectable);
- if (selectable->error) {
- selectable->error(selectable);
- }
-}
-
-void pn_selectable_expired(pn_selectable_t *selectable)
-{
- assert(selectable);
- if (selectable->expired) {
- selectable->expired(selectable);
- }
-}
-
-bool pn_selectable_is_registered(pn_selectable_t *selectable)
-{
- assert(selectable);
- return selectable->registered;
-}
-
-void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered)
-{
- assert(selectable);
- selectable->registered = registered;
-}
-
-bool pn_selectable_is_terminal(pn_selectable_t *selectable)
-{
- assert(selectable);
- return selectable->terminal;
-}
-
-void pn_selectable_terminate(pn_selectable_t *selectable)
-{
- assert(selectable);
- selectable->terminal = true;
-}
-
-void pn_selectable_release(pn_selectable_t *selectable)
-{
- assert(selectable);
- if (selectable->release) {
- selectable->release(selectable);
- }
-}
-
-void pn_selectable_free(pn_selectable_t *selectable)
-{
- pn_decref(selectable);
-}
-
-static void pni_readable(pn_selectable_t *selectable) {
- pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_READABLE);
-}
-
-static void pni_writable(pn_selectable_t *selectable) {
- pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_WRITABLE);
-}
-
-static void pni_error(pn_selectable_t *selectable) {
- pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_ERROR);
-}
-
-static void pni_expired(pn_selectable_t *selectable) {
- pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_EXPIRED);
-}
-
-void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector) {
- assert(selectable);
- pn_decref(selectable->collector);
- selectable->collector = collector;
- pn_incref(selectable->collector);
-
- if (collector) {
- pn_selectable_on_readable(selectable, pni_readable);
- pn_selectable_on_writable(selectable, pni_writable);
- pn_selectable_on_error(selectable, pni_error);
- pn_selectable_on_expired(selectable, pni_expired);
- }
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/src/selectable.h b/proton-c/src/selectable.h
deleted file mode 100644
index 7a5b80b..0000000
--- a/proton-c/src/selectable.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _PROTON_SRC_SELECTABLE_H
-#define _PROTON_SRC_SELECTABLE_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-
-#include <proton/selectable.h>
-
-void *pni_selectable_get_context(pn_selectable_t *selectable);
-void pni_selectable_set_context(pn_selectable_t *selectable, void *context);
-int pni_selectable_get_index(pn_selectable_t *selectable);
-void pni_selectable_set_index(pn_selectable_t *selectable, int index);
-
-#endif /* selectable.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index 48cb051..0d7c40b 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -19,11 +19,12 @@
*
*/
+#include "platform/platform.h"
+#include "core/util.h"
+#include "core/engine-internal.h"
+
#include <proton/ssl.h>
#include <proton/engine.h>
-#include "engine/engine-internal.h"
-#include "platform.h"
-#include "util.h"
// openssl on windows expects the user to have already included
// winsock.h
@@ -749,7 +750,7 @@ bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
if (ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) {
const char *v = SSL_CIPHER_get_name(c);
if (v) {
- snprintf( buffer, size, "%s", v );
+ pni_snprintf( buffer, size, "%s", v );
return true;
}
}
@@ -765,7 +766,7 @@ bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
if (ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) {
const char *v = SSL_CIPHER_get_version(c);
if (v) {
- snprintf( buffer, size, "%s", v );
+ pni_snprintf( buffer, size, "%s", v );
return true;
}
}
@@ -1345,7 +1346,7 @@ int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0, char *fingerprint, size_t finger
char *cursor = fingerprint;
for (size_t i=0; i<len ; i++) {
- cursor += snprintf((char *)cursor, fingerprint_length, "%02x", bytes[i]);
+ cursor += pni_snprintf((char *)cursor, fingerprint_length, "%02x", bytes[i]);
fingerprint_length = fingerprint_length - 2;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[08/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/object.c b/proton-c/src/object/object.c
deleted file mode 100644
index b0c1b33..0000000
--- a/proton-c/src/object/object.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define pn_object_initialize NULL
-#define pn_object_finalize NULL
-#define pn_object_inspect NULL
-uintptr_t pn_object_hashcode(void *object) { return (uintptr_t) object; }
-intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
-
-const pn_class_t PN_OBJECT[] = {PN_CLASS(pn_object)};
-
-#define pn_void_initialize NULL
-static void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); }
-static void pn_void_incref(void *object) {}
-static void pn_void_decref(void *object) {}
-static int pn_void_refcount(void *object) { return -1; }
-#define pn_void_finalize NULL
-static void pn_void_free(void *object) { free(object); }
-static const pn_class_t *pn_void_reify(void *object) { return PN_VOID; }
-uintptr_t pn_void_hashcode(void *object) { return (uintptr_t) object; }
-intptr_t pn_void_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
-int pn_void_inspect(void *object, pn_string_t *dst) { return pn_string_addf(dst, "%p", object); }
-
-const pn_class_t PN_VOID[] = {PN_METACLASS(pn_void)};
-
-const char *pn_class_name(const pn_class_t *clazz)
-{
- return clazz->name;
-}
-
-pn_cid_t pn_class_id(const pn_class_t *clazz)
-{
- return clazz->cid;
-}
-
-void *pn_class_new(const pn_class_t *clazz, size_t size)
-{
- assert(clazz);
- void *object = clazz->newinst(clazz, size);
- if (clazz->initialize) {
- clazz->initialize(object);
- }
- return object;
-}
-
-void *pn_class_incref(const pn_class_t *clazz, void *object)
-{
- assert(clazz);
- if (object) {
- clazz = clazz->reify(object);
- clazz->incref(object);
- }
- return object;
-}
-
-int pn_class_refcount(const pn_class_t *clazz, void *object)
-{
- assert(clazz);
- clazz = clazz->reify(object);
- return clazz->refcount(object);
-}
-
-int pn_class_decref(const pn_class_t *clazz, void *object)
-{
- assert(clazz);
-
- if (object) {
- clazz = clazz->reify(object);
- clazz->decref(object);
- int rc = clazz->refcount(object);
- if (rc == 0) {
- if (clazz->finalize) {
- clazz->finalize(object);
- // check the refcount again in case the finalizer created a
- // new reference
- rc = clazz->refcount(object);
- }
- if (rc == 0) {
- clazz->free(object);
- return 0;
- }
- } else {
- return rc;
- }
- }
-
- return 0;
-}
-
-void pn_class_free(const pn_class_t *clazz, void *object)
-{
- assert(clazz);
- if (object) {
- clazz = clazz->reify(object);
- int rc = clazz->refcount(object);
- assert(rc == 1 || rc == -1);
- if (rc == 1) {
- rc = pn_class_decref(clazz, object);
- assert(rc == 0);
- } else {
- if (clazz->finalize) {
- clazz->finalize(object);
- }
- clazz->free(object);
- }
- }
-}
-
-const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object)
-{
- assert(clazz);
- return clazz->reify(object);
-}
-
-uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object)
-{
- assert(clazz);
-
- if (!object) return 0;
-
- clazz = clazz->reify(object);
-
- if (clazz->hashcode) {
- return clazz->hashcode(object);
- } else {
- return (uintptr_t) object;
- }
-}
-
-intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b)
-{
- assert(clazz);
-
- if (a == b) return 0;
-
- clazz = clazz->reify(a);
-
- if (a && b && clazz->compare) {
- return clazz->compare(a, b);
- } else {
- return (intptr_t) a - (intptr_t) b;
- }
-}
-
-bool pn_class_equals(const pn_class_t *clazz, void *a, void *b)
-{
- return pn_class_compare(clazz, a, b) == 0;
-}
-
-int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst)
-{
- assert(clazz);
-
- clazz = clazz->reify(object);
-
- if (!pn_string_get(dst)) {
- pn_string_set(dst, "");
- }
-
- if (object && clazz->inspect) {
- return clazz->inspect(object, dst);
- }
-
- const char *name = clazz->name ? clazz->name : "<anon>";
-
- return pn_string_addf(dst, "%s<%p>", name, object);
-}
-
-typedef struct {
- const pn_class_t *clazz;
- int refcount;
-} pni_head_t;
-
-#define pni_head(PTR) \
- (((pni_head_t *) (PTR)) - 1)
-
-void *pn_object_new(const pn_class_t *clazz, size_t size)
-{
- void *object = NULL;
- pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size);
- if (head != NULL) {
- object = head + 1;
- head->clazz = clazz;
- head->refcount = 1;
- }
- return object;
-}
-
-const pn_class_t *pn_object_reify(void *object)
-{
- if (object) {
- return pni_head(object)->clazz;
- } else {
- return PN_OBJECT;
- }
-}
-
-void pn_object_incref(void *object)
-{
- if (object) {
- pni_head(object)->refcount++;
- }
-}
-
-int pn_object_refcount(void *object)
-{
- assert(object);
- return pni_head(object)->refcount;
-}
-
-void pn_object_decref(void *object)
-{
- pni_head_t *head = pni_head(object);
- assert(head->refcount > 0);
- head->refcount--;
-}
-
-void pn_object_free(void *object)
-{
- pni_head_t *head = pni_head(object);
- free(head);
-}
-
-void *pn_incref(void *object)
-{
- return pn_class_incref(PN_OBJECT, object);
-}
-
-int pn_decref(void *object)
-{
- return pn_class_decref(PN_OBJECT, object);
-}
-
-int pn_refcount(void *object)
-{
- return pn_class_refcount(PN_OBJECT, object);
-}
-
-void pn_free(void *object)
-{
- pn_class_free(PN_OBJECT, object);
-}
-
-const pn_class_t *pn_class(void *object)
-{
- return pn_class_reify(PN_OBJECT, object);
-}
-
-uintptr_t pn_hashcode(void *object)
-{
- return pn_class_hashcode(PN_OBJECT, object);
-}
-
-intptr_t pn_compare(void *a, void *b)
-{
- return pn_class_compare(PN_OBJECT, a, b);
-}
-
-bool pn_equals(void *a, void *b)
-{
- return !pn_compare(a, b);
-}
-
-int pn_inspect(void *object, pn_string_t *dst)
-{
- return pn_class_inspect(PN_OBJECT, object, dst);
-}
-
-#define pn_weakref_new NULL
-#define pn_weakref_initialize NULL
-#define pn_weakref_finalize NULL
-#define pn_weakref_free NULL
-
-static void pn_weakref_incref(void *object) {}
-static void pn_weakref_decref(void *object) {}
-static int pn_weakref_refcount(void *object) { return -1; }
-static const pn_class_t *pn_weakref_reify(void *object) {
- return PN_WEAKREF;
-}
-static uintptr_t pn_weakref_hashcode(void *object) {
- return pn_hashcode(object);
-}
-static intptr_t pn_weakref_compare(void *a, void *b) {
- return pn_compare(a, b);
-}
-static int pn_weakref_inspect(void *object, pn_string_t *dst) {
- return pn_inspect(object, dst);
-}
-
-const pn_class_t PN_WEAKREF[] = {PN_METACLASS(pn_weakref)};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/record.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/record.c b/proton-c/src/object/record.c
deleted file mode 100644
index 6f4fe0a..0000000
--- a/proton-c/src/object/record.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-typedef struct {
- pn_handle_t key;
- const pn_class_t *clazz;
- void *value;
-} pni_field_t;
-
-struct pn_record_t {
- size_t size;
- size_t capacity;
- pni_field_t *fields;
-};
-
-static void pn_record_initialize(void *object)
-{
- pn_record_t *record = (pn_record_t *) object;
- record->size = 0;
- record->capacity = 0;
- record->fields = NULL;
-}
-
-static void pn_record_finalize(void *object)
-{
- pn_record_t *record = (pn_record_t *) object;
- for (size_t i = 0; i < record->size; i++) {
- pni_field_t *v = &record->fields[i];
- pn_class_decref(v->clazz, v->value);
- }
- free(record->fields);
-}
-
-#define pn_record_hashcode NULL
-#define pn_record_compare NULL
-#define pn_record_inspect NULL
-
-pn_record_t *pn_record(void)
-{
- static const pn_class_t clazz = PN_CLASS(pn_record);
- pn_record_t *record = (pn_record_t *) pn_class_new(&clazz, sizeof(pn_record_t));
- pn_record_def(record, PN_LEGCTX, PN_VOID);
- return record;
-}
-
-static pni_field_t *pni_record_find(pn_record_t *record, pn_handle_t key) {
- for (size_t i = 0; i < record->size; i++) {
- pni_field_t *field = &record->fields[i];
- if (field->key == key) {
- return field;
- }
- }
- return NULL;
-}
-
-static pni_field_t *pni_record_create(pn_record_t *record) {
- record->size++;
- if (record->size > record->capacity) {
- record->fields = (pni_field_t *) realloc(record->fields, record->size * sizeof(pni_field_t));
- record->capacity = record->size;
- }
- pni_field_t *field = &record->fields[record->size - 1];
- field->key = 0;
- field->clazz = NULL;
- field->value = NULL;
- return field;
-}
-
-void pn_record_def(pn_record_t *record, pn_handle_t key, const pn_class_t *clazz)
-{
- assert(record);
- assert(clazz);
-
- pni_field_t *field = pni_record_find(record, key);
- if (field) {
- assert(field->clazz == clazz);
- } else {
- field = pni_record_create(record);
- field->key = key;
- field->clazz = clazz;
- }
-}
-
-bool pn_record_has(pn_record_t *record, pn_handle_t key)
-{
- assert(record);
- pni_field_t *field = pni_record_find(record, key);
- if (field) {
- return true;
- } else {
- return false;
- }
-}
-
-void *pn_record_get(pn_record_t *record, pn_handle_t key)
-{
- assert(record);
- pni_field_t *field = pni_record_find(record, key);
- if (field) {
- return field->value;
- } else {
- return NULL;
- }
-}
-
-void pn_record_set(pn_record_t *record, pn_handle_t key, void *value)
-{
- assert(record);
-
- pni_field_t *field = pni_record_find(record, key);
- if (field) {
- void *old = field->value;
- field->value = value;
- pn_class_incref(field->clazz, value);
- pn_class_decref(field->clazz, old);
- }
-}
-
-void pn_record_clear(pn_record_t *record)
-{
- assert(record);
- for (size_t i = 0; i < record->size; i++) {
- pni_field_t *field = &record->fields[i];
- pn_class_decref(field->clazz, field->value);
- field->key = 0;
- field->clazz = NULL;
- field->value = NULL;
- }
- record->size = 0;
- pn_record_def(record, PN_LEGCTX, PN_VOID);
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/string.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/string.c b/proton-c/src/object/string.c
deleted file mode 100644
index 7b900ca..0000000
--- a/proton-c/src/object/string.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "platform.h"
-
-#include <proton/error.h>
-#include <proton/object.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-
-#define PNI_NULL_SIZE (-1)
-
-struct pn_string_t {
- char *bytes;
- ssize_t size; // PNI_NULL_SIZE (-1) means null
- size_t capacity;
-};
-
-static void pn_string_finalize(void *object)
-{
- pn_string_t *string = (pn_string_t *) object;
- free(string->bytes);
-}
-
-static uintptr_t pn_string_hashcode(void *object)
-{
- pn_string_t *string = (pn_string_t *) object;
- if (string->size == PNI_NULL_SIZE) {
- return 0;
- }
-
- uintptr_t hashcode = 1;
- for (ssize_t i = 0; i < string->size; i++) {
- hashcode = hashcode * 31 + string->bytes[i];
- }
- return hashcode;
-}
-
-static intptr_t pn_string_compare(void *oa, void *ob)
-{
- pn_string_t *a = (pn_string_t *) oa;
- pn_string_t *b = (pn_string_t *) ob;
- if (a->size != b->size) {
- return b->size - a->size;
- }
-
- if (a->size == PNI_NULL_SIZE) {
- return 0;
- } else {
- return memcmp(a->bytes, b->bytes, a->size);
- }
-}
-
-static int pn_string_inspect(void *obj, pn_string_t *dst)
-{
- pn_string_t *str = (pn_string_t *) obj;
- if (str->size == PNI_NULL_SIZE) {
- return pn_string_addf(dst, "null");
- }
-
- int err = pn_string_addf(dst, "\"");
-
- for (int i = 0; i < str->size; i++) {
- uint8_t c = str->bytes[i];
- if (isprint(c)) {
- err = pn_string_addf(dst, "%c", c);
- if (err) return err;
- } else {
- err = pn_string_addf(dst, "\\x%.2x", c);
- if (err) return err;
- }
- }
-
- return pn_string_addf(dst, "\"");
-}
-
-pn_string_t *pn_string(const char *bytes)
-{
- return pn_stringn(bytes, bytes ? strlen(bytes) : 0);
-}
-
-#define pn_string_initialize NULL
-
-
-pn_string_t *pn_stringn(const char *bytes, size_t n)
-{
- static const pn_class_t clazz = PN_CLASS(pn_string);
- pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, sizeof(pn_string_t));
- string->capacity = n ? n * sizeof(char) : 16;
- string->bytes = (char *) malloc(string->capacity);
- pn_string_setn(string, bytes, n);
- return string;
-}
-
-const char *pn_string_get(pn_string_t *string)
-{
- assert(string);
- if (string->size == PNI_NULL_SIZE) {
- return NULL;
- } else {
- return string->bytes;
- }
-}
-
-size_t pn_string_size(pn_string_t *string)
-{
- assert(string);
- if (string->size == PNI_NULL_SIZE) {
- return 0;
- } else {
- return string->size;
- }
-}
-
-int pn_string_set(pn_string_t *string, const char *bytes)
-{
- return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
-}
-
-int pn_string_grow(pn_string_t *string, size_t capacity)
-{
- bool grow = false;
- while (string->capacity < (capacity*sizeof(char) + 1)) {
- string->capacity *= 2;
- grow = true;
- }
-
- if (grow) {
- char *growed = (char *) realloc(string->bytes, string->capacity);
- if (growed) {
- string->bytes = growed;
- } else {
- return PN_ERR;
- }
- }
-
- return 0;
-}
-
-int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
-{
- int err = pn_string_grow(string, n);
- if (err) return err;
-
- if (bytes) {
- memcpy(string->bytes, bytes, n*sizeof(char));
- string->bytes[n] = '\0';
- string->size = n;
- } else {
- string->size = PNI_NULL_SIZE;
- }
-
- return 0;
-}
-
-ssize_t pn_string_put(pn_string_t *string, char *dst)
-{
- assert(string);
- assert(dst);
-
- if (string->size != PNI_NULL_SIZE) {
- memcpy(dst, string->bytes, string->size + 1);
- }
-
- return string->size;
-}
-
-void pn_string_clear(pn_string_t *string)
-{
- pn_string_set(string, NULL);
-}
-
-int pn_string_format(pn_string_t *string, const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- int err = pn_string_vformat(string, format, ap);
- va_end(ap);
- return err;
-}
-
-int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
-{
- pn_string_set(string, "");
- return pn_string_vaddf(string, format, ap);
-}
-
-int pn_string_addf(pn_string_t *string, const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- int err = pn_string_vaddf(string, format, ap);
- va_end(ap);
- return err;
-}
-
-int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap)
-{
- va_list copy;
-
- if (string->size == PNI_NULL_SIZE) {
- return PN_ERR;
- }
-
- while (true) {
- va_copy(copy, ap);
- int err = vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy);
- va_end(copy);
- if (err < 0) {
- return err;
- } else if ((size_t) err >= string->capacity - string->size) {
- pn_string_grow(string, string->size + err);
- } else {
- string->size += err;
- return 0;
- }
- }
-}
-
-char *pn_string_buffer(pn_string_t *string)
-{
- assert(string);
- return string->bytes;
-}
-
-size_t pn_string_capacity(pn_string_t *string)
-{
- assert(string);
- return string->capacity - 1;
-}
-
-int pn_string_resize(pn_string_t *string, size_t size)
-{
- assert(string);
- int err = pn_string_grow(string, size);
- if (err) return err;
- string->size = size;
- string->bytes[size] = '\0';
- return 0;
-}
-
-int pn_string_copy(pn_string_t *string, pn_string_t *src)
-{
- assert(string);
- return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/parser.c
----------------------------------------------------------------------
diff --git a/proton-c/src/parser.c b/proton-c/src/parser.c
deleted file mode 100644
index 87cb758..0000000
--- a/proton-c/src/parser.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/parser.h>
-#include <proton/scanner.h>
-#include <proton/error.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include "platform.h"
-
-struct pn_parser_t {
- pn_scanner_t *scanner;
- char *atoms;
- size_t size;
- size_t capacity;
- int error_code;
-};
-
-pn_parser_t *pn_parser()
-{
- pn_parser_t *parser = (pn_parser_t *) malloc(sizeof(pn_parser_t));
- if (parser != NULL) {
- parser->scanner = pn_scanner();
- parser->atoms = NULL;
- parser->size = 0;
- parser->capacity = 0;
- }
- return parser;
-}
-
-static void pni_parser_ensure(pn_parser_t *parser, size_t size)
-{
- while (parser->capacity - parser->size < size) {
- parser->capacity = parser->capacity ? 2 * parser->capacity : 1024;
- parser->atoms = (char *) realloc(parser->atoms, parser->capacity);
- }
-}
-
-int pn_parser_err(pn_parser_t *parser, int code, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- int err = pn_scanner_verr(parser->scanner, code, fmt, ap);
- va_end(ap);
- return err;
-}
-
-int pn_parser_errno(pn_parser_t *parser)
-{
- return pn_scanner_errno(parser->scanner);
-}
-
-const char *pn_parser_error(pn_parser_t *parser)
-{
- return pn_scanner_error(parser->scanner);
-}
-
-void pn_parser_free(pn_parser_t *parser)
-{
- if (parser) {
- pn_scanner_free(parser->scanner);
- free(parser->atoms);
- free(parser);
- }
-}
-
-static int pni_parser_shift(pn_parser_t *parser)
-{
- return pn_scanner_shift(parser->scanner);
-}
-
-static pn_token_t pni_parser_token(pn_parser_t *parser)
-{
- return pn_scanner_token(parser->scanner);
-}
-
-static int pni_parser_value(pn_parser_t *parser, pn_data_t *data);
-
-static int pni_parser_descriptor(pn_parser_t *parser, pn_data_t *data)
-{
- if (pni_parser_token(parser).type == PN_TOK_AT) {
- int err = pni_parser_shift(parser);
- if (err) return err;
-
- err = pn_data_put_described(data);
- if (err) return pn_parser_err(parser, err, "error writing described");
- pn_data_enter(data);
- for (int i = 0; i < 2; i++) {
- err = pni_parser_value(parser, data);
- if (err) return err;
- }
- pn_data_exit(data);
- return 0;
- } else {
- return pn_parser_err(parser, PN_ERR, "expecting '@'");
- }
-}
-
-static int pni_parser_map(pn_parser_t *parser, pn_data_t *data)
-{
- if (pni_parser_token(parser).type == PN_TOK_LBRACE) {
- int err = pni_parser_shift(parser);
- if (err) return err;
-
- err = pn_data_put_map(data);
- if (err) return pn_parser_err(parser, err, "error writing map");
-
- pn_data_enter(data);
-
- if (pni_parser_token(parser).type != PN_TOK_RBRACE) {
- while (true) {
- err = pni_parser_value(parser, data);
- if (err) return err;
-
- if (pni_parser_token(parser).type == PN_TOK_EQUAL) {
- err = pni_parser_shift(parser);
- if (err) return err;
- } else {
- return pn_parser_err(parser, PN_ERR, "expecting '='");
- }
-
- err = pni_parser_value(parser, data);
- if (err) return err;
-
- if (pni_parser_token(parser).type == PN_TOK_COMMA) {
- err = pni_parser_shift(parser);
- if (err) return err;
- } else {
- break;
- }
- }
- }
-
- pn_data_exit(data);
-
- if (pni_parser_token(parser).type == PN_TOK_RBRACE) {
- return pni_parser_shift(parser);
- } else {
- return pn_parser_err(parser, PN_ERR, "expecting '}'");
- }
- } else {
- return pn_parser_err(parser, PN_ERR, "expecting '{'");
- }
-}
-
-static int pni_parser_list(pn_parser_t *parser, pn_data_t *data)
-{
- int err;
-
- if (pni_parser_token(parser).type == PN_TOK_LBRACKET) {
- err = pni_parser_shift(parser);
- if (err) return err;
-
- err = pn_data_put_list(data);
- if (err) return pn_parser_err(parser, err, "error writing list");
-
- pn_data_enter(data);
-
- if (pni_parser_token(parser).type != PN_TOK_RBRACKET) {
- while (true) {
- err = pni_parser_value(parser, data);
- if (err) return err;
-
- if (pni_parser_token(parser).type == PN_TOK_COMMA) {
- err = pni_parser_shift(parser);
- if (err) return err;
- } else {
- break;
- }
- }
- }
-
- pn_data_exit(data);
-
- if (pni_parser_token(parser).type == PN_TOK_RBRACKET) {
- return pni_parser_shift(parser);
- } else {
- return pn_parser_err(parser, PN_ERR, "expecting ']'");
- }
- } else {
- return pn_parser_err(parser, PN_ERR, "expecting '['");
- }
-}
-
-static void pni_parser_append_tok(pn_parser_t *parser, char *dst, int *idx)
-{
- memcpy(dst + *idx, pni_parser_token(parser).start, pni_parser_token(parser).size);
- *idx += pni_parser_token(parser).size;
-}
-
-static int pni_parser_number(pn_parser_t *parser, pn_data_t *data)
-{
- bool dbl = false;
- char number[1024];
- int idx = 0;
- int err;
-
- bool negate = false;
-
- if (pni_parser_token(parser).type == PN_TOK_NEG || pni_parser_token(parser).type == PN_TOK_POS) {
- if (pni_parser_token(parser).type == PN_TOK_NEG)
- negate = !negate;
- err = pni_parser_shift(parser);
- if (err) return err;
- }
-
- if (pni_parser_token(parser).type == PN_TOK_FLOAT || pni_parser_token(parser).type == PN_TOK_INT) {
- dbl = pni_parser_token(parser).type == PN_TOK_FLOAT;
- pni_parser_append_tok(parser, number, &idx);
- err = pni_parser_shift(parser);
- if (err) return err;
- } else {
- return pn_parser_err(parser, PN_ERR, "expecting FLOAT or INT");
- }
-
- number[idx] = '\0';
-
- if (dbl) {
- double value = atof(number);
- if (negate) {
- value = -value;
- }
- err = pn_data_put_double(data, value);
- if (err) return pn_parser_err(parser, err, "error writing double");
- } else {
- int64_t value = pn_i_atoll(number);
- if (negate) {
- value = -value;
- }
- err = pn_data_put_long(data, value);
- if (err) return pn_parser_err(parser, err, "error writing long");
- }
-
- return 0;
-}
-
-static int pni_parser_unquote(pn_parser_t *parser, char *dst, const char *src, size_t *n)
-{
- size_t idx = 0;
- bool escape = false;
- int start, end;
- if (src[0] != '"') {
- if (src[1] == '"') {
- start = 2;
- end = *n - 1;
- } else {
- start = 1;
- end = *n;
- }
- } else {
- start = 1;
- end = *n - 1;
- }
- for (int i = start; i < end; i++)
- {
- char c = src[i];
- if (escape) {
- switch (c) {
- case '"':
- case '\\':
- case '/':
- dst[idx++] = c;
- escape = false;
- break;
- case 'b':
- dst[idx++] = '\b';
- break;
- case 'f':
- dst[idx++] = '\f';
- break;
- case 'n':
- dst[idx++] = '\n';
- break;
- case 'r':
- dst[idx++] = '\r';
- break;
- case 't':
- dst[idx++] = '\t';
- break;
- case 'x':
- {
- char n1 = toupper(src[i+1]);
- char n2 = n1 ? toupper(src[i+2]) : 0;
- if (!n2) {
- return pn_parser_err(parser, PN_ERR, "truncated escape code");
- }
- int d1 = isdigit(n1) ? n1 - '0' : n1 - 'A' + 10;
- int d2 = isdigit(n2) ? n2 - '0' : n2 - 'A' + 10;
- dst[idx++] = d1*16 + d2;
- i += 2;
- }
- break;
- // XXX: need to handle unicode escapes: 'u'
- default:
- return pn_parser_err(parser, PN_ERR, "unrecognized escape code");
- }
- escape = false;
- } else {
- switch (c)
- {
- case '\\':
- escape = true;
- break;
- default:
- dst[idx++] = c;
- break;
- }
- }
- }
- dst[idx++] = '\0';
- *n = idx;
- return 0;
-}
-
-static int pni_parser_value(pn_parser_t *parser, pn_data_t *data)
-{
- int err;
- size_t n;
- char *dst;
-
- pn_token_t tok = pni_parser_token(parser);
-
- switch (tok.type)
- {
- case PN_TOK_AT:
- return pni_parser_descriptor(parser, data);
- case PN_TOK_LBRACE:
- return pni_parser_map(parser, data);
- case PN_TOK_LBRACKET:
- return pni_parser_list(parser, data);
- case PN_TOK_BINARY:
- case PN_TOK_SYMBOL:
- case PN_TOK_STRING:
- n = tok.size;
- pni_parser_ensure(parser, n);
- dst = parser->atoms + parser->size;
- err = pni_parser_unquote(parser, dst, tok.start, &n);
- if (err) return err;
- parser->size += n;
- switch (tok.type) {
- case PN_TOK_BINARY:
- err = pn_data_put_binary(data, pn_bytes(n - 1, dst));
- break;
- case PN_TOK_STRING:
- err = pn_data_put_string(data, pn_bytes(n - 1, dst));
- break;
- case PN_TOK_SYMBOL:
- err = pn_data_put_symbol(data, pn_bytes(n - 1, dst));
- break;
- default:
- return pn_parser_err(parser, PN_ERR, "internal error");
- }
- if (err) return pn_parser_err(parser, err, "error writing string/binary/symbol");
- return pni_parser_shift(parser);
- case PN_TOK_POS:
- case PN_TOK_NEG:
- case PN_TOK_FLOAT:
- case PN_TOK_INT:
- return pni_parser_number(parser, data);
- case PN_TOK_TRUE:
- err = pn_data_put_bool(data, true);
- if (err) return pn_parser_err(parser, err, "error writing boolean");
- return pni_parser_shift(parser);
- case PN_TOK_FALSE:
- err = pn_data_put_bool(data, false);
- if (err) return pn_parser_err(parser, err, "error writing boolean");
- return pni_parser_shift(parser);
- case PN_TOK_NULL:
- err = pn_data_put_null(data);
- if (err) return pn_parser_err(parser, err, "error writing null");
- return pni_parser_shift(parser);
- default:
- return pn_parser_err(parser, PN_ERR, "expecting one of '[', '{', STRING, "
- "SYMBOL, BINARY, true, false, null, NUMBER");
- }
-}
-
-static int pni_parser_parse_r(pn_parser_t *parser, pn_data_t *data)
-{
- while (true) {
- int err;
- switch (pni_parser_token(parser).type)
- {
- case PN_TOK_EOS:
- return 0;
- case PN_TOK_ERR:
- return PN_ERR;
- default:
- err = pni_parser_value(parser, data);
- if (err) return err;
- }
- }
-}
-
-int pn_parser_parse(pn_parser_t *parser, const char *str, pn_data_t *data)
-{
- int err = pn_scanner_start(parser->scanner, str);
- if (err) return err;
- parser->size = 0;
- return pni_parser_parse_r(parser, data);
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform.c
----------------------------------------------------------------------
diff --git a/proton-c/src/platform.c b/proton-c/src/platform.c
deleted file mode 100644
index 3a8cade..0000000
--- a/proton-c/src/platform.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "platform.h"
-#include "util.h"
-
-#ifdef PN_WINAPI
-#include <windows.h>
-int pn_i_getpid() {
- return (int) GetCurrentProcessId();
-}
-#else
-#include <unistd.h>
-int pn_i_getpid() {
- return (int) getpid();
-}
-#endif
-
-/* Allow for systems that do not implement clock_gettime()*/
-#ifdef USE_CLOCK_GETTIME
-#include <time.h>
-pn_timestamp_t pn_i_now(void)
-{
- struct timespec now;
- if (clock_gettime(CLOCK_REALTIME, &now)) pni_fatal("clock_gettime() failed\n");
- return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_nsec / 1000000);
-}
-#elif defined(USE_WIN_FILETIME)
-#include <windows.h>
-pn_timestamp_t pn_i_now(void)
-{
- FILETIME now;
- GetSystemTimeAsFileTime(&now);
- ULARGE_INTEGER t;
- t.u.HighPart = now.dwHighDateTime;
- t.u.LowPart = now.dwLowDateTime;
- // Convert to milliseconds and adjust base epoch
- return t.QuadPart / 10000 - 11644473600000;
-}
-#else
-#include <sys/time.h>
-pn_timestamp_t pn_i_now(void)
-{
- struct timeval now;
- if (gettimeofday(&now, NULL)) pni_fatal("gettimeofday failed\n");
- return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000);
-}
-#endif
-
-#include <string.h>
-#include <stdio.h>
-static void pn_i_strerror(int errnum, char *buf, size_t buflen)
-{
- // PROTON-1029 provide a simple default in case strerror fails
- snprintf(buf, buflen, "errno: %d", errnum);
-#ifdef USE_STRERROR_R
- strerror_r(errnum, buf, buflen);
-#elif USE_STRERROR_S
- strerror_s(buf, buflen, errnum);
-#elif USE_OLD_STRERROR
- strncpy(buf, strerror(errnum), buflen);
-#endif
-}
-
-int pn_i_error_from_errno(pn_error_t *error, const char *msg)
-{
- char err[1024];
- pn_i_strerror(errno, err, 1024);
- int code = PN_ERR;
- if (errno == EINTR)
- code = PN_INTR;
- return pn_error_format(error, code, "%s: %s", msg, err);
-}
-
-#ifdef USE_ATOLL
-#include <stdlib.h>
-int64_t pn_i_atoll(const char* num) {
- return atoll(num);
-}
-#elif USE_ATOI64
-#include <stdlib.h>
-int64_t pn_i_atoll(const char* num) {
- return _atoi64(num);
-}
-#else
-#error "Don't know how to convert int64_t values on this platform"
-#endif
-
-#ifdef _MSC_VER
-// [v]snprintf on Windows only matches C99 when no errors or overflow.
-int pn_i_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap) {
- if (fmt == NULL)
- return -1;
- if ((buf == NULL) && (count > 0))
- return -1;
- if (count > 0) {
- int n = vsnprintf_s(buf, count, _TRUNCATE, fmt, ap);
- if (n >= 0) // no overflow
- return n; // same as C99
- buf[count-1] = '\0';
- }
- // separate call to get needed buffer size on overflow
- int n = _vscprintf(fmt, ap);
- if (n >= (int) count)
- return n;
- return -1;
-}
-
-int pn_i_snprintf(char *buf, size_t count, const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- int n = pn_i_vsnprintf(buf, count, fmt, ap);
- va_end(ap);
- return n;
-}
-#endif
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform.h b/proton-c/src/platform.h
deleted file mode 100644
index 6a0bbc1..0000000
--- a/proton-c/src/platform.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef PROTON_PLATFORM_H
-#define PROTON_PLATFORM_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/types.h"
-#include "proton/error.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Get the current PID
- *
- * @return process id
- * @internal
- */
-int pn_i_getpid(void);
-
-
-/** Get the current time in pn_timestamp_t format.
- *
- * Returns current time in milliseconds since Unix Epoch,
- * as defined by AMQP 1.0
- *
- * @return current time
- * @internal
- */
-pn_timestamp_t pn_i_now(void);
-
-/** Generate system error message.
- *
- * Populate the proton error structure based on the last system error
- * code.
- *
- * @param[in] error the proton error structure
- * @param[in] msg the descriptive context message
- * @return error->code
- *
- * @internal
- */
-int pn_i_error_from_errno(pn_error_t *error, const char *msg);
-
-/** Provide C99 atoll functinality.
- *
- * @param[in] num the string representation of the number.
- * @return the integer value.
- *
- * @internal
- */
-int64_t pn_i_atoll(const char* num);
-
-#ifdef _MSC_VER
-/** Windows snprintf and vsnprintf substitutes.
- *
- * Provide the expected C99 behavior for these functions.
- */
-#include <stdio.h>
-
-#define snprintf pn_i_snprintf
-#define vsnprintf pn_i_vsnprintf
-
-int pn_i_snprintf(char *buf, size_t count, const char *fmt, ...);
-int pn_i_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap);
-
-#if !defined(S_ISDIR)
-# define S_ISDIR(X) ((X) & _S_IFDIR)
-#endif
-
-#endif
-
-#if defined _MSC_VER || defined _OPENVMS
-#if !defined(va_copy)
-#define va_copy(d,s) ((d) = (s))
-#endif
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* platform.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform/platform.c
----------------------------------------------------------------------
diff --git a/proton-c/src/platform/platform.c b/proton-c/src/platform/platform.c
new file mode 100644
index 0000000..393f75c
--- /dev/null
+++ b/proton-c/src/platform/platform.c
@@ -0,0 +1,122 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "platform.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef PN_WINAPI
+#include <windows.h>
+int pn_i_getpid() {
+ return (int) GetCurrentProcessId();
+}
+#else
+#include <unistd.h>
+int pn_i_getpid() {
+ return (int) getpid();
+}
+#endif
+
+void pni_vfatal(const char *fmt, va_list ap)
+{
+ vfprintf(stderr, fmt, ap);
+ abort();
+}
+
+void pni_fatal(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ pni_vfatal(fmt, ap);
+ va_end(ap);
+}
+
+/* Allow for systems that do not implement clock_gettime()*/
+#ifdef USE_CLOCK_GETTIME
+#include <time.h>
+pn_timestamp_t pn_i_now(void)
+{
+ struct timespec now;
+ if (clock_gettime(CLOCK_REALTIME, &now)) pni_fatal("clock_gettime() failed\n");
+ return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_nsec / 1000000);
+}
+#elif defined(USE_WIN_FILETIME)
+#include <windows.h>
+pn_timestamp_t pn_i_now(void)
+{
+ FILETIME now;
+ GetSystemTimeAsFileTime(&now);
+ ULARGE_INTEGER t;
+ t.u.HighPart = now.dwHighDateTime;
+ t.u.LowPart = now.dwLowDateTime;
+ // Convert to milliseconds and adjust base epoch
+ return t.QuadPart / 10000 - 11644473600000;
+}
+#else
+#include <sys/time.h>
+pn_timestamp_t pn_i_now(void)
+{
+ struct timeval now;
+ if (gettimeofday(&now, NULL)) pni_fatal("gettimeofday failed\n");
+ return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000);
+}
+#endif
+
+#include <string.h>
+#include <stdio.h>
+static void pn_i_strerror(int errnum, char *buf, size_t buflen)
+{
+ // PROTON-1029 provide a simple default in case strerror fails
+ pni_snprintf(buf, buflen, "errno: %d", errnum);
+#ifdef USE_STRERROR_R
+ strerror_r(errnum, buf, buflen);
+#elif USE_STRERROR_S
+ strerror_s(buf, buflen, errnum);
+#elif USE_OLD_STRERROR
+ strncpy(buf, strerror(errnum), buflen);
+#endif
+}
+
+int pn_i_error_from_errno(pn_error_t *error, const char *msg)
+{
+ char err[1024];
+ pn_i_strerror(errno, err, 1024);
+ int code = PN_ERR;
+ if (errno == EINTR)
+ code = PN_INTR;
+ return pn_error_format(error, code, "%s: %s", msg, err);
+}
+
+#ifdef USE_ATOLL
+#include <stdlib.h>
+int64_t pn_i_atoll(const char* num) {
+ return atoll(num);
+}
+#elif USE_ATOI64
+#include <stdlib.h>
+int64_t pn_i_atoll(const char* num) {
+ return _atoi64(num);
+}
+#else
+#error "Don't know how to convert int64_t values on this platform"
+#endif
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform/platform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform/platform.h b/proton-c/src/platform/platform.h
new file mode 100644
index 0000000..d846cda
--- /dev/null
+++ b/proton-c/src/platform/platform.h
@@ -0,0 +1,93 @@
+#ifndef PROTON_PLATFORM_H
+#define PROTON_PLATFORM_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/types.h"
+#include "proton/error.h"
+
+/** Get the current PID
+ *
+ * @return process id
+ * @internal
+ */
+int pn_i_getpid(void);
+
+
+/** Get the current time in pn_timestamp_t format.
+ *
+ * Returns current time in milliseconds since Unix Epoch,
+ * as defined by AMQP 1.0
+ *
+ * @return current time
+ * @internal
+ */
+pn_timestamp_t pn_i_now(void);
+
+/** Generate system error message.
+ *
+ * Populate the proton error structure based on the last system error
+ * code.
+ *
+ * @param[in] error the proton error structure
+ * @param[in] msg the descriptive context message
+ * @return error->code
+ *
+ * @internal
+ */
+int pn_i_error_from_errno(pn_error_t *error, const char *msg);
+
+/** Provide C99 atoll functinality.
+ *
+ * @param[in] num the string representation of the number.
+ * @return the integer value.
+ *
+ * @internal
+ */
+int64_t pn_i_atoll(const char* num);
+
+int pni_snprintf(char *buf, size_t count, const char *fmt, ...);
+int pni_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap);
+
+#ifndef _MSC_VER
+
+#define pni_snprintf snprintf
+#define pni_vsnprintf vsnprintf
+
+#else
+
+#if !defined(S_ISDIR)
+# define S_ISDIR(X) ((X) & _S_IFDIR)
+#endif
+
+#endif
+
+#if defined _MSC_VER || defined _OPENVMS
+#if !defined(va_copy)
+#define va_copy(d,s) ((d) = (s))
+#endif
+#endif
+
+// Low level pretty rubbish URL parser
+void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path);
+
+#endif /* platform.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform/platform_fmt.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform/platform_fmt.h b/proton-c/src/platform/platform_fmt.h
new file mode 100644
index 0000000..17f95f3
--- /dev/null
+++ b/proton-c/src/platform/platform_fmt.h
@@ -0,0 +1,85 @@
+#ifndef _PROTON_SRC_PLATFORM_FMT_H
+#define _PROTON_SRC_PLATFORM_FMT_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * Platform dependent type-specific format specifiers for PRIx and %z
+ * for use with printf. PRIx defs are normally available in
+ * inttypes.h (C99), but extra steps are required for C++, and they
+ * are not available in Visual Studio at all.
+ * Visual studio uses "%I" for size_t instead of "%z".
+ */
+
+#ifndef __cplusplus
+
+// normal case
+#include <inttypes.h>
+#define PN_ZI "zi"
+#define PN_ZU "zu"
+
+#ifdef _OPENVMS
+
+#undef PN_ZI
+#undef PN_ZU
+#define PN_ZI "i"
+#define PN_ZU "u"
+#define PRIu64 "llu"
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "llu"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "lli"
+
+#endif /* _OPENVMS */
+
+#else
+
+#ifdef _MSC_VER
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "I64u"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "I64i"
+
+#define PN_ZI "Ii"
+#define PN_ZU "Iu"
+#else
+// Normal C++
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#define PN_ZI "zi"
+#define PN_ZU "zu"
+
+#endif /* _MSC_VER */
+
+#endif /* __cplusplus */
+
+#endif /* platform_fmt.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform_fmt.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform_fmt.h b/proton-c/src/platform_fmt.h
deleted file mode 100644
index 17f95f3..0000000
--- a/proton-c/src/platform_fmt.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef _PROTON_SRC_PLATFORM_FMT_H
-#define _PROTON_SRC_PLATFORM_FMT_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/*
- * Platform dependent type-specific format specifiers for PRIx and %z
- * for use with printf. PRIx defs are normally available in
- * inttypes.h (C99), but extra steps are required for C++, and they
- * are not available in Visual Studio at all.
- * Visual studio uses "%I" for size_t instead of "%z".
- */
-
-#ifndef __cplusplus
-
-// normal case
-#include <inttypes.h>
-#define PN_ZI "zi"
-#define PN_ZU "zu"
-
-#ifdef _OPENVMS
-
-#undef PN_ZI
-#undef PN_ZU
-#define PN_ZI "i"
-#define PN_ZU "u"
-#define PRIu64 "llu"
-#define PRIu8 "u"
-#define PRIu16 "u"
-#define PRIu32 "u"
-#define PRIu64 "llu"
-
-#define PRIi8 "i"
-#define PRIi16 "i"
-#define PRIi32 "i"
-#define PRIi64 "lli"
-
-#endif /* _OPENVMS */
-
-#else
-
-#ifdef _MSC_VER
-#define PRIu8 "u"
-#define PRIu16 "u"
-#define PRIu32 "u"
-#define PRIu64 "I64u"
-
-#define PRIi8 "i"
-#define PRIi16 "i"
-#define PRIi32 "i"
-#define PRIi64 "I64i"
-
-#define PN_ZI "Ii"
-#define PN_ZU "Iu"
-#else
-// Normal C++
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#define PN_ZI "zi"
-#define PN_ZU "zu"
-
-#endif /* _MSC_VER */
-
-#endif /* __cplusplus */
-
-#endif /* platform_fmt.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/posix/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/io.c b/proton-c/src/posix/io.c
deleted file mode 100644
index 27d1a35..0000000
--- a/proton-c/src/posix/io.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/io.h>
-#include <proton/object.h>
-#include <proton/selector.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "platform.h"
-
-#define MAX_HOST (1024)
-#define MAX_SERV (64)
-
-struct pn_io_t {
- char host[MAX_HOST];
- char serv[MAX_SERV];
- pn_error_t *error;
- pn_selector_t *selector;
- bool wouldblock;
-};
-
-void pn_io_initialize(void *obj)
-{
- pn_io_t *io = (pn_io_t *) obj;
- io->error = pn_error();
- io->wouldblock = false;
- io->selector = NULL;
-}
-
-void pn_io_finalize(void *obj)
-{
- pn_io_t *io = (pn_io_t *) obj;
- pn_error_free(io->error);
-}
-
-#define pn_io_hashcode NULL
-#define pn_io_compare NULL
-#define pn_io_inspect NULL
-
-pn_io_t *pn_io(void)
-{
- static const pn_class_t clazz = PN_CLASS(pn_io);
- pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
- return io;
-}
-
-void pn_io_free(pn_io_t *io)
-{
- pn_free(io);
-}
-
-pn_error_t *pn_io_error(pn_io_t *io)
-{
- assert(io);
- return io->error;
-}
-
-int pn_pipe(pn_io_t *io, pn_socket_t *dest)
-{
- int n = pipe(dest);
- if (n) {
- pn_i_error_from_errno(io->error, "pipe");
- }
-
- return n;
-}
-
-static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
- // this would be nice, but doesn't appear to exist on linux
- /*
- int set = 1;
- if (!setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int))) {
- pn_i_error_from_errno(io->error, "setsockopt");
- };
- */
-
- int flags = fcntl(sock, F_GETFL);
- flags |= O_NONBLOCK;
-
- if (fcntl(sock, F_SETFL, flags) < 0) {
- pn_i_error_from_errno(io->error, "fcntl");
- }
-
- //
- // Disable the Nagle algorithm on TCP connections.
- //
- // Note: It would be more correct for the "level" argument to be SOL_TCP. However, there
- // are portability issues with this macro so we use IPPROTO_TCP instead.
- //
- int tcp_nodelay = 1;
- if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*) &tcp_nodelay, sizeof(tcp_nodelay)) < 0) {
- pn_i_error_from_errno(io->error, "setsockopt");
- }
-}
-
-static inline int pn_create_socket(int af, int protocol);
-
-pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
-{
- struct addrinfo *addr;
- struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
- int code = getaddrinfo(host, port, &hints, &addr);
- if (code) {
- pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
- return PN_INVALID_SOCKET;
- }
-
- pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
- if (sock == PN_INVALID_SOCKET) {
- freeaddrinfo(addr);
- pn_i_error_from_errno(io->error, "pn_create_socket");
- return PN_INVALID_SOCKET;
- }
-
- int optval = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
- pn_i_error_from_errno(io->error, "setsockopt");
- freeaddrinfo(addr);
- close(sock);
- return PN_INVALID_SOCKET;
- }
-
- if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
- pn_i_error_from_errno(io->error, "bind");
- freeaddrinfo(addr);
- close(sock);
- return PN_INVALID_SOCKET;
- }
-
- freeaddrinfo(addr);
-
- if (listen(sock, 50) == -1) {
- pn_i_error_from_errno(io->error, "listen");
- close(sock);
- return PN_INVALID_SOCKET;
- }
-
- return sock;
-}
-
-pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port)
-{
- struct addrinfo *addr;
- struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
- int code = getaddrinfo(host, port, &hints, &addr);
- if (code) {
- pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
- return PN_INVALID_SOCKET;
- }
-
- pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
- if (sock == PN_INVALID_SOCKET) {
- pn_i_error_from_errno(io->error, "pn_create_socket");
- freeaddrinfo(addr);
- return PN_INVALID_SOCKET;
- }
-
- pn_configure_sock(io, sock);
-
- if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
- if (errno != EINPROGRESS) {
- pn_i_error_from_errno(io->error, "connect");
- freeaddrinfo(addr);
- close(sock);
- return PN_INVALID_SOCKET;
- }
- }
-
- freeaddrinfo(addr);
-
- return sock;
-}
-
-pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size)
-{
- struct sockaddr_storage addr;
- socklen_t addrlen = sizeof(addr);
- *name = '\0';
- pn_socket_t sock = accept(socket, (struct sockaddr *) &addr, &addrlen);
- if (sock == PN_INVALID_SOCKET) {
- pn_i_error_from_errno(io->error, "accept");
- return sock;
- } else {
- int code;
- if ((code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, MAX_HOST, io->serv, MAX_SERV, 0))) {
- pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
- if (close(sock) == -1)
- pn_i_error_from_errno(io->error, "close");
- return PN_INVALID_SOCKET;
- } else {
- pn_configure_sock(io, sock);
- snprintf(name, size, "%s:%s", io->host, io->serv);
- return sock;
- }
- }
-}
-
-/* Abstract away turning off SIGPIPE */
-#ifdef MSG_NOSIGNAL
-ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t len) {
- ssize_t count = send(socket, buf, len, MSG_NOSIGNAL);
- io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
- if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
- return count;
-}
-
-static inline int pn_create_socket(int af, int protocol) {
- return socket(af, SOCK_STREAM, protocol);
-}
-#elif defined(SO_NOSIGPIPE)
-ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
- ssize_t count = send(socket, buf, size, 0);
- io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
- if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
- return count;
-}
-
-static inline int pn_create_socket(int af, int protocol) {
- int sock;
- sock = socket(af, SOCK_STREAM, protocol);
- if (sock == -1) return sock;
-
- int optval = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) == -1) {
- close(sock);
- return -1;
- }
- return sock;
-}
-#else
-
-#include <signal.h>
-
-static inline int pn_create_socket(int af, int protocol) {
- return socket(af, SOCK_STREAM, protocol);
-}
-
-static ssize_t nosigpipe_send(int fd, const void *buffer, size_t size) {
- sigset_t pendingSignals, oldSignals, newSignals;
- ssize_t count;
- int sendErrno, sigmaskErr;
-
- sigpending(&pendingSignals);
- int sigpipeIsPending = sigismember(&pendingSignals, SIGPIPE);
- if (!sigpipeIsPending) {
- sigemptyset(&newSignals);
- sigaddset(&newSignals, SIGPIPE);
- if (sigmaskErr = pthread_sigmask(SIG_BLOCK, (const sigset_t *)&newSignals, (sigset_t *)&oldSignals))
- {
- errno = sigmaskErr;
- return -1;
- }
- }
-
- count = send(fd, buffer, size, 0);
- if (!sigpipeIsPending) {
- sendErrno = errno;
- if (count == -1 && errno == EPIPE) {
- while (-1 == sigtimedwait(&newSignals, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
- ; //do nothing
- }
- if (sigmaskErr = pthread_sigmask(SIG_SETMASK, (const sigset_t *)&oldSignals, (sigset_t *)NULL))
- {
- errno = sigmaskErr;
- return -1;
- }
- errno = sendErrno;
- }
- return count;
-}
-
-ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
- ssize_t count = nosigpipe_send(socket, buf, size);
- io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
- if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
- return count;
-}
-#endif
-
-ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
- ssize_t count = recv(socket, buf, size, 0);
- io->wouldblock = count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK);
- if (count < 0) { pn_i_error_from_errno(io->error, "recv"); }
- return count;
-}
-
-ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
-{
- return write(socket, buf, size);
-}
-
-ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
- return read(socket, buf, size);
-}
-
-void pn_close(pn_io_t *io, pn_socket_t socket)
-{
- close(socket);
-}
-
-bool pn_wouldblock(pn_io_t *io)
-{
- return io->wouldblock;
-}
-
-pn_selector_t *pn_io_selector(pn_io_t *io)
-{
- if (io->selector == NULL)
- io->selector = pni_selector();
- return io->selector;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/posix/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/selector.c b/proton-c/src/posix/selector.c
deleted file mode 100644
index 7f72c84..0000000
--- a/proton-c/src/posix/selector.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/selector.h>
-#include <proton/error.h>
-#include <poll.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "platform.h"
-#include "selectable.h"
-#include "util.h"
-
-struct pn_selector_t {
- struct pollfd *fds;
- pn_timestamp_t *deadlines;
- size_t capacity;
- pn_list_t *selectables;
- size_t current;
- pn_timestamp_t awoken;
- pn_error_t *error;
-};
-
-void pn_selector_initialize(void *obj)
-{
- pn_selector_t *selector = (pn_selector_t *) obj;
- selector->fds = NULL;
- selector->deadlines = NULL;
- selector->capacity = 0;
- selector->selectables = pn_list(PN_WEAKREF, 0);
- selector->current = 0;
- selector->awoken = 0;
- selector->error = pn_error();
-}
-
-void pn_selector_finalize(void *obj)
-{
- pn_selector_t *selector = (pn_selector_t *) obj;
- free(selector->fds);
- free(selector->deadlines);
- pn_free(selector->selectables);
- pn_error_free(selector->error);
-}
-
-#define pn_selector_hashcode NULL
-#define pn_selector_compare NULL
-#define pn_selector_inspect NULL
-
-pn_selector_t *pni_selector(void)
-{
- static const pn_class_t clazz = PN_CLASS(pn_selector);
- pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
- return selector;
-}
-
-void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
-{
- assert(selector);
- assert(selectable);
- assert(pni_selectable_get_index(selectable) < 0);
-
- if (pni_selectable_get_index(selectable) < 0) {
- pn_list_add(selector->selectables, selectable);
- size_t size = pn_list_size(selector->selectables);
-
- if (selector->capacity < size) {
- selector->fds = (struct pollfd *) realloc(selector->fds, size*sizeof(struct pollfd));
- selector->deadlines = (pn_timestamp_t *) realloc(selector->deadlines, size*sizeof(pn_timestamp_t));
- selector->capacity = size;
- }
-
- pni_selectable_set_index(selectable, size - 1);
- }
-
- pn_selector_update(selector, selectable);
-}
-
-void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
-{
- int idx = pni_selectable_get_index(selectable);
- assert(idx >= 0);
- selector->fds[idx].fd = pn_selectable_get_fd(selectable);
- selector->fds[idx].events = 0;
- selector->fds[idx].revents = 0;
- if (pn_selectable_is_reading(selectable)) {
- selector->fds[idx].events |= POLLIN;
- }
- if (pn_selectable_is_writing(selectable)) {
- selector->fds[idx].events |= POLLOUT;
- }
- selector->deadlines[idx] = pn_selectable_get_deadline(selectable);
-}
-
-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);
- pn_list_del(selector->selectables, 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);
- selector->fds[i] = selector->fds[i + 1];
- }
-
- pni_selectable_set_index(selectable, -1);
-
- if (selector->current >= (size_t) idx) {
- selector->current--;
- }
-}
-
-size_t pn_selector_size(pn_selector_t *selector) {
- assert(selector);
- return pn_list_size(selector->selectables);
-}
-
-int pn_selector_select(pn_selector_t *selector, int timeout)
-{
- assert(selector);
-
- size_t size = pn_list_size(selector->selectables);
-
- if (timeout) {
- pn_timestamp_t deadline = 0;
- for (size_t i = 0; i < size; i++) {
- pn_timestamp_t d = selector->deadlines[i];
- if (d)
- deadline = (deadline == 0) ? d : pn_min(deadline, d);
- }
-
- if (deadline) {
- pn_timestamp_t now = pn_i_now();
- int64_t delta = deadline - now;
- if (delta < 0) {
- timeout = 0;
- } else if (delta < timeout) {
- timeout = delta;
- }
- }
- }
-
- int error = 0;
- int result = poll(selector->fds, size, timeout);
- if (result == -1) {
- error = pn_i_error_from_errno(selector->error, "poll");
- } else {
- selector->current = 0;
- selector->awoken = pn_i_now();
- }
-
- return error;
-}
-
-pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
-{
- pn_list_t *l = selector->selectables;
- size_t size = pn_list_size(l);
- while (selector->current < size) {
- pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(l, selector->current);
- struct pollfd *pfd = &selector->fds[selector->current];
- pn_timestamp_t deadline = selector->deadlines[selector->current];
- int ev = 0;
- if (pfd->revents & POLLIN) {
- ev |= PN_READABLE;
- }
- if ((pfd->revents & POLLERR) ||
- (pfd->revents & POLLHUP) ||
- (pfd->revents & POLLNVAL)) {
- ev |= PN_ERROR;
- }
- if (pfd->revents & POLLOUT) {
- ev |= PN_WRITABLE;
- }
- if (deadline && selector->awoken >= deadline) {
- ev |= PN_EXPIRED;
- }
- selector->current++;
- if (ev) {
- *events = ev;
- return sel;
- }
- }
- return NULL;
-}
-
-void pn_selector_free(pn_selector_t *selector)
-{
- assert(selector);
- pn_free(selector);
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/acceptor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/acceptor.c b/proton-c/src/reactor/acceptor.c
index f56f7bd..a044748 100644
--- a/proton-c/src/reactor/acceptor.c
+++ b/proton-c/src/reactor/acceptor.c
@@ -19,13 +19,14 @@
*
*/
-#include <proton/io.h>
#include <proton/sasl.h>
-#include <proton/selector.h>
#include <proton/transport.h>
#include <proton/connection.h>
+
+#include "io.h"
#include "reactor.h"
#include "selectable.h"
+#include "selector.h"
#include <string.h>
@@ -38,7 +39,7 @@ PN_HANDLE(PNI_ACCEPTOR_CONNECTION)
void pni_acceptor_readable(pn_selectable_t *sel) {
pn_reactor_t *reactor = (pn_reactor_t *) pni_selectable_get_context(sel);
char name[1024];
- pn_socket_t sock = pn_accept(pn_reactor_io(reactor), pn_selectable_get_fd(sel), name, 1024);
+ pn_socket_t sock = pn_accept(pni_reactor_io(reactor), pn_selectable_get_fd(sel), name, 1024);
pn_handler_t *handler = (pn_handler_t *) pn_record_get(pn_selectable_attachments(sel), PNI_ACCEPTOR_HANDLER);
if (!handler) { handler = pn_reactor_get_handler(reactor); }
pn_record_t *record = pn_selectable_attachments(sel);
@@ -67,12 +68,12 @@ void pni_acceptor_readable(pn_selectable_t *sel) {
void pni_acceptor_finalize(pn_selectable_t *sel) {
pn_reactor_t *reactor = (pn_reactor_t *) pni_selectable_get_context(sel);
if (pn_selectable_get_fd(sel) != PN_INVALID_SOCKET) {
- pn_close(pn_reactor_io(reactor), pn_selectable_get_fd(sel));
+ pn_close(pni_reactor_io(reactor), pn_selectable_get_fd(sel));
}
}
pn_acceptor_t *pn_reactor_acceptor(pn_reactor_t *reactor, const char *host, const char *port, pn_handler_t *handler) {
- pn_socket_t socket = pn_listen(pn_reactor_io(reactor), host, port);
+ pn_socket_t socket = pn_listen(pni_reactor_io(reactor), host, port);
if (socket == PN_INVALID_SOCKET) {
return NULL;
}
@@ -94,7 +95,7 @@ void pn_acceptor_close(pn_acceptor_t *acceptor) {
if (!pn_selectable_is_terminal(sel)) {
pn_reactor_t *reactor = (pn_reactor_t *) pni_selectable_get_context(sel);
pn_socket_t socket = pn_selectable_get_fd(sel);
- pn_close(pn_reactor_io(reactor), socket);
+ pn_close(pni_reactor_io(reactor), socket);
pn_selectable_set_fd(sel, PN_INVALID_SOCKET);
pn_selectable_terminate(sel);
pn_reactor_update(reactor, sel);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/connection.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/connection.c b/proton-c/src/reactor/connection.c
index d73e386..4bc8b8d 100644
--- a/proton-c/src/reactor/connection.c
+++ b/proton-c/src/reactor/connection.c
@@ -28,6 +28,7 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
+#include "io.h"
#include "selectable.h"
#include "reactor.h"
@@ -187,12 +188,12 @@ void pni_handle_bound(pn_reactor_t *reactor, pn_event_t *event) {
pn_transport_close_tail(transport);
pn_transport_close_head(transport);
} else {
- pn_socket_t sock = pn_connect(pn_reactor_io(reactor), host, port);
+ pn_socket_t sock = pn_connect(pni_reactor_io(reactor), host, port);
// invalid sockets are ignored by poll, so we need to do this manualy
if (sock == PN_INVALID_SOCKET) {
pn_condition_t *cond = pn_transport_condition(transport);
pn_condition_set_name(cond, "proton:io");
- pn_condition_set_description(cond, pn_error_text(pn_io_error(pn_reactor_io(reactor))));
+ pn_condition_set_description(cond, pn_error_text(pn_reactor_error(reactor)));
pn_transport_close_tail(transport);
pn_transport_close_head(transport);
} else {
@@ -215,14 +216,14 @@ static void pni_connection_readable(pn_selectable_t *sel)
pn_transport_t *transport = pni_transport(sel);
ssize_t capacity = pn_transport_capacity(transport);
if (capacity > 0) {
- ssize_t n = pn_recv(pn_reactor_io(reactor), pn_selectable_get_fd(sel),
+ ssize_t n = pn_recv(pni_reactor_io(reactor), pn_selectable_get_fd(sel),
pn_transport_tail(transport), capacity);
if (n <= 0) {
- if (n == 0 || !pn_wouldblock(pn_reactor_io(reactor))) {
+ if (n == 0 || !pn_wouldblock(pni_reactor_io(reactor))) {
if (n < 0) {
pn_condition_t *cond = pn_transport_condition(transport);
pn_condition_set_name(cond, "proton:io");
- pn_condition_set_description(cond, pn_error_text(pn_io_error(pn_reactor_io(reactor))));
+ pn_condition_set_description(cond, pn_error_text(pn_reactor_error(reactor)));
}
pn_transport_close_tail(transport);
}
@@ -246,14 +247,14 @@ static void pni_connection_writable(pn_selectable_t *sel)
pn_transport_t *transport = pni_transport(sel);
ssize_t pending = pn_transport_pending(transport);
if (pending > 0) {
- ssize_t n = pn_send(pn_reactor_io(reactor), pn_selectable_get_fd(sel),
+ ssize_t n = pn_send(pni_reactor_io(reactor), pn_selectable_get_fd(sel),
pn_transport_head(transport), pending);
if (n < 0) {
- if (!pn_wouldblock(pn_reactor_io(reactor))) {
+ if (!pn_wouldblock(pni_reactor_io(reactor))) {
pn_condition_t *cond = pn_transport_condition(transport);
if (!pn_condition_is_set(cond)) {
pn_condition_set_name(cond, "proton:io");
- pn_condition_set_description(cond, pn_error_text(pn_io_error(pn_reactor_io(reactor))));
+ pn_condition_set_description(cond, pn_error_text(pn_reactor_error(reactor)));
}
pn_transport_close_head(transport);
}
@@ -296,7 +297,7 @@ static void pni_connection_finalize(pn_selectable_t *sel) {
pn_record_t *record = pn_transport_attachments(transport);
pn_record_set(record, PN_TRANCTX, NULL);
pn_socket_t fd = pn_selectable_get_fd(sel);
- pn_close(pn_reactor_io(reactor), fd);
+ pn_close(pni_reactor_io(reactor), fd);
}
pn_selectable_t *pn_reactor_selectable_transport(pn_reactor_t *reactor, pn_socket_t sock, pn_transport_t *transport) {
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io.h b/proton-c/src/reactor/io.h
new file mode 100644
index 0000000..24596ec
--- /dev/null
+++ b/proton-c/src/reactor/io.h
@@ -0,0 +1,70 @@
+#ifndef PROTON_IO_H
+#define PROTON_IO_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "selector.h"
+
+#include <proton/import_export.h>
+#include <proton/error.h>
+#include <proton/type_compat.h>
+#include <stddef.h>
+
+/**
+ * A ::pn_io_t manages IO for a group of pn_socket_t handles. A
+ * pn_io_t object may have zero or one pn_selector_t selectors
+ * associated with it (see ::pn_io_selector()). If one is associated,
+ * all the pn_socket_t handles managed by a pn_io_t must use that
+ * pn_selector_t instance.
+ *
+ * The pn_io_t interface is single-threaded. All methods are intended
+ * to be used by one thread at a time, except that multiple threads
+ * may use:
+ *
+ * ::pn_write()
+ * ::pn_send()
+ * ::pn_recv()
+ * ::pn_close()
+ * ::pn_selector_select()
+ *
+ * provided at most one thread is calling ::pn_selector_select() and
+ * the other threads are operating on separate pn_socket_t handles.
+ */
+typedef struct pn_io_t pn_io_t;
+
+pn_io_t *pn_io(void);
+void pn_io_free(pn_io_t *io);
+pn_error_t *pn_io_error(pn_io_t *io);
+pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port);
+pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port);
+
+pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size);
+void pn_close(pn_io_t *io, pn_socket_t socket);
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
+ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
+int pn_pipe(pn_io_t *io, pn_socket_t *dest);
+ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
+ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
+bool pn_wouldblock(pn_io_t *io);
+pn_selector_t *pn_io_selector(pn_io_t *io);
+
+#endif /* io.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/posix/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/posix/io.c b/proton-c/src/reactor/io/posix/io.c
new file mode 100644
index 0000000..5a0de3b
--- /dev/null
+++ b/proton-c/src/reactor/io/posix/io.c
@@ -0,0 +1,342 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "reactor/io.h"
+#include "reactor/selector.h"
+#include "platform/platform.h" // pn_i_error_from_errno
+
+#include <proton/object.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define MAX_HOST (1024)
+#define MAX_SERV (64)
+
+struct pn_io_t {
+ char host[MAX_HOST];
+ char serv[MAX_SERV];
+ pn_error_t *error;
+ pn_selector_t *selector;
+ bool wouldblock;
+};
+
+void pn_io_initialize(void *obj)
+{
+ pn_io_t *io = (pn_io_t *) obj;
+ io->error = pn_error();
+ io->wouldblock = false;
+ io->selector = NULL;
+}
+
+void pn_io_finalize(void *obj)
+{
+ pn_io_t *io = (pn_io_t *) obj;
+ pn_error_free(io->error);
+}
+
+#define pn_io_hashcode NULL
+#define pn_io_compare NULL
+#define pn_io_inspect NULL
+
+pn_io_t *pn_io(void)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_io);
+ pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
+ return io;
+}
+
+void pn_io_free(pn_io_t *io)
+{
+ pn_free(io);
+}
+
+pn_error_t *pn_io_error(pn_io_t *io)
+{
+ assert(io);
+ return io->error;
+}
+
+int pn_pipe(pn_io_t *io, pn_socket_t *dest)
+{
+ int n = pipe(dest);
+ if (n) {
+ pn_i_error_from_errno(io->error, "pipe");
+ }
+
+ return n;
+}
+
+static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
+ // this would be nice, but doesn't appear to exist on linux
+ /*
+ int set = 1;
+ if (!setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int))) {
+ pn_i_error_from_errno(io->error, "setsockopt");
+ };
+ */
+
+ int flags = fcntl(sock, F_GETFL);
+ flags |= O_NONBLOCK;
+
+ if (fcntl(sock, F_SETFL, flags) < 0) {
+ pn_i_error_from_errno(io->error, "fcntl");
+ }
+
+ //
+ // Disable the Nagle algorithm on TCP connections.
+ //
+ // Note: It would be more correct for the "level" argument to be SOL_TCP. However, there
+ // are portability issues with this macro so we use IPPROTO_TCP instead.
+ //
+ int tcp_nodelay = 1;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*) &tcp_nodelay, sizeof(tcp_nodelay)) < 0) {
+ pn_i_error_from_errno(io->error, "setsockopt");
+ }
+}
+
+static inline int pn_create_socket(int af, int protocol);
+
+pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
+{
+ struct addrinfo *addr;
+ struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
+ int code = getaddrinfo(host, port, &hints, &addr);
+ if (code) {
+ pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
+ return PN_INVALID_SOCKET;
+ }
+
+ pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
+ if (sock == PN_INVALID_SOCKET) {
+ freeaddrinfo(addr);
+ pn_i_error_from_errno(io->error, "pn_create_socket");
+ return PN_INVALID_SOCKET;
+ }
+
+ int optval = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
+ pn_i_error_from_errno(io->error, "setsockopt");
+ freeaddrinfo(addr);
+ close(sock);
+ return PN_INVALID_SOCKET;
+ }
+
+ if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
+ pn_i_error_from_errno(io->error, "bind");
+ freeaddrinfo(addr);
+ close(sock);
+ return PN_INVALID_SOCKET;
+ }
+
+ freeaddrinfo(addr);
+
+ if (listen(sock, 50) == -1) {
+ pn_i_error_from_errno(io->error, "listen");
+ close(sock);
+ return PN_INVALID_SOCKET;
+ }
+
+ return sock;
+}
+
+pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port)
+{
+ struct addrinfo *addr;
+ struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
+ int code = getaddrinfo(host, port, &hints, &addr);
+ if (code) {
+ pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
+ return PN_INVALID_SOCKET;
+ }
+
+ pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
+ if (sock == PN_INVALID_SOCKET) {
+ pn_i_error_from_errno(io->error, "pn_create_socket");
+ freeaddrinfo(addr);
+ return PN_INVALID_SOCKET;
+ }
+
+ pn_configure_sock(io, sock);
+
+ if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
+ if (errno != EINPROGRESS) {
+ pn_i_error_from_errno(io->error, "connect");
+ freeaddrinfo(addr);
+ close(sock);
+ return PN_INVALID_SOCKET;
+ }
+ }
+
+ freeaddrinfo(addr);
+
+ return sock;
+}
+
+pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ *name = '\0';
+ pn_socket_t sock = accept(socket, (struct sockaddr *) &addr, &addrlen);
+ if (sock == PN_INVALID_SOCKET) {
+ pn_i_error_from_errno(io->error, "accept");
+ return sock;
+ } else {
+ int code;
+ if ((code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, MAX_HOST, io->serv, MAX_SERV, 0))) {
+ pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
+ if (close(sock) == -1)
+ pn_i_error_from_errno(io->error, "close");
+ return PN_INVALID_SOCKET;
+ } else {
+ pn_configure_sock(io, sock);
+ pni_snprintf(name, size, "%s:%s", io->host, io->serv);
+ return sock;
+ }
+ }
+}
+
+/* Abstract away turning off SIGPIPE */
+#ifdef MSG_NOSIGNAL
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t len) {
+ ssize_t count = send(socket, buf, len, MSG_NOSIGNAL);
+ io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
+ if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
+ return count;
+}
+
+static inline int pn_create_socket(int af, int protocol) {
+ return socket(af, SOCK_STREAM, protocol);
+}
+#elif defined(SO_NOSIGPIPE)
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
+ ssize_t count = send(socket, buf, size, 0);
+ io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
+ if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
+ return count;
+}
+
+static inline int pn_create_socket(int af, int protocol) {
+ int sock;
+ sock = socket(af, SOCK_STREAM, protocol);
+ if (sock == -1) return sock;
+
+ int optval = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) == -1) {
+ close(sock);
+ return -1;
+ }
+ return sock;
+}
+#else
+
+#include <signal.h>
+
+static inline int pn_create_socket(int af, int protocol) {
+ return socket(af, SOCK_STREAM, protocol);
+}
+
+static ssize_t nosigpipe_send(int fd, const void *buffer, size_t size) {
+ sigset_t pendingSignals, oldSignals, newSignals;
+ ssize_t count;
+ int sendErrno, sigmaskErr;
+
+ sigpending(&pendingSignals);
+ int sigpipeIsPending = sigismember(&pendingSignals, SIGPIPE);
+ if (!sigpipeIsPending) {
+ sigemptyset(&newSignals);
+ sigaddset(&newSignals, SIGPIPE);
+ if (sigmaskErr = pthread_sigmask(SIG_BLOCK, (const sigset_t *)&newSignals, (sigset_t *)&oldSignals))
+ {
+ errno = sigmaskErr;
+ return -1;
+ }
+ }
+
+ count = send(fd, buffer, size, 0);
+ if (!sigpipeIsPending) {
+ sendErrno = errno;
+ if (count == -1 && errno == EPIPE) {
+ while (-1 == sigtimedwait(&newSignals, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
+ ; //do nothing
+ }
+ if (sigmaskErr = pthread_sigmask(SIG_SETMASK, (const sigset_t *)&oldSignals, (sigset_t *)NULL))
+ {
+ errno = sigmaskErr;
+ return -1;
+ }
+ errno = sendErrno;
+ }
+ return count;
+}
+
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
+ ssize_t count = nosigpipe_send(socket, buf, size);
+ io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
+ if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
+ return count;
+}
+#endif
+
+ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+ ssize_t count = recv(socket, buf, size, 0);
+ io->wouldblock = count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK);
+ if (count < 0) { pn_i_error_from_errno(io->error, "recv"); }
+ return count;
+}
+
+ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
+{
+ return write(socket, buf, size);
+}
+
+ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+ return read(socket, buf, size);
+}
+
+void pn_close(pn_io_t *io, pn_socket_t socket)
+{
+ close(socket);
+}
+
+bool pn_wouldblock(pn_io_t *io)
+{
+ return io->wouldblock;
+}
+
+pn_selector_t *pn_io_selector(pn_io_t *io)
+{
+ if (io->selector == NULL)
+ io->selector = pni_selector();
+ return io->selector;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/posix/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/posix/selector.c b/proton-c/src/reactor/io/posix/selector.c
new file mode 100644
index 0000000..bf6882a
--- /dev/null
+++ b/proton-c/src/reactor/io/posix/selector.c
@@ -0,0 +1,214 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "core/util.h"
+#include "platform/platform.h" // pn_i_now, pn_i_error_from_errno
+#include "reactor/io.h"
+#include "reactor/selector.h"
+#include "reactor/selectable.h"
+
+#include <proton/error.h>
+
+#include <poll.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_selector_t {
+ struct pollfd *fds;
+ pn_timestamp_t *deadlines;
+ size_t capacity;
+ pn_list_t *selectables;
+ size_t current;
+ pn_timestamp_t awoken;
+ pn_error_t *error;
+};
+
+void pn_selector_initialize(void *obj)
+{
+ pn_selector_t *selector = (pn_selector_t *) obj;
+ selector->fds = NULL;
+ selector->deadlines = NULL;
+ selector->capacity = 0;
+ selector->selectables = pn_list(PN_WEAKREF, 0);
+ selector->current = 0;
+ selector->awoken = 0;
+ selector->error = pn_error();
+}
+
+void pn_selector_finalize(void *obj)
+{
+ pn_selector_t *selector = (pn_selector_t *) obj;
+ free(selector->fds);
+ free(selector->deadlines);
+ pn_free(selector->selectables);
+ pn_error_free(selector->error);
+}
+
+#define pn_selector_hashcode NULL
+#define pn_selector_compare NULL
+#define pn_selector_inspect NULL
+
+pn_selector_t *pni_selector(void)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_selector);
+ pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
+ return selector;
+}
+
+void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+ assert(selector);
+ assert(selectable);
+ assert(pni_selectable_get_index(selectable) < 0);
+
+ if (pni_selectable_get_index(selectable) < 0) {
+ pn_list_add(selector->selectables, selectable);
+ size_t size = pn_list_size(selector->selectables);
+
+ if (selector->capacity < size) {
+ selector->fds = (struct pollfd *) realloc(selector->fds, size*sizeof(struct pollfd));
+ selector->deadlines = (pn_timestamp_t *) realloc(selector->deadlines, size*sizeof(pn_timestamp_t));
+ selector->capacity = size;
+ }
+
+ pni_selectable_set_index(selectable, size - 1);
+ }
+
+ pn_selector_update(selector, selectable);
+}
+
+void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+ int idx = pni_selectable_get_index(selectable);
+ assert(idx >= 0);
+ selector->fds[idx].fd = pn_selectable_get_fd(selectable);
+ selector->fds[idx].events = 0;
+ selector->fds[idx].revents = 0;
+ if (pn_selectable_is_reading(selectable)) {
+ selector->fds[idx].events |= POLLIN;
+ }
+ if (pn_selectable_is_writing(selectable)) {
+ selector->fds[idx].events |= POLLOUT;
+ }
+ selector->deadlines[idx] = pn_selectable_get_deadline(selectable);
+}
+
+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);
+ pn_list_del(selector->selectables, 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);
+ selector->fds[i] = selector->fds[i + 1];
+ }
+
+ pni_selectable_set_index(selectable, -1);
+
+ if (selector->current >= (size_t) idx) {
+ selector->current--;
+ }
+}
+
+size_t pn_selector_size(pn_selector_t *selector) {
+ assert(selector);
+ return pn_list_size(selector->selectables);
+}
+
+int pn_selector_select(pn_selector_t *selector, int timeout)
+{
+ assert(selector);
+
+ size_t size = pn_list_size(selector->selectables);
+
+ if (timeout) {
+ pn_timestamp_t deadline = 0;
+ for (size_t i = 0; i < size; i++) {
+ pn_timestamp_t d = selector->deadlines[i];
+ if (d)
+ deadline = (deadline == 0) ? d : pn_min(deadline, d);
+ }
+
+ if (deadline) {
+ pn_timestamp_t now = pn_i_now();
+ int64_t delta = deadline - now;
+ if (delta < 0) {
+ timeout = 0;
+ } else if (delta < timeout) {
+ timeout = delta;
+ }
+ }
+ }
+
+ int error = 0;
+ int result = poll(selector->fds, size, timeout);
+ if (result == -1) {
+ error = pn_i_error_from_errno(selector->error, "poll");
+ } else {
+ selector->current = 0;
+ selector->awoken = pn_i_now();
+ }
+
+ return error;
+}
+
+pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
+{
+ pn_list_t *l = selector->selectables;
+ size_t size = pn_list_size(l);
+ while (selector->current < size) {
+ pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(l, selector->current);
+ struct pollfd *pfd = &selector->fds[selector->current];
+ pn_timestamp_t deadline = selector->deadlines[selector->current];
+ int ev = 0;
+ if (pfd->revents & POLLIN) {
+ ev |= PN_READABLE;
+ }
+ if ((pfd->revents & POLLERR) ||
+ (pfd->revents & POLLHUP) ||
+ (pfd->revents & POLLNVAL)) {
+ ev |= PN_ERROR;
+ }
+ if (pfd->revents & POLLOUT) {
+ ev |= PN_WRITABLE;
+ }
+ if (deadline && selector->awoken >= deadline) {
+ ev |= PN_EXPIRED;
+ }
+ selector->current++;
+ if (ev) {
+ *events = ev;
+ return sel;
+ }
+ }
+ return NULL;
+}
+
+void pn_selector_free(pn_selector_t *selector)
+{
+ assert(selector);
+ pn_free(selector);
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[12/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/transport.c b/proton-c/src/core/transport.c
new file mode 100644
index 0000000..e3b88b1
--- /dev/null
+++ b/proton-c/src/core/transport.c
@@ -0,0 +1,3019 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "engine-internal.h"
+#include "framing.h"
+#include "platform/platform.h"
+#include "platform/platform_fmt.h"
+#include "sasl/sasl-internal.h"
+#include "ssl/ssl-internal.h"
+
+#include "autodetect.h"
+#include "protocol.h"
+#include "dispatch_actions.h"
+#include "config.h"
+#include "log_private.h"
+
+#include "proton/event.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+static ssize_t transport_consume(pn_transport_t *transport);
+
+// delivery buffers
+
+/*
+ * Call this any time anything happens that may affect channel_max:
+ * i.e. when the app indicates a preference, or when we receive the
+ * OPEN frame from the remote peer. And call it to do the final
+ * calculation just before we communicate our limit to the remote
+ * peer by sending our OPEN frame.
+ */
+static void pni_calculate_channel_max(pn_transport_t *transport) {
+ /*
+ * The application cannot make the limit larger than
+ * what this library will allow.
+ */
+ transport->channel_max = (PN_IMPL_CHANNEL_MAX < transport->local_channel_max)
+ ? PN_IMPL_CHANNEL_MAX
+ : transport->local_channel_max;
+
+ /*
+ * The remote peer's constraint is not valid until the
+ * peer's open frame has been received.
+ */
+ if(transport->open_rcvd) {
+ transport->channel_max = (transport->channel_max < transport->remote_channel_max)
+ ? transport->channel_max
+ : transport->remote_channel_max;
+ }
+}
+
+void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next)
+{
+ db->deliveries = pn_hash(PN_WEAKREF, 0, 0.75);
+ db->next = next;
+}
+
+void pn_delivery_map_free(pn_delivery_map_t *db)
+{
+ pn_free(db->deliveries);
+}
+
+static pn_delivery_t *pni_delivery_map_get(pn_delivery_map_t *db, pn_sequence_t id)
+{
+ return (pn_delivery_t *) pn_hash_get(db->deliveries, id);
+}
+
+static void pn_delivery_state_init(pn_delivery_state_t *ds, pn_delivery_t *delivery, pn_sequence_t id)
+{
+ ds->id = id;
+ ds->sent = false;
+ ds->init = true;
+}
+
+static pn_delivery_state_t *pni_delivery_map_push(pn_delivery_map_t *db, pn_delivery_t *delivery)
+{
+ pn_delivery_state_t *ds = &delivery->state;
+ pn_delivery_state_init(ds, delivery, db->next++);
+ pn_hash_put(db->deliveries, ds->id, delivery);
+ return ds;
+}
+
+void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery)
+{
+ if (delivery->state.init) {
+ delivery->state.init = false;
+ delivery->state.sent = false;
+ pn_hash_del(db->deliveries, delivery->state.id);
+ }
+}
+
+static void pni_delivery_map_clear(pn_delivery_map_t *dm)
+{
+ pn_hash_t *hash = dm->deliveries;
+ for (pn_handle_t entry = pn_hash_head(hash);
+ entry;
+ entry = pn_hash_next(hash, entry))
+ {
+ pn_delivery_t *dlv = (pn_delivery_t *) pn_hash_value(hash, entry);
+ pn_delivery_map_del(dm, dlv);
+ }
+ dm->next = 0;
+}
+
+static void pni_default_tracer(pn_transport_t *transport, const char *message)
+{
+ fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
+}
+
+static ssize_t pn_io_layer_input_passthru(pn_transport_t *, unsigned int, const char *, size_t );
+static ssize_t pn_io_layer_output_passthru(pn_transport_t *, unsigned int, char *, size_t );
+
+static ssize_t pn_io_layer_input_error(pn_transport_t *, unsigned int, const char *, size_t );
+static ssize_t pn_io_layer_output_error(pn_transport_t *, unsigned int, char *, size_t );
+
+static ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+
+static ssize_t pn_input_read_amqp_header(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_input_read_amqp(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_output_write_amqp_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+static ssize_t pn_output_write_amqp(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+static void pn_error_amqp(pn_transport_t *transport, unsigned int layer);
+static pn_timestamp_t pn_tick_amqp(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now);
+
+static ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+
+const pn_io_layer_t amqp_header_layer = {
+ pn_input_read_amqp_header,
+ pn_output_write_amqp_header,
+ NULL,
+ pn_tick_amqp,
+ NULL
+};
+
+const pn_io_layer_t amqp_write_header_layer = {
+ pn_input_read_amqp,
+ pn_output_write_amqp_header,
+ NULL,
+ pn_tick_amqp,
+ NULL
+};
+
+const pn_io_layer_t amqp_read_header_layer = {
+ pn_input_read_amqp_header,
+ pn_output_write_amqp,
+ pn_error_amqp,
+ pn_tick_amqp,
+ NULL
+};
+
+const pn_io_layer_t amqp_layer = {
+ pn_input_read_amqp,
+ pn_output_write_amqp,
+ pn_error_amqp,
+ pn_tick_amqp,
+ NULL
+};
+
+const pn_io_layer_t pni_setup_layer = {
+ pn_io_layer_input_setup,
+ pn_io_layer_output_setup,
+ NULL,
+ NULL,
+ NULL
+};
+
+const pn_io_layer_t pni_autodetect_layer = {
+ pn_io_layer_input_autodetect,
+ pn_io_layer_output_null,
+ NULL,
+ NULL,
+ NULL
+};
+
+const pn_io_layer_t pni_passthru_layer = {
+ pn_io_layer_input_passthru,
+ pn_io_layer_output_passthru,
+ NULL,
+ NULL,
+ NULL
+};
+
+const pn_io_layer_t pni_header_error_layer = {
+ pn_io_layer_input_error,
+ pn_output_write_amqp_header,
+ NULL,
+ NULL,
+ NULL
+};
+
+const pn_io_layer_t pni_error_layer = {
+ pn_io_layer_input_error,
+ pn_io_layer_output_error,
+ pn_error_amqp,
+ NULL,
+ NULL
+};
+
+/* Set up the transport protocol layers depending on what is configured */
+static void pn_io_layer_setup(pn_transport_t *transport, unsigned int layer)
+{
+ assert(layer == 0);
+ // Figure out if we are server or not
+ if (transport->server) {
+ transport->io_layers[layer++] = &pni_autodetect_layer;
+ return;
+ }
+ if (transport->ssl) {
+ transport->io_layers[layer++] = &ssl_layer;
+ }
+ if (transport->sasl) {
+ transport->io_layers[layer++] = &sasl_header_layer;
+ }
+ transport->io_layers[layer++] = &amqp_header_layer;
+}
+
+ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
+{
+ pn_io_layer_setup(transport, layer);
+ return transport->io_layers[layer]->process_input(transport, layer, bytes, available);
+}
+
+ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
+{
+ pn_io_layer_setup(transport, layer);
+ return transport->io_layers[layer]->process_output(transport, layer, bytes, available);
+}
+
+void pn_set_error_layer(pn_transport_t *transport)
+{
+ // Set every layer to the error layer in case we manually
+ // pass through (happens from SASL to AMQP)
+ for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
+ transport->io_layers[layer] = &pni_error_layer;
+ }
+}
+
+// Autodetect the layer by reading the protocol header
+ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
+{
+ const char* error;
+ bool eos = pn_transport_capacity(transport)==PN_EOS;
+ if (eos && available==0) {
+ pn_do_error(transport, "amqp:connection:framing-error", "No valid protocol header found");
+ pn_set_error_layer(transport);
+ return PN_EOS;
+ }
+ pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
+ if (transport->trace & PN_TRACE_DRV)
+ pn_transport_logf(transport, "%s detected", pni_protocol_name(protocol));
+ switch (protocol) {
+ case PNI_PROTOCOL_SSL:
+ if (!(transport->allowed_layers & LAYER_SSL)) {
+ error = "SSL protocol header not allowed (maybe detected twice)";
+ break;
+ }
+ transport->present_layers |= LAYER_SSL;
+ transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
+ if (!transport->ssl) {
+ pn_ssl(transport);
+ }
+ transport->io_layers[layer] = &ssl_layer;
+ transport->io_layers[layer+1] = &pni_autodetect_layer;
+ return ssl_layer.process_input(transport, layer, bytes, available);
+ case PNI_PROTOCOL_AMQP_SSL:
+ if (!(transport->allowed_layers & LAYER_AMQPSSL)) {
+ error = "AMQP SSL protocol header not allowed (maybe detected twice)";
+ break;
+ }
+ transport->present_layers |= LAYER_AMQPSSL;
+ transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
+ if (!transport->ssl) {
+ pn_ssl(transport);
+ }
+ transport->io_layers[layer] = &ssl_layer;
+ transport->io_layers[layer+1] = &pni_autodetect_layer;
+ return 8;
+ case PNI_PROTOCOL_AMQP_SASL:
+ if (!(transport->allowed_layers & LAYER_AMQPSASL)) {
+ error = "AMQP SASL protocol header not allowed (maybe detected twice)";
+ break;
+ }
+ transport->present_layers |= LAYER_AMQPSASL;
+ transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSSL;
+ if (!transport->sasl) {
+ pn_sasl(transport);
+ }
+ transport->io_layers[layer] = &sasl_write_header_layer;
+ transport->io_layers[layer+1] = &pni_autodetect_layer;
+ if (transport->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, " <- %s", "SASL");
+ pni_sasl_set_external_security(transport, pn_ssl_get_ssf((pn_ssl_t*)transport), pn_ssl_get_remote_subject((pn_ssl_t*)transport));
+ return 8;
+ case PNI_PROTOCOL_AMQP1:
+ if (!(transport->allowed_layers & LAYER_AMQP1)) {
+ error = "AMQP1.0 protocol header not allowed (maybe detected twice)";
+ break;
+ }
+ transport->present_layers |= LAYER_AMQP1;
+ transport->allowed_layers = LAYER_NONE;
+ if (transport->auth_required && !pn_transport_is_authenticated(transport)) {
+ pn_do_error(transport, "amqp:connection:policy-error",
+ "Client skipped authentication - forbidden");
+ pn_set_error_layer(transport);
+ return 8;
+ }
+ if (transport->encryption_required && !pn_transport_is_encrypted(transport)) {
+ pn_do_error(transport, "amqp:connection:policy-error",
+ "Client connection unencryted - forbidden");
+ pn_set_error_layer(transport);
+ return 8;
+ }
+ transport->io_layers[layer] = &amqp_write_header_layer;
+ if (transport->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, " <- %s", "AMQP");
+ return 8;
+ case PNI_PROTOCOL_INSUFFICIENT:
+ if (!eos) return 0;
+ error = "End of input stream before protocol detection";
+ break;
+ case PNI_PROTOCOL_AMQP_OTHER:
+ error = "Incompatible AMQP connection detected";
+ break;
+ case PNI_PROTOCOL_UNKNOWN:
+ default:
+ error = "Unknown protocol detected";
+ break;
+ }
+ transport->io_layers[layer] = &pni_header_error_layer;
+ char quoted[1024];
+ pn_quote_data(quoted, 1024, bytes, available);
+ pn_do_error(transport, "amqp:connection:framing-error",
+ "%s: '%s'%s", error, quoted,
+ !eos ? "" : " (connection aborted)");
+ return 0;
+}
+
+// We don't know what the output should be - do nothing
+ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
+{
+ return 0;
+}
+
+/** Pass through input handler */
+ssize_t pn_io_layer_input_passthru(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
+{
+ if (layer+1<PN_IO_LAYER_CT)
+ return transport->io_layers[layer+1]->process_input(transport, layer+1, data, available);
+ return PN_EOS;
+}
+
+/** Pass through output handler */
+ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
+{
+ if (layer+1<PN_IO_LAYER_CT)
+ return transport->io_layers[layer+1]->process_output(transport, layer+1, data, available);
+ return PN_EOS;
+}
+
+/** Input handler after detected error */
+ssize_t pn_io_layer_input_error(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
+{
+ return PN_EOS;
+}
+
+/** Output handler after detected error */
+ssize_t pn_io_layer_output_error(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
+{
+ return PN_EOS;
+}
+
+static void pn_transport_initialize(void *object)
+{
+ pn_transport_t *transport = (pn_transport_t *)object;
+ transport->freed = false;
+ transport->output_buf = NULL;
+ transport->output_size = PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
+ transport->input_buf = NULL;
+ transport->input_size = PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
+ transport->tracer = pni_default_tracer;
+ transport->sasl = NULL;
+ transport->ssl = NULL;
+
+ transport->scratch = pn_string(NULL);
+ transport->args = pn_data(16);
+ transport->output_args = pn_data(16);
+ transport->frame = pn_buffer(PN_TRANSPORT_INITIAL_FRAME_SIZE);
+ transport->input_frames_ct = 0;
+ transport->output_frames_ct = 0;
+
+ transport->connection = NULL;
+ transport->context = pn_record();
+
+ for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
+ transport->io_layers[layer] = NULL;
+ }
+
+ transport->allowed_layers = LAYER_AMQP1 | LAYER_AMQPSASL | LAYER_AMQPSSL | LAYER_SSL;
+ transport->present_layers = LAYER_NONE;
+
+ // Defer setting up the layers until the first data arrives or is sent
+ transport->io_layers[0] = &pni_setup_layer;
+
+ transport->open_sent = false;
+ transport->open_rcvd = false;
+ transport->close_sent = false;
+ transport->close_rcvd = false;
+ transport->tail_closed = false;
+ transport->head_closed = false;
+ transport->remote_container = NULL;
+ transport->remote_hostname = NULL;
+ transport->local_max_frame = PN_DEFAULT_MAX_FRAME_SIZE;
+ transport->remote_max_frame = (uint32_t) 0xffffffff;
+
+ /*
+ * We set the local limit on channels to 2^15, because
+ * parts of the code use the topmost bit (of a short)
+ * as a flag.
+ * The peer that this transport connects to may also
+ * place its own limit on max channel number, and the
+ * application may also set a limit.
+ * The maximum that we use will be the minimum of all
+ * these constraints.
+ */
+ // There is no constraint yet from remote peer,
+ // so set to max possible.
+ transport->remote_channel_max = 65535;
+ transport->local_channel_max = PN_IMPL_CHANNEL_MAX;
+ transport->channel_max = transport->local_channel_max;
+
+ transport->local_idle_timeout = 0;
+ transport->dead_remote_deadline = 0;
+ transport->last_bytes_input = 0;
+ transport->remote_idle_timeout = 0;
+ transport->keepalive_deadline = 0;
+ transport->last_bytes_output = 0;
+ transport->remote_offered_capabilities = pn_data(0);
+ transport->remote_desired_capabilities = pn_data(0);
+ transport->remote_properties = pn_data(0);
+ transport->disp_data = pn_data(0);
+ pn_condition_init(&transport->remote_condition);
+ pn_condition_init(&transport->condition);
+ transport->error = pn_error();
+
+ transport->local_channels = pn_hash(PN_WEAKREF, 0, 0.75);
+ transport->remote_channels = pn_hash(PN_WEAKREF, 0, 0.75);
+
+ transport->bytes_input = 0;
+ transport->bytes_output = 0;
+
+ transport->input_pending = 0;
+ transport->output_pending = 0;
+
+ transport->done_processing = false;
+
+ transport->posted_idle_timeout = false;
+
+ transport->server = false;
+ transport->halt = false;
+ transport->auth_required = false;
+ transport->authenticated = false;
+ transport->encryption_required = false;
+
+ transport->referenced = true;
+
+ transport->trace =
+ (pn_env_bool("PN_TRACE_RAW") ? PN_TRACE_RAW : PN_TRACE_OFF) |
+ (pn_env_bool("PN_TRACE_FRM") ? PN_TRACE_FRM : PN_TRACE_OFF) |
+ (pn_env_bool("PN_TRACE_DRV") ? PN_TRACE_DRV : PN_TRACE_OFF) |
+ (pn_env_bool("PN_TRACE_EVT") ? PN_TRACE_EVT : PN_TRACE_OFF) ;
+}
+
+
+static pn_session_t *pni_channel_state(pn_transport_t *transport, uint16_t channel)
+{
+ return (pn_session_t *) pn_hash_get(transport->remote_channels, channel);
+}
+
+static void pni_map_remote_channel(pn_session_t *session, uint16_t channel)
+{
+ pn_transport_t *transport = session->connection->transport;
+ pn_hash_put(transport->remote_channels, channel, session);
+ session->state.remote_channel = channel;
+ pn_ep_incref(&session->endpoint);
+}
+
+void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state);
+
+static void pni_unmap_remote_channel(pn_session_t *ssn)
+{
+ // XXX: should really update link state also
+ pni_delivery_map_clear(&ssn->state.incoming);
+ pni_transport_unbind_handles(ssn->state.remote_handles, false);
+ pn_transport_t *transport = ssn->connection->transport;
+ uint16_t channel = ssn->state.remote_channel;
+ ssn->state.remote_channel = -2;
+ if (pn_hash_get(transport->remote_channels, channel)) {
+ pn_ep_decref(&ssn->endpoint);
+ }
+ // note: may free the session:
+ pn_hash_del(transport->remote_channels, channel);
+}
+
+static void pn_transport_incref(void *object)
+{
+ pn_transport_t *transport = (pn_transport_t *) object;
+ if (!transport->referenced) {
+ transport->referenced = true;
+ if (transport->connection) {
+ pn_incref(transport->connection);
+ } else {
+ pn_object_incref(object);
+ }
+ } else {
+ pn_object_incref(object);
+ }
+}
+
+static void pn_transport_finalize(void *object);
+#define pn_transport_new pn_object_new
+#define pn_transport_refcount pn_object_refcount
+#define pn_transport_decref pn_object_decref
+#define pn_transport_reify pn_object_reify
+#define pn_transport_hashcode NULL
+#define pn_transport_compare NULL
+#define pn_transport_inspect NULL
+
+pn_transport_t *pn_transport(void)
+{
+#define pn_transport_free pn_object_free
+ static const pn_class_t clazz = PN_METACLASS(pn_transport);
+#undef pn_transport_free
+ pn_transport_t *transport =
+ (pn_transport_t *) pn_class_new(&clazz, sizeof(pn_transport_t));
+ if (!transport) return NULL;
+
+ transport->output_buf = (char *) malloc(transport->output_size);
+ if (!transport->output_buf) {
+ pn_transport_free(transport);
+ return NULL;
+ }
+
+ transport->input_buf = (char *) malloc(transport->input_size);
+ if (!transport->input_buf) {
+ pn_transport_free(transport);
+ return NULL;
+ }
+
+ transport->capacity = 4*1024;
+ transport->available = 0;
+ transport->output = (char *) malloc(transport->capacity);
+ if (!transport->output) {
+ pn_transport_free(transport);
+ return NULL;
+ }
+
+ return transport;
+}
+
+void pn_transport_set_server(pn_transport_t *transport)
+{
+ assert(transport);
+ transport->server = true;
+}
+
+const char *pn_transport_get_user(pn_transport_t *transport)
+{
+ assert(transport);
+ // Client - just return whatever we gave to sasl
+ if (!transport->server) {
+ if (transport->sasl) return pn_sasl_get_user((pn_sasl_t *)transport);
+ return "anonymous";
+ }
+
+ // Server
+ // Not finished authentication yet
+ if (!(transport->present_layers & LAYER_AMQP1)) return 0;
+ // We have SASL so it takes precedence
+ if (transport->present_layers & LAYER_AMQPSASL) return pn_sasl_get_user((pn_sasl_t *)transport);
+ // No SASL but we may have a SSL remote_subject
+ if (transport->present_layers & (LAYER_AMQPSSL | LAYER_SSL)) return pn_ssl_get_remote_subject((pn_ssl_t *)transport);
+ // otherwise it's just an unauthenticated anonymous connection
+ return "anonymous";
+}
+
+void pn_transport_require_auth(pn_transport_t *transport, bool required)
+{
+ assert(transport);
+ transport->auth_required = required;
+}
+
+bool pn_transport_is_authenticated(pn_transport_t *transport)
+{
+ return transport && transport->authenticated;
+}
+
+void pn_transport_require_encryption(pn_transport_t *transport, bool required)
+{
+ assert(transport);
+ transport->encryption_required = required;
+}
+
+bool pn_transport_is_encrypted(pn_transport_t *transport)
+{
+ return transport && transport->ssl && pn_ssl_get_ssf((pn_ssl_t*)transport)>0;
+}
+
+void pn_transport_free(pn_transport_t *transport)
+{
+ if (!transport) return;
+ assert(!transport->freed);
+ transport->freed = true;
+ pn_decref(transport);
+}
+
+static void pn_transport_finalize(void *object)
+{
+ pn_transport_t *transport = (pn_transport_t *) object;
+
+ if (transport->referenced && transport->connection && pn_refcount(transport->connection) > 1) {
+ pn_object_incref(transport);
+ transport->referenced = false;
+ pn_decref(transport->connection);
+ return;
+ }
+
+ // once the application frees the transport, no further I/O
+ // processing can be done to the connection:
+ pn_transport_unbind(transport);
+ // we may have posted events, so stay alive until they are processed
+ if (pn_refcount(transport) > 0) return;
+
+ pn_ssl_free(transport);
+ pn_sasl_free(transport);
+ free(transport->remote_container);
+ free(transport->remote_hostname);
+ pn_free(transport->remote_offered_capabilities);
+ pn_free(transport->remote_desired_capabilities);
+ pn_free(transport->remote_properties);
+ pn_free(transport->disp_data);
+ pn_condition_tini(&transport->remote_condition);
+ pn_condition_tini(&transport->condition);
+ pn_error_free(transport->error);
+ pn_free(transport->local_channels);
+ pn_free(transport->remote_channels);
+ if (transport->input_buf) free(transport->input_buf);
+ if (transport->output_buf) free(transport->output_buf);
+ pn_free(transport->scratch);
+ pn_data_free(transport->args);
+ pn_data_free(transport->output_args);
+ pn_buffer_free(transport->frame);
+ pn_free(transport->context);
+ free(transport->output);
+}
+
+static void pni_post_remote_open_events(pn_transport_t *transport, pn_connection_t *connection) {
+ pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_REMOTE_OPEN);
+ if (transport->remote_idle_timeout) {
+ pn_collector_put(connection->collector, PN_OBJECT, transport, PN_TRANSPORT);
+ }
+}
+
+int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
+{
+ assert(transport);
+ assert(connection);
+
+ if (transport->connection) return PN_STATE_ERR;
+ if (connection->transport) return PN_STATE_ERR;
+
+ transport->connection = connection;
+ connection->transport = transport;
+
+ pn_incref(connection);
+
+ pn_connection_bound(connection);
+
+ // set the hostname/user/password
+ if (pn_string_size(connection->auth_user)) {
+ pn_sasl(transport);
+ pni_sasl_set_user_password(transport, pn_string_get(connection->auth_user), pn_string_get(connection->auth_password));
+ }
+
+ if (pn_string_size(connection->hostname)) {
+ if (transport->sasl) {
+ pni_sasl_set_remote_hostname(transport, pn_string_get(connection->hostname));
+ }
+
+ // be sure not to overwrite a hostname already set by the user via
+ // pn_ssl_set_peer_hostname() called before the bind
+ if (transport->ssl) {
+ size_t name_len = 0;
+ pn_ssl_get_peer_hostname((pn_ssl_t*) transport, NULL, &name_len);
+ if (name_len == 0) {
+ pn_ssl_set_peer_hostname((pn_ssl_t*) transport, pn_string_get(connection->hostname));
+ }
+ }
+ }
+
+ if (transport->open_rcvd) {
+ PN_SET_REMOTE(connection->endpoint.state, PN_REMOTE_ACTIVE);
+ pni_post_remote_open_events(transport, connection);
+ transport->halt = false;
+ transport_consume(transport); // blech - testBindAfterOpen
+ }
+
+ return 0;
+}
+
+void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state)
+{
+ for (pn_handle_t h = pn_hash_head(handles); h; h = pn_hash_next(handles, h)) {
+ uintptr_t key = pn_hash_key(handles, h);
+ pn_link_t *link = (pn_link_t *) pn_hash_value(handles, h);
+ if (reset_state) {
+ pn_link_unbound(link);
+ }
+ pn_ep_decref(&link->endpoint);
+ pn_hash_del(handles, key);
+ }
+}
+
+void pni_transport_unbind_channels(pn_hash_t *channels)
+{
+ for (pn_handle_t h = pn_hash_head(channels); h; h = pn_hash_next(channels, h)) {
+ uintptr_t key = pn_hash_key(channels, h);
+ pn_session_t *ssn = (pn_session_t *) pn_hash_value(channels, h);
+ pni_delivery_map_clear(&ssn->state.incoming);
+ pni_delivery_map_clear(&ssn->state.outgoing);
+ pni_transport_unbind_handles(ssn->state.local_handles, true);
+ pni_transport_unbind_handles(ssn->state.remote_handles, true);
+ pn_session_unbound(ssn);
+ pn_ep_decref(&ssn->endpoint);
+ pn_hash_del(channels, key);
+ }
+}
+
+int pn_transport_unbind(pn_transport_t *transport)
+{
+ assert(transport);
+ if (!transport->connection) return 0;
+
+
+ pn_connection_t *conn = transport->connection;
+ transport->connection = NULL;
+ bool was_referenced = transport->referenced;
+
+ pn_collector_put(conn->collector, PN_OBJECT, conn, PN_CONNECTION_UNBOUND);
+
+ // XXX: what happens if the endpoints are freed before we get here?
+ pn_session_t *ssn = pn_session_head(conn, 0);
+ while (ssn) {
+ pni_delivery_map_clear(&ssn->state.incoming);
+ pni_delivery_map_clear(&ssn->state.outgoing);
+ ssn = pn_session_next(ssn, 0);
+ }
+
+ pn_endpoint_t *endpoint = conn->endpoint_head;
+ while (endpoint) {
+ pn_condition_clear(&endpoint->remote_condition);
+ pn_modified(conn, endpoint, true);
+ endpoint = endpoint->endpoint_next;
+ }
+
+ pni_transport_unbind_channels(transport->local_channels);
+ pni_transport_unbind_channels(transport->remote_channels);
+
+ pn_connection_unbound(conn);
+ if (was_referenced) {
+ pn_decref(conn);
+ }
+ return 0;
+}
+
+pn_error_t *pn_transport_error(pn_transport_t *transport)
+{
+ assert(transport);
+ if (pn_condition_is_set(&transport->condition)) {
+ pn_error_format(transport->error, PN_ERR, "%s: %s",
+ pn_condition_get_name(&transport->condition),
+ pn_condition_get_description(&transport->condition));
+ } else {
+ pn_error_clear(transport->error);
+ }
+ return transport->error;
+}
+
+pn_condition_t *pn_transport_condition(pn_transport_t *transport)
+{
+ assert(transport);
+ return &transport->condition;
+}
+
+static void pni_map_remote_handle(pn_link_t *link, uint32_t handle)
+{
+ link->state.remote_handle = handle;
+ pn_hash_put(link->session->state.remote_handles, handle, link);
+ pn_ep_incref(&link->endpoint);
+}
+
+static void pni_unmap_remote_handle(pn_link_t *link)
+{
+ uintptr_t handle = link->state.remote_handle;
+ link->state.remote_handle = -2;
+ if (pn_hash_get(link->session->state.remote_handles, handle)) {
+ pn_ep_decref(&link->endpoint);
+ }
+ // may delete link:
+ pn_hash_del(link->session->state.remote_handles, handle);
+}
+
+static pn_link_t *pni_handle_state(pn_session_t *ssn, uint32_t handle)
+{
+ return (pn_link_t *) pn_hash_get(ssn->state.remote_handles, handle);
+}
+
+bool pni_disposition_batchable(pn_disposition_t *disposition)
+{
+ switch (disposition->type) {
+ case PN_ACCEPTED:
+ return true;
+ case PN_RELEASED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int pni_disposition_encode(pn_disposition_t *disposition, pn_data_t *data)
+{
+ pn_condition_t *cond = &disposition->condition;
+ switch (disposition->type) {
+ case PN_RECEIVED:
+ PN_RETURN_IF_ERROR(pn_data_put_list(data));
+ pn_data_enter(data);
+ PN_RETURN_IF_ERROR(pn_data_put_uint(data, disposition->section_number));
+ PN_RETURN_IF_ERROR(pn_data_put_ulong(data, disposition->section_offset));
+ pn_data_exit(data);
+ return 0;
+ case PN_ACCEPTED:
+ case PN_RELEASED:
+ return 0;
+ case PN_REJECTED:
+ return pn_data_fill(data, "[?DL[sSC]]", pn_condition_is_set(cond), ERROR,
+ pn_condition_get_name(cond),
+ pn_condition_get_description(cond),
+ pn_condition_info(cond));
+ case PN_MODIFIED:
+ return pn_data_fill(data, "[ooC]",
+ disposition->failed,
+ disposition->undeliverable,
+ disposition->annotations);
+ default:
+ return pn_data_copy(data, disposition->data);
+ }
+}
+
+
+void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
+ pn_data_t *args, const char *payload, size_t size)
+{
+ if (transport->trace & PN_TRACE_FRM) {
+ pn_string_format(transport->scratch, "%u %s ", ch, dir == OUT ? "->" : "<-");
+ pn_inspect(args, transport->scratch);
+
+ if (pn_data_size(args)==0) {
+ pn_string_addf(transport->scratch, "(EMPTY FRAME)");
+ }
+
+ if (size) {
+ char buf[1024];
+ int e = pn_quote_data(buf, 1024, payload, size);
+ pn_string_addf(transport->scratch, " (%" PN_ZU ") \"%s\"%s", size, buf,
+ e == PN_OVERFLOW ? "... (truncated)" : "");
+ }
+
+ pn_transport_log(transport, pn_string_get(transport->scratch));
+ }
+}
+
+int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...)
+{
+ pn_buffer_t *frame_buf = transport->frame;
+ va_list ap;
+ va_start(ap, fmt);
+ pn_data_clear(transport->output_args);
+ int err = pn_data_vfill(transport->output_args, fmt, ap);
+ va_end(ap);
+ if (err) {
+ pn_transport_logf(transport,
+ "error posting frame: %s, %s: %s", fmt, pn_code(err),
+ pn_error_text(pn_data_error(transport->output_args)));
+ return PN_ERR;
+ }
+
+ pn_do_trace(transport, ch, OUT, transport->output_args, NULL, 0);
+
+ encode_performatives:
+ pn_buffer_clear( frame_buf );
+ pn_rwbytes_t buf = pn_buffer_memory( frame_buf );
+ buf.size = pn_buffer_available( frame_buf );
+
+ ssize_t wr = pn_data_encode( transport->output_args, buf.start, buf.size );
+ if (wr < 0) {
+ if (wr == PN_OVERFLOW) {
+ pn_buffer_ensure( frame_buf, pn_buffer_available( frame_buf ) * 2 );
+ goto encode_performatives;
+ }
+ pn_transport_logf(transport,
+ "error posting frame: %s", pn_code(wr));
+ return PN_ERR;
+ }
+
+ pn_frame_t frame = {0,};
+ frame.type = type;
+ frame.channel = ch;
+ frame.payload = buf.start;
+ frame.size = wr;
+ size_t n;
+ while (!(n = pn_write_frame(transport->output + transport->available,
+ transport->capacity - transport->available, frame))) {
+ transport->capacity *= 2;
+ transport->output = (char *) realloc(transport->output, transport->capacity);
+ }
+ transport->output_frames_ct += 1;
+ if (transport->trace & PN_TRACE_RAW) {
+ pn_string_set(transport->scratch, "RAW: \"");
+ pn_quote(transport->scratch, transport->output + transport->available, n);
+ pn_string_addf(transport->scratch, "\"");
+ pn_transport_log(transport, pn_string_get(transport->scratch));
+ }
+ transport->available += n;
+
+ return 0;
+}
+
+static int pni_post_amqp_transfer_frame(pn_transport_t *transport, uint16_t ch,
+ uint32_t handle,
+ pn_sequence_t id,
+ pn_bytes_t *payload,
+ const pn_bytes_t *tag,
+ uint32_t message_format,
+ bool settled,
+ bool more,
+ pn_sequence_t frame_limit,
+ uint64_t code,
+ pn_data_t* state)
+{
+ bool more_flag = more;
+ int framecount = 0;
+ pn_buffer_t *frame = transport->frame;
+
+ // create preformatives, assuming 'more' flag need not change
+
+ compute_performatives:
+ pn_data_clear(transport->output_args);
+ int err = pn_data_fill(transport->output_args, "DL[IIzIoon?DLC]", TRANSFER,
+ handle, id, tag->size, tag->start,
+ message_format,
+ settled, more_flag, (bool)code, code, state);
+ if (err) {
+ pn_transport_logf(transport,
+ "error posting transfer frame: %s: %s", pn_code(err),
+ pn_error_text(pn_data_error(transport->output_args)));
+ return PN_ERR;
+ }
+
+ do { // send as many frames as possible without changing the 'more' flag...
+
+ encode_performatives:
+ pn_buffer_clear( frame );
+ pn_rwbytes_t buf = pn_buffer_memory( frame );
+ buf.size = pn_buffer_available( frame );
+
+ ssize_t wr = pn_data_encode(transport->output_args, buf.start, buf.size);
+ if (wr < 0) {
+ if (wr == PN_OVERFLOW) {
+ pn_buffer_ensure( frame, pn_buffer_available( frame ) * 2 );
+ goto encode_performatives;
+ }
+ pn_transport_logf(transport, "error posting frame: %s", pn_code(wr));
+ return PN_ERR;
+ }
+ buf.size = wr;
+
+ // check if we need to break up the outbound frame
+ size_t available = payload->size;
+ if (transport->remote_max_frame) {
+ if ((available + buf.size) > transport->remote_max_frame - 8) {
+ available = transport->remote_max_frame - 8 - buf.size;
+ if (more_flag == false) {
+ more_flag = true;
+ goto compute_performatives; // deal with flag change
+ }
+ } else if (more_flag == true && more == false) {
+ // caller has no more, and this is the last frame
+ more_flag = false;
+ goto compute_performatives;
+ }
+ }
+
+ if (pn_buffer_available( frame ) < (available + buf.size)) {
+ // not enough room for payload - try again...
+ pn_buffer_ensure( frame, available + buf.size );
+ goto encode_performatives;
+ }
+
+ pn_do_trace(transport, ch, OUT, transport->output_args, payload->start, available);
+
+ memmove( buf.start + buf.size, payload->start, available);
+ payload->start += available;
+ payload->size -= available;
+ buf.size += available;
+
+ pn_frame_t frame = {AMQP_FRAME_TYPE};
+ frame.channel = ch;
+ frame.payload = buf.start;
+ frame.size = buf.size;
+
+ size_t n;
+ while (!(n = pn_write_frame(transport->output + transport->available,
+ transport->capacity - transport->available, frame))) {
+ transport->capacity *= 2;
+ transport->output = (char *) realloc(transport->output, transport->capacity);
+ }
+ transport->output_frames_ct += 1;
+ framecount++;
+ if (transport->trace & PN_TRACE_RAW) {
+ pn_string_set(transport->scratch, "RAW: \"");
+ pn_quote(transport->scratch, transport->output + transport->available, n);
+ pn_string_addf(transport->scratch, "\"");
+ pn_transport_log(transport, pn_string_get(transport->scratch));
+ }
+ transport->available += n;
+ } while (payload->size > 0 && framecount < frame_limit);
+
+ return framecount;
+}
+
+static int pni_post_close(pn_transport_t *transport, pn_condition_t *cond)
+{
+ if (!cond && transport->connection) {
+ cond = pn_connection_condition(transport->connection);
+ }
+ const char *condition = NULL;
+ const char *description = NULL;
+ pn_data_t *info = NULL;
+ if (pn_condition_is_set(cond)) {
+ condition = pn_condition_get_name(cond);
+ description = pn_condition_get_description(cond);
+ info = pn_condition_info(cond);
+ }
+
+ return pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[?DL[sSC]]", CLOSE,
+ (bool) condition, ERROR, condition, description, info);
+}
+
+static pn_collector_t *pni_transport_collector(pn_transport_t *transport)
+{
+ if (transport->connection && transport->connection->collector) {
+ return transport->connection->collector;
+ } else {
+ return NULL;
+ }
+}
+
+static void pni_maybe_post_closed(pn_transport_t *transport)
+{
+ pn_collector_t *collector = pni_transport_collector(transport);
+ if (transport->head_closed && transport->tail_closed) {
+ pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_CLOSED);
+ }
+}
+
+static void pni_close_tail(pn_transport_t *transport)
+{
+ if (!transport->tail_closed) {
+ transport->tail_closed = true;
+ pn_collector_t *collector = pni_transport_collector(transport);
+ pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_TAIL_CLOSED);
+ pni_maybe_post_closed(transport);
+ }
+}
+
+int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ char buf[1024];
+ if (fmt) {
+ // XXX: result
+ pni_vsnprintf(buf, 1024, fmt, ap);
+ } else {
+ buf[0] = '\0';
+ }
+ va_end(ap);
+ pn_condition_t *cond = &transport->condition;
+ if (!pn_condition_is_set(cond)) {
+ pn_condition_set_name(cond, condition);
+ if (fmt) {
+ pn_condition_set_description(cond, buf);
+ }
+ } else {
+ const char *first = pn_condition_get_description(cond);
+ if (first && fmt) {
+ char extended[2048];
+ pni_snprintf(extended, 2048, "%s (%s)", first, buf);
+ pn_condition_set_description(cond, extended);
+ } else if (fmt) {
+ pn_condition_set_description(cond, buf);
+ }
+ }
+ pn_collector_t *collector = pni_transport_collector(transport);
+ pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_ERROR);
+ if (transport->trace & PN_TRACE_DRV) {
+ pn_transport_logf(transport, "ERROR %s %s", condition, buf);
+ }
+
+ for (int i = 0; i<PN_IO_LAYER_CT; ++i) {
+ if (transport->io_layers[i] && transport->io_layers[i]->handle_error)
+ transport->io_layers[i]->handle_error(transport, i);
+ }
+
+ pni_close_tail(transport);
+ return PN_ERR;
+}
+
+static char *pn_bytes_strdup(pn_bytes_t str)
+{
+ return pn_strndup(str.start, str.size);
+}
+
+int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ pn_connection_t *conn = transport->connection;
+ bool container_q, hostname_q, remote_channel_max_q, remote_max_frame_q;
+ uint16_t remote_channel_max;
+ uint32_t remote_max_frame;
+ pn_bytes_t remote_container, remote_hostname;
+ pn_data_clear(transport->remote_offered_capabilities);
+ pn_data_clear(transport->remote_desired_capabilities);
+ pn_data_clear(transport->remote_properties);
+ int err = pn_data_scan(args, "D.[?S?S?I?HI..CCC]",
+ &container_q, &remote_container,
+ &hostname_q, &remote_hostname,
+ &remote_max_frame_q, &remote_max_frame,
+ &remote_channel_max_q, &remote_channel_max,
+ &transport->remote_idle_timeout,
+ transport->remote_offered_capabilities,
+ transport->remote_desired_capabilities,
+ transport->remote_properties);
+ if (err) return err;
+ /*
+ * The default value is already stored in the variable.
+ * But the scanner zeroes out values if it does not
+ * find them in the args, so don't give the variable
+ * directly to the scanner.
+ */
+ if (remote_channel_max_q) {
+ transport->remote_channel_max = remote_channel_max;
+ }
+
+ if (remote_max_frame_q) {
+ transport->remote_max_frame = remote_max_frame;
+ }
+
+ if (transport->remote_max_frame > 0) {
+ if (transport->remote_max_frame < AMQP_MIN_MAX_FRAME_SIZE) {
+ pn_transport_logf(transport, "Peer advertised bad max-frame (%u), forcing to %u",
+ transport->remote_max_frame, AMQP_MIN_MAX_FRAME_SIZE);
+ transport->remote_max_frame = AMQP_MIN_MAX_FRAME_SIZE;
+ }
+ }
+ if (container_q) {
+ transport->remote_container = pn_bytes_strdup(remote_container);
+ } else {
+ transport->remote_container = NULL;
+ }
+ if (hostname_q) {
+ transport->remote_hostname = pn_bytes_strdup(remote_hostname);
+ } else {
+ transport->remote_hostname = NULL;
+ }
+
+ if (conn) {
+ PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_ACTIVE);
+ pni_post_remote_open_events(transport, conn);
+ } else {
+ transport->halt = true;
+ }
+ transport->open_rcvd = true;
+ pni_calculate_channel_max(transport);
+ return 0;
+}
+
+int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ bool reply;
+ uint16_t remote_channel;
+ pn_sequence_t next;
+ int err = pn_data_scan(args, "D.[?HI]", &reply, &remote_channel, &next);
+ if (err) return err;
+
+ // AMQP 1.0 section 2.7.1 - if the peer doesn't honor our channel_max --
+ // express our displeasure by closing the connection with a framing error.
+ if (remote_channel > transport->channel_max) {
+ pn_do_error(transport,
+ "amqp:connection:framing-error",
+ "remote channel %d is above negotiated channel_max %d.",
+ remote_channel,
+ transport->channel_max
+ );
+ return PN_TRANSPORT_ERROR;
+ }
+
+ pn_session_t *ssn;
+ if (reply) {
+ ssn = (pn_session_t *) pn_hash_get(transport->local_channels, remote_channel);
+ } else {
+ ssn = pn_session(transport->connection);
+ }
+ if (ssn == 0) {
+ pn_do_error(transport,
+ "amqp:connection:framing-error",
+ "remote channel is above negotiated channel_max %d.",
+ transport->channel_max
+ );
+ return PN_TRANSPORT_ERROR;
+ }
+ ssn->state.incoming_transfer_count = next;
+ pni_map_remote_channel(ssn, channel);
+ PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
+ pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_OPEN);
+ return 0;
+}
+
+pn_link_t *pn_find_link(pn_session_t *ssn, pn_bytes_t name, bool is_sender)
+{
+ pn_endpoint_type_t type = is_sender ? SENDER : RECEIVER;
+
+ for (size_t i = 0; i < pn_list_size(ssn->links); i++)
+ {
+ pn_link_t *link = (pn_link_t *) pn_list_get(ssn->links, i);
+ if (link->endpoint.type == type &&
+ // This function is used to locate the link object for an
+ // incoming attach. If a link object of the same name is found
+ // which is closed both locally and remotely, assume that is
+ // no longer in use.
+ !((link->endpoint.state & PN_LOCAL_CLOSED) && (link->endpoint.state & PN_REMOTE_CLOSED)) &&
+ !strncmp(name.start, pn_string_get(link->name), name.size))
+ {
+ return link;
+ }
+ }
+ return NULL;
+}
+
+static pn_expiry_policy_t symbol2policy(pn_bytes_t symbol)
+{
+ if (!symbol.start)
+ return PN_EXPIRE_WITH_SESSION;
+
+ if (!strncmp(symbol.start, "link-detach", symbol.size))
+ return PN_EXPIRE_WITH_LINK;
+ if (!strncmp(symbol.start, "session-end", symbol.size))
+ return PN_EXPIRE_WITH_SESSION;
+ if (!strncmp(symbol.start, "connection-close", symbol.size))
+ return PN_EXPIRE_WITH_CONNECTION;
+ if (!strncmp(symbol.start, "never", symbol.size))
+ return PN_EXPIRE_NEVER;
+
+ return PN_EXPIRE_WITH_SESSION;
+}
+
+static pn_distribution_mode_t symbol2dist_mode(const pn_bytes_t symbol)
+{
+ if (!symbol.start)
+ return PN_DIST_MODE_UNSPECIFIED;
+
+ if (!strncmp(symbol.start, "move", symbol.size))
+ return PN_DIST_MODE_MOVE;
+ if (!strncmp(symbol.start, "copy", symbol.size))
+ return PN_DIST_MODE_COPY;
+
+ return PN_DIST_MODE_UNSPECIFIED;
+}
+
+static const char *dist_mode2symbol(const pn_distribution_mode_t mode)
+{
+ switch (mode)
+ {
+ case PN_DIST_MODE_COPY:
+ return "copy";
+ case PN_DIST_MODE_MOVE:
+ return "move";
+ default:
+ return NULL;
+ }
+}
+
+int pn_terminus_set_address_bytes(pn_terminus_t *terminus, pn_bytes_t address)
+{
+ assert(terminus);
+ return pn_string_setn(terminus->address, address.start, address.size);
+}
+
+int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ pn_bytes_t name;
+ uint32_t handle;
+ bool is_sender;
+ pn_bytes_t source, target;
+ pn_durability_t src_dr, tgt_dr;
+ pn_bytes_t src_exp, tgt_exp;
+ pn_seconds_t src_timeout, tgt_timeout;
+ bool src_dynamic, tgt_dynamic;
+ pn_sequence_t idc;
+ pn_bytes_t dist_mode;
+ bool snd_settle, rcv_settle;
+ uint8_t snd_settle_mode, rcv_settle_mode;
+ int err = pn_data_scan(args, "D.[SIo?B?BD.[SIsIo.s]D.[SIsIo]..I]", &name, &handle,
+ &is_sender,
+ &snd_settle, &snd_settle_mode,
+ &rcv_settle, &rcv_settle_mode,
+ &source, &src_dr, &src_exp, &src_timeout, &src_dynamic, &dist_mode,
+ &target, &tgt_dr, &tgt_exp, &tgt_timeout, &tgt_dynamic,
+ &idc);
+ if (err) return err;
+ char strbuf[128]; // avoid malloc for most link names
+ char *strheap = (name.size >= sizeof(strbuf)) ? (char *) malloc(name.size + 1) : NULL;
+ char *strname = strheap ? strheap : strbuf;
+ strncpy(strname, name.start, name.size);
+ strname[name.size] = '\0';
+
+ pn_session_t *ssn = pni_channel_state(transport, channel);
+ if (!ssn) {
+ pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+ if (strheap) free(strheap);
+ return PN_EOS;
+ }
+ pn_link_t *link = pn_find_link(ssn, name, is_sender);
+ if (!link) {
+ if (is_sender) {
+ link = (pn_link_t *) pn_sender(ssn, strname);
+ } else {
+ link = (pn_link_t *) pn_receiver(ssn, strname);
+ }
+ }
+
+ if (strheap) {
+ free(strheap);
+ }
+
+ pni_map_remote_handle(link, handle);
+ PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_ACTIVE);
+ pn_terminus_t *rsrc = &link->remote_source;
+ if (source.start || src_dynamic) {
+ pn_terminus_set_type(rsrc, PN_SOURCE);
+ pn_terminus_set_address_bytes(rsrc, source);
+ pn_terminus_set_durability(rsrc, src_dr);
+ pn_terminus_set_expiry_policy(rsrc, symbol2policy(src_exp));
+ pn_terminus_set_timeout(rsrc, src_timeout);
+ pn_terminus_set_dynamic(rsrc, src_dynamic);
+ pn_terminus_set_distribution_mode(rsrc, symbol2dist_mode(dist_mode));
+ } else {
+ pn_terminus_set_type(rsrc, PN_UNSPECIFIED);
+ }
+ pn_terminus_t *rtgt = &link->remote_target;
+ if (target.start || tgt_dynamic) {
+ pn_terminus_set_type(rtgt, PN_TARGET);
+ pn_terminus_set_address_bytes(rtgt, target);
+ pn_terminus_set_durability(rtgt, tgt_dr);
+ pn_terminus_set_expiry_policy(rtgt, symbol2policy(tgt_exp));
+ pn_terminus_set_timeout(rtgt, tgt_timeout);
+ pn_terminus_set_dynamic(rtgt, tgt_dynamic);
+ } else {
+ uint64_t code = 0;
+ pn_data_clear(link->remote_target.capabilities);
+ err = pn_data_scan(args, "D.[.....D..DL[C]...]", &code,
+ link->remote_target.capabilities);
+ if (err) return err;
+ if (code == COORDINATOR) {
+ pn_terminus_set_type(rtgt, PN_COORDINATOR);
+ } else if (code == TARGET) {
+ pn_terminus_set_type(rtgt, PN_TARGET);
+ } else {
+ pn_terminus_set_type(rtgt, PN_UNSPECIFIED);
+ }
+ }
+
+ if (snd_settle)
+ link->remote_snd_settle_mode = snd_settle_mode;
+ if (rcv_settle)
+ link->remote_rcv_settle_mode = rcv_settle_mode;
+
+ pn_data_clear(link->remote_source.properties);
+ pn_data_clear(link->remote_source.filter);
+ pn_data_clear(link->remote_source.outcomes);
+ pn_data_clear(link->remote_source.capabilities);
+ pn_data_clear(link->remote_target.properties);
+ pn_data_clear(link->remote_target.capabilities);
+
+ err = pn_data_scan(args, "D.[.....D.[.....C.C.CC]D.[.....CC]",
+ link->remote_source.properties,
+ link->remote_source.filter,
+ link->remote_source.outcomes,
+ link->remote_source.capabilities,
+ link->remote_target.properties,
+ link->remote_target.capabilities);
+ if (err) return err;
+
+ pn_data_rewind(link->remote_source.properties);
+ pn_data_rewind(link->remote_source.filter);
+ pn_data_rewind(link->remote_source.outcomes);
+ pn_data_rewind(link->remote_source.capabilities);
+ pn_data_rewind(link->remote_target.properties);
+ pn_data_rewind(link->remote_target.capabilities);
+
+ if (!is_sender) {
+ link->state.delivery_count = idc;
+ }
+
+ pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_OPEN);
+ return 0;
+}
+
+static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link);
+
+// free the delivery
+static void pn_full_settle(pn_delivery_map_t *db, pn_delivery_t *delivery)
+{
+ assert(!delivery->work);
+ pn_clear_tpwork(delivery);
+ pn_delivery_map_del(db, delivery);
+ pn_incref(delivery);
+ pn_decref(delivery);
+}
+
+int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ // XXX: multi transfer
+ uint32_t handle;
+ pn_bytes_t tag;
+ bool id_present;
+ pn_sequence_t id;
+ bool settled;
+ bool more;
+ bool has_type;
+ uint64_t type;
+ pn_data_clear(transport->disp_data);
+ int err = pn_data_scan(args, "D.[I?Iz.oo.D?LC]", &handle, &id_present, &id, &tag,
+ &settled, &more, &has_type, &type, transport->disp_data);
+ if (err) return err;
+ pn_session_t *ssn = pni_channel_state(transport, channel);
+ if (!ssn) {
+ return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+ }
+
+ if (!ssn->state.incoming_window) {
+ return pn_do_error(transport, "amqp:session:window-violation", "incoming session window exceeded");
+ }
+
+ pn_link_t *link = pni_handle_state(ssn, handle);
+ if (!link) {
+ return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
+ }
+ pn_delivery_t *delivery;
+ if (link->unsettled_tail && !link->unsettled_tail->done) {
+ delivery = link->unsettled_tail;
+ } else {
+ pn_delivery_map_t *incoming = &ssn->state.incoming;
+
+ if (!ssn->state.incoming_init) {
+ incoming->next = id;
+ ssn->state.incoming_init = true;
+ ssn->incoming_deliveries++;
+ }
+
+ delivery = pn_delivery(link, pn_dtag(tag.start, tag.size));
+ pn_delivery_state_t *state = pni_delivery_map_push(incoming, delivery);
+ if (id_present && id != state->id) {
+ return pn_do_error(transport, "amqp:session:invalid-field",
+ "sequencing error, expected delivery-id %u, got %u",
+ state->id, id);
+ }
+ if (has_type) {
+ delivery->remote.type = type;
+ pn_data_copy(delivery->remote.data, transport->disp_data);
+ }
+
+ link->state.delivery_count++;
+ link->state.link_credit--;
+ link->queued++;
+
+ // XXX: need to fill in remote state: delivery->remote.state = ...;
+ delivery->remote.settled = settled;
+ if (settled) {
+ delivery->updated = true;
+ pn_work_update(transport->connection, delivery);
+ }
+ }
+
+ pn_buffer_append(delivery->bytes, payload->start, payload->size);
+ ssn->incoming_bytes += payload->size;
+ delivery->done = !more;
+
+ ssn->state.incoming_transfer_count++;
+ ssn->state.incoming_window--;
+
+ // XXX: need better policy for when to refresh window
+ if (!ssn->state.incoming_window && (int32_t) link->state.local_handle >= 0) {
+ pni_post_flow(transport, ssn, link);
+ }
+
+ pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
+ return 0;
+}
+
+int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ pn_sequence_t onext, inext, delivery_count;
+ uint32_t iwin, owin, link_credit;
+ uint32_t handle;
+ bool inext_init, handle_init, dcount_init, drain;
+ int err = pn_data_scan(args, "D.[?IIII?I?II.o]", &inext_init, &inext, &iwin,
+ &onext, &owin, &handle_init, &handle, &dcount_init,
+ &delivery_count, &link_credit, &drain);
+ if (err) return err;
+
+ pn_session_t *ssn = pni_channel_state(transport, channel);
+ if (!ssn) {
+ return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+ }
+
+ if (inext_init) {
+ ssn->state.remote_incoming_window = inext + iwin - ssn->state.outgoing_transfer_count;
+ } else {
+ ssn->state.remote_incoming_window = iwin;
+ }
+
+ if (handle_init) {
+ pn_link_t *link = pni_handle_state(ssn, handle);
+ if (!link) {
+ return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
+ }
+ if (link->endpoint.type == SENDER) {
+ pn_sequence_t receiver_count;
+ if (dcount_init) {
+ receiver_count = delivery_count;
+ } else {
+ // our initial delivery count
+ receiver_count = 0;
+ }
+ pn_sequence_t old = link->state.link_credit;
+ link->state.link_credit = receiver_count + link_credit - link->state.delivery_count;
+ link->credit += link->state.link_credit - old;
+ link->drain = drain;
+ pn_delivery_t *delivery = pn_link_current(link);
+ if (delivery) pn_work_update(transport->connection, delivery);
+ } else {
+ pn_sequence_t delta = delivery_count - link->state.delivery_count;
+ if (delta > 0) {
+ link->state.delivery_count += delta;
+ link->state.link_credit -= delta;
+ link->credit -= delta;
+ link->drained += delta;
+ }
+ }
+
+ pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
+ }
+
+ return 0;
+}
+
+#define SCAN_ERROR_DEFAULT ("D.[D.[sSC]")
+#define SCAN_ERROR_DETACH ("D.[..D.[sSC]")
+#define SCAN_ERROR_DISP ("[D.[sSC]")
+
+static int pn_scan_error(pn_data_t *data, pn_condition_t *condition, const char *fmt)
+{
+ pn_bytes_t cond;
+ pn_bytes_t desc;
+ pn_condition_clear(condition);
+ int err = pn_data_scan(data, fmt, &cond, &desc, condition->info);
+ if (err) return err;
+ pn_string_setn(condition->name, cond.start, cond.size);
+ pn_string_setn(condition->description, desc.start, desc.size);
+ pn_data_rewind(condition->info);
+ return 0;
+}
+
+int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ bool role;
+ pn_sequence_t first, last;
+ uint64_t type = 0;
+ bool last_init, settled, type_init;
+ pn_data_clear(transport->disp_data);
+ int err = pn_data_scan(args, "D.[oI?IoD?LC]", &role, &first, &last_init,
+ &last, &settled, &type_init, &type,
+ transport->disp_data);
+ if (err) return err;
+ if (!last_init) last = first;
+
+ pn_session_t *ssn = pni_channel_state(transport, channel);
+ if (!ssn) {
+ return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+ }
+
+ pn_delivery_map_t *deliveries;
+ if (role) {
+ deliveries = &ssn->state.outgoing;
+ } else {
+ deliveries = &ssn->state.incoming;
+ }
+
+ pn_data_rewind(transport->disp_data);
+ bool remote_data = (pn_data_next(transport->disp_data) &&
+ pn_data_get_list(transport->disp_data) > 0);
+
+ for (pn_sequence_t id = first; id <= last; id++) {
+ pn_delivery_t *delivery = pni_delivery_map_get(deliveries, id);
+ pn_disposition_t *remote = &delivery->remote;
+ if (delivery) {
+ if (type_init) remote->type = type;
+ if (remote_data) {
+ switch (type) {
+ case PN_RECEIVED:
+ pn_data_rewind(transport->disp_data);
+ pn_data_next(transport->disp_data);
+ pn_data_enter(transport->disp_data);
+ if (pn_data_next(transport->disp_data))
+ remote->section_number = pn_data_get_uint(transport->disp_data);
+ if (pn_data_next(transport->disp_data))
+ remote->section_offset = pn_data_get_ulong(transport->disp_data);
+ break;
+ case PN_ACCEPTED:
+ break;
+ case PN_REJECTED:
+ err = pn_scan_error(transport->disp_data, &remote->condition, SCAN_ERROR_DISP);
+ if (err) return err;
+ break;
+ case PN_RELEASED:
+ break;
+ case PN_MODIFIED:
+ pn_data_rewind(transport->disp_data);
+ pn_data_next(transport->disp_data);
+ pn_data_enter(transport->disp_data);
+ if (pn_data_next(transport->disp_data))
+ remote->failed = pn_data_get_bool(transport->disp_data);
+ if (pn_data_next(transport->disp_data))
+ remote->undeliverable = pn_data_get_bool(transport->disp_data);
+ pn_data_narrow(transport->disp_data);
+ pn_data_clear(remote->data);
+ pn_data_appendn(remote->annotations, transport->disp_data, 1);
+ pn_data_widen(transport->disp_data);
+ break;
+ default:
+ pn_data_copy(remote->data, transport->disp_data);
+ break;
+ }
+ }
+ remote->settled = settled;
+ delivery->updated = true;
+ pn_work_update(transport->connection, delivery);
+
+ pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
+ }
+ }
+
+ return 0;
+}
+
+int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ uint32_t handle;
+ bool closed;
+ int err = pn_data_scan(args, "D.[Io]", &handle, &closed);
+ if (err) return err;
+
+ pn_session_t *ssn = pni_channel_state(transport, channel);
+ if (!ssn) {
+ return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+ }
+ pn_link_t *link = pni_handle_state(ssn, handle);
+ if (!link) {
+ return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
+ }
+
+ err = pn_scan_error(args, &link->endpoint.remote_condition, SCAN_ERROR_DETACH);
+ if (err) return err;
+
+ if (closed)
+ {
+ PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_CLOSED);
+ pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_CLOSE);
+ } else {
+ pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_DETACH);
+ }
+
+ pni_unmap_remote_handle(link);
+ return 0;
+}
+
+int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ pn_session_t *ssn = pni_channel_state(transport, channel);
+ if (!ssn) {
+ return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+ }
+ int err = pn_scan_error(args, &ssn->endpoint.remote_condition, SCAN_ERROR_DEFAULT);
+ if (err) return err;
+ PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED);
+ pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_CLOSE);
+ pni_unmap_remote_channel(ssn);
+ return 0;
+}
+
+int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ pn_connection_t *conn = transport->connection;
+ int err = pn_scan_error(args, &transport->remote_condition, SCAN_ERROR_DEFAULT);
+ if (err) return err;
+ transport->close_rcvd = true;
+ PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_CLOSED);
+ pn_collector_put(transport->connection->collector, PN_OBJECT, conn, PN_CONNECTION_REMOTE_CLOSE);
+ return 0;
+}
+
+// deprecated
+ssize_t pn_transport_input(pn_transport_t *transport, const char *bytes, size_t available)
+{
+ if (!transport) return PN_ARG_ERR;
+ if (available == 0) {
+ return pn_transport_close_tail(transport);
+ }
+ const size_t original = available;
+ ssize_t capacity = pn_transport_capacity(transport);
+ if (capacity < 0) return capacity;
+ while (available && capacity) {
+ char *dest = pn_transport_tail(transport);
+ assert(dest);
+ size_t count = pn_min( (size_t)capacity, available );
+ memmove( dest, bytes, count );
+ available -= count;
+ bytes += count;
+ int rc = pn_transport_process( transport, count );
+ if (rc < 0) return rc;
+ capacity = pn_transport_capacity(transport);
+ if (capacity < 0) return capacity;
+ }
+
+ return original - available;
+}
+
+// process pending input until none remaining or EOS
+static ssize_t transport_consume(pn_transport_t *transport)
+{
+ // This allows whatever is driving the I/O to set the error
+ // condition on the transport before doing pn_transport_close_head()
+ // or pn_transport_close_tail(). This allows all transport errors to
+ // flow to the app the same way, but provides cleaner error messages
+ // since we don't try to look for a protocol header when, e.g. the
+ // connection was refused.
+ if (!transport->bytes_input && transport->tail_closed &&
+ pn_condition_is_set(&transport->condition)) {
+ pn_do_error(transport, NULL, NULL);
+ return PN_EOS;
+ }
+
+ size_t consumed = 0;
+
+ while (transport->input_pending || transport->tail_closed) {
+ ssize_t n;
+ n = transport->io_layers[0]->
+ process_input( transport, 0,
+ transport->input_buf + consumed,
+ transport->input_pending );
+ if (n > 0) {
+ consumed += n;
+ transport->input_pending -= n;
+ } else if (n == 0) {
+ break;
+ } else {
+ assert(n == PN_EOS);
+ if (transport->trace & (PN_TRACE_RAW | PN_TRACE_FRM))
+ pn_transport_log(transport, " <- EOS");
+ transport->input_pending = 0; // XXX ???
+ return n;
+ }
+ }
+
+ if (transport->input_pending && consumed) {
+ memmove( transport->input_buf, &transport->input_buf[consumed], transport->input_pending );
+ }
+
+ return consumed;
+}
+
+static int pni_process_conn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == CONNECTION)
+ {
+ if (!(endpoint->state & PN_LOCAL_UNINIT) && !transport->open_sent)
+ {
+ // as per the recommendation in the spec, advertise half our
+ // actual timeout to the remote
+ const pn_millis_t idle_timeout = transport->local_idle_timeout
+ ? (transport->local_idle_timeout/2)
+ : 0;
+ pn_connection_t *connection = (pn_connection_t *) endpoint;
+ const char *cid = pn_string_get(connection->container);
+ pni_calculate_channel_max(transport);
+ int err = pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[SS?I?H?InnCCC]", OPEN,
+ cid ? cid : "",
+ pn_string_get(connection->hostname),
+ // if not zero, advertise our max frame size and idle timeout
+ (bool)transport->local_max_frame, transport->local_max_frame,
+ (bool)transport->channel_max, transport->channel_max,
+ (bool)idle_timeout, idle_timeout,
+ connection->offered_capabilities,
+ connection->desired_capabilities,
+ connection->properties);
+ if (err) return err;
+ transport->open_sent = true;
+ }
+ }
+
+ return 0;
+}
+
+static uint16_t allocate_alias(pn_hash_t *aliases, uint32_t max_index, int * valid)
+{
+ for (uint32_t i = 0; i <= max_index; i++) {
+ if (!pn_hash_get(aliases, i)) {
+ * valid = 1;
+ return i;
+ }
+ }
+
+ * valid = 0;
+ return 0;
+}
+
+static size_t pni_session_outgoing_window(pn_session_t *ssn)
+{
+ return ssn->outgoing_window;
+}
+
+static size_t pni_session_incoming_window(pn_session_t *ssn)
+{
+ uint32_t size = ssn->connection->transport->local_max_frame;
+ if (!size) {
+ return 2147483647; // biggest legal value
+ } else {
+ return (ssn->incoming_capacity - ssn->incoming_bytes)/size;
+ }
+}
+
+static int pni_map_local_channel(pn_session_t *ssn)
+{
+ pn_transport_t *transport = ssn->connection->transport;
+ pn_session_state_t *state = &ssn->state;
+ int valid;
+ uint16_t channel = allocate_alias(transport->local_channels, transport->channel_max, & valid);
+ if (!valid) {
+ return 0;
+ }
+ state->local_channel = channel;
+ pn_hash_put(transport->local_channels, channel, ssn);
+ pn_ep_incref(&ssn->endpoint);
+ return 1;
+}
+
+static int pni_process_ssn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == SESSION && transport->open_sent)
+ {
+ pn_session_t *ssn = (pn_session_t *) endpoint;
+ pn_session_state_t *state = &ssn->state;
+ if (!(endpoint->state & PN_LOCAL_UNINIT) && state->local_channel == (uint16_t) -1)
+ {
+ if (! pni_map_local_channel(ssn)) {
+ pn_transport_logf(transport, "unable to find an open available channel within limit of %d", transport->channel_max );
+ return PN_ERR;
+ }
+ state->incoming_window = pni_session_incoming_window(ssn);
+ state->outgoing_window = pni_session_outgoing_window(ssn);
+ pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?HIII]", BEGIN,
+ ((int16_t) state->remote_channel >= 0), state->remote_channel,
+ state->outgoing_transfer_count,
+ state->incoming_window,
+ state->outgoing_window);
+ }
+ }
+
+ return 0;
+}
+
+static const char *expiry_symbol(pn_expiry_policy_t policy)
+{
+ switch (policy)
+ {
+ case PN_EXPIRE_WITH_LINK:
+ return "link-detach";
+ case PN_EXPIRE_WITH_SESSION:
+ return NULL;
+ case PN_EXPIRE_WITH_CONNECTION:
+ return "connection-close";
+ case PN_EXPIRE_NEVER:
+ return "never";
+ }
+ return NULL;
+}
+
+static int pni_map_local_handle(pn_link_t *link) {
+ pn_link_state_t *state = &link->state;
+ pn_session_state_t *ssn_state = &link->session->state;
+ int valid;
+ // XXX TODO MICK: once changes are made to handle_max, change this hardcoded value to something reasonable.
+ state->local_handle = allocate_alias(ssn_state->local_handles, 65536, & valid);
+ if ( ! valid )
+ return 0;
+ pn_hash_put(ssn_state->local_handles, state->local_handle, link);
+ pn_ep_incref(&link->endpoint);
+ return 1;
+}
+
+static int pni_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (transport->open_sent && (endpoint->type == SENDER ||
+ endpoint->type == RECEIVER))
+ {
+ pn_link_t *link = (pn_link_t *) endpoint;
+ pn_session_state_t *ssn_state = &link->session->state;
+ pn_link_state_t *state = &link->state;
+ if (((int16_t) ssn_state->local_channel >= 0) &&
+ !(endpoint->state & PN_LOCAL_UNINIT) && state->local_handle == (uint32_t) -1)
+ {
+ pni_map_local_handle(link);
+ const pn_distribution_mode_t dist_mode = link->source.distribution_mode;
+ if (link->target.type == PN_COORDINATOR) {
+ int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
+ "DL[SIoBB?DL[SIsIoC?sCnCC]DL[C]nnI]", ATTACH,
+ pn_string_get(link->name),
+ state->local_handle,
+ endpoint->type == RECEIVER,
+ link->snd_settle_mode,
+ link->rcv_settle_mode,
+ (bool) link->source.type, SOURCE,
+ pn_string_get(link->source.address),
+ link->source.durability,
+ expiry_symbol(link->source.expiry_policy),
+ link->source.timeout,
+ link->source.dynamic,
+ link->source.properties,
+ (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
+ link->source.filter,
+ link->source.outcomes,
+ link->source.capabilities,
+ COORDINATOR, link->target.capabilities,
+ 0);
+ if (err) return err;
+ } else {
+ int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
+ "DL[SIoBB?DL[SIsIoC?sCnCC]?DL[SIsIoCC]nnI]", ATTACH,
+ pn_string_get(link->name),
+ state->local_handle,
+ endpoint->type == RECEIVER,
+ link->snd_settle_mode,
+ link->rcv_settle_mode,
+ (bool) link->source.type, SOURCE,
+ pn_string_get(link->source.address),
+ link->source.durability,
+ expiry_symbol(link->source.expiry_policy),
+ link->source.timeout,
+ link->source.dynamic,
+ link->source.properties,
+ (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
+ link->source.filter,
+ link->source.outcomes,
+ link->source.capabilities,
+ (bool) link->target.type, TARGET,
+ pn_string_get(link->target.address),
+ link->target.durability,
+ expiry_symbol(link->target.expiry_policy),
+ link->target.timeout,
+ link->target.dynamic,
+ link->target.properties,
+ link->target.capabilities,
+ 0);
+ if (err) return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link)
+{
+ ssn->state.incoming_window = pni_session_incoming_window(ssn);
+ ssn->state.outgoing_window = pni_session_outgoing_window(ssn);
+ bool linkq = (bool) link;
+ pn_link_state_t *state = &link->state;
+ return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[?IIII?I?I?In?o]", FLOW,
+ (int16_t) ssn->state.remote_channel >= 0, ssn->state.incoming_transfer_count,
+ ssn->state.incoming_window,
+ ssn->state.outgoing_transfer_count,
+ ssn->state.outgoing_window,
+ linkq, linkq ? state->local_handle : 0,
+ linkq, linkq ? state->delivery_count : 0,
+ linkq, linkq ? state->link_credit : 0,
+ linkq, linkq ? link->drain : false);
+}
+
+static int pni_process_flow_receiver(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == RECEIVER && endpoint->state & PN_LOCAL_ACTIVE)
+ {
+ pn_link_t *rcv = (pn_link_t *) endpoint;
+ pn_session_t *ssn = rcv->session;
+ pn_link_state_t *state = &rcv->state;
+ if ((int16_t) ssn->state.local_channel >= 0 &&
+ (int32_t) state->local_handle >= 0 &&
+ ((rcv->drain || state->link_credit != rcv->credit - rcv->queued) || !ssn->state.incoming_window)) {
+ state->link_credit = rcv->credit - rcv->queued;
+ return pni_post_flow(transport, ssn, rcv);
+ }
+ }
+
+ return 0;
+}
+
+static int pni_flush_disp(pn_transport_t *transport, pn_session_t *ssn)
+{
+ uint64_t code = ssn->state.disp_code;
+ bool settled = ssn->state.disp_settled;
+ if (ssn->state.disp) {
+ int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[oIIo?DL[]]", DISPOSITION,
+ ssn->state.disp_type, ssn->state.disp_first, ssn->state.disp_last,
+ settled, (bool)code, code);
+ if (err) return err;
+ ssn->state.disp_type = 0;
+ ssn->state.disp_code = 0;
+ ssn->state.disp_settled = 0;
+ ssn->state.disp_first = 0;
+ ssn->state.disp_last = 0;
+ ssn->state.disp = false;
+ }
+ return 0;
+}
+
+static int pni_post_disp(pn_transport_t *transport, pn_delivery_t *delivery)
+{
+ pn_link_t *link = delivery->link;
+ pn_session_t *ssn = link->session;
+ pn_session_state_t *ssn_state = &ssn->state;
+ pn_modified(transport->connection, &link->session->endpoint, false);
+ pn_delivery_state_t *state = &delivery->state;
+ assert(state->init);
+ bool role = (link->endpoint.type == RECEIVER);
+ uint64_t code = delivery->local.type;
+
+ if (!code && !delivery->local.settled) {
+ return 0;
+ }
+
+ if (!pni_disposition_batchable(&delivery->local)) {
+ pn_data_clear(transport->disp_data);
+ PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
+ return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel,
+ "DL[oIIo?DLC]", DISPOSITION,
+ role, state->id, state->id, delivery->local.settled,
+ (bool)code, code, transport->disp_data);
+ }
+
+ if (ssn_state->disp && code == ssn_state->disp_code &&
+ delivery->local.settled == ssn_state->disp_settled &&
+ ssn_state->disp_type == role) {
+ if (state->id == ssn_state->disp_first - 1) {
+ ssn_state->disp_first = state->id;
+ return 0;
+ } else if (state->id == ssn_state->disp_last + 1) {
+ ssn_state->disp_last = state->id;
+ return 0;
+ }
+ }
+
+ if (ssn_state->disp) {
+ int err = pni_flush_disp(transport, ssn);
+ if (err) return err;
+ }
+
+ ssn_state->disp_type = role;
+ ssn_state->disp_code = code;
+ ssn_state->disp_settled = delivery->local.settled;
+ ssn_state->disp_first = state->id;
+ ssn_state->disp_last = state->id;
+ ssn_state->disp = true;
+
+ return 0;
+}
+
+static int pni_process_tpwork_sender(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
+{
+ *settle = false;
+ pn_link_t *link = delivery->link;
+ pn_session_state_t *ssn_state = &link->session->state;
+ pn_link_state_t *link_state = &link->state;
+ bool xfr_posted = false;
+ if ((int16_t) ssn_state->local_channel >= 0 && (int32_t) link_state->local_handle >= 0) {
+ pn_delivery_state_t *state = &delivery->state;
+ if (!state->sent && (delivery->done || pn_buffer_size(delivery->bytes) > 0) &&
+ ssn_state->remote_incoming_window > 0 && link_state->link_credit > 0) {
+ if (!state->init) {
+ state = pni_delivery_map_push(&ssn_state->outgoing, delivery);
+ }
+
+ pn_bytes_t bytes = pn_buffer_bytes(delivery->bytes);
+ size_t full_size = bytes.size;
+ pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
+ pn_data_clear(transport->disp_data);
+ PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
+ int count = pni_post_amqp_transfer_frame(transport,
+ ssn_state->local_channel,
+ link_state->local_handle,
+ state->id, &bytes, &tag,
+ 0, // message-format
+ delivery->local.settled,
+ !delivery->done,
+ ssn_state->remote_incoming_window,
+ delivery->local.type, transport->disp_data);
+ if (count < 0) return count;
+ xfr_posted = true;
+ ssn_state->outgoing_transfer_count += count;
+ ssn_state->remote_incoming_window -= count;
+
+ int sent = full_size - bytes.size;
+ pn_buffer_trim(delivery->bytes, sent, 0);
+ link->session->outgoing_bytes -= sent;
+ if (!pn_buffer_size(delivery->bytes) && delivery->done) {
+ state->sent = true;
+ link_state->delivery_count++;
+ link_state->link_credit--;
+ link->queued--;
+ link->session->outgoing_deliveries--;
+ }
+
+ pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
+ }
+ }
+
+ pn_delivery_state_t *state = delivery->state.init ? &delivery->state : NULL;
+ if ((int16_t) ssn_state->local_channel >= 0 && !delivery->remote.settled
+ && state && state->sent && !xfr_posted) {
+ int err = pni_post_disp(transport, delivery);
+ if (err) return err;
+ }
+
+ *settle = delivery->local.settled && state && state->sent;
+ return 0;
+}
+
+static int pni_process_tpwork_receiver(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
+{
+ *settle = false;
+ pn_link_t *link = delivery->link;
+ // XXX: need to prevent duplicate disposition sending
+ pn_session_t *ssn = link->session;
+ if ((int16_t) ssn->state.local_channel >= 0 && !delivery->remote.settled && delivery->state.init) {
+ int err = pni_post_disp(transport, delivery);
+ if (err) return err;
+ }
+
+ // XXX: need to centralize this policy and improve it
+ if (!ssn->state.incoming_window) {
+ int err = pni_post_flow(transport, ssn, link);
+ if (err) return err;
+ }
+
+ *settle = delivery->local.settled;
+ return 0;
+}
+
+static int pni_process_tpwork(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == CONNECTION && !transport->close_sent)
+ {
+ pn_connection_t *conn = (pn_connection_t *) endpoint;
+ pn_delivery_t *delivery = conn->tpwork_head;
+ while (delivery)
+ {
+ pn_delivery_t *tp_next = delivery->tpwork_next;
+ bool settle = false;
+
+ pn_link_t *link = delivery->link;
+ pn_delivery_map_t *dm = NULL;
+ if (pn_link_is_sender(link)) {
+ dm = &link->session->state.outgoing;
+ int err = pni_process_tpwork_sender(transport, delivery, &settle);
+ if (err) return err;
+ } else {
+ dm = &link->session->state.incoming;
+ int err = pni_process_tpwork_receiver(transport, delivery, &settle);
+ if (err) return err;
+ }
+
+ if (settle) {
+ pn_full_settle(dm, delivery);
+ } else if (!pn_delivery_buffered(delivery)) {
+ pn_clear_tpwork(delivery);
+ }
+
+ delivery = tp_next;
+ }
+ }
+
+ return 0;
+}
+
+static int pni_process_flush_disp(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == SESSION) {
+ pn_session_t *session = (pn_session_t *) endpoint;
+ pn_session_state_t *state = &session->state;
+ if ((int16_t) state->local_channel >= 0 && !transport->close_sent)
+ {
+ int err = pni_flush_disp(transport, session);
+ if (err) return err;
+ }
+ }
+
+ return 0;
+}
+
+static int pni_process_flow_sender(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == SENDER && endpoint->state & PN_LOCAL_ACTIVE)
+ {
+ pn_link_t *snd = (pn_link_t *) endpoint;
+ pn_session_t *ssn = snd->session;
+ pn_link_state_t *state = &snd->state;
+ if ((int16_t) ssn->state.local_channel >= 0 &&
+ (int32_t) state->local_handle >= 0 &&
+ snd->drain && snd->drained) {
+ pn_delivery_t *tail = snd->unsettled_tail;
+ if (!tail || !pn_delivery_buffered(tail)) {
+ state->delivery_count += state->link_credit;
+ state->link_credit = 0;
+ snd->drained = 0;
+ return pni_post_flow(transport, ssn, snd);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void pni_unmap_local_handle(pn_link_t *link) {
+ pn_link_state_t *state = &link->state;
+ uintptr_t handle = state->local_handle;
+ state->local_handle = -2;
+ if (pn_hash_get(link->session->state.local_handles, handle)) {
+ pn_ep_decref(&link->endpoint);
+ }
+ // may delete link
+ pn_hash_del(link->session->state.local_handles, handle);
+}
+
+static int pni_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == SENDER || endpoint->type == RECEIVER)
+ {
+ pn_link_t *link = (pn_link_t *) endpoint;
+ pn_session_t *session = link->session;
+ pn_session_state_t *ssn_state = &session->state;
+ pn_link_state_t *state = &link->state;
+ if (((endpoint->state & PN_LOCAL_CLOSED) || link->detached) && (int32_t) state->local_handle >= 0 &&
+ (int16_t) ssn_state->local_channel >= 0 && !transport->close_sent) {
+ if (pn_link_is_sender(link) && pn_link_queued(link) &&
+ (int32_t) state->remote_handle != -2 &&
+ (int16_t) ssn_state->remote_channel != -2 &&
+ !transport->close_rcvd) return 0;
+
+ const char *name = NULL;
+ const char *description = NULL;
+ pn_data_t *info = NULL;
+
+ if (pn_condition_is_set(&endpoint->condition)) {
+ name = pn_condition_get_name(&endpoint->condition);
+ description = pn_condition_get_description(&endpoint->condition);
+ info = pn_condition_info(&endpoint->condition);
+ }
+
+ int err =
+ pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
+ "DL[Io?DL[sSC]]", DETACH, state->local_handle, !link->detached,
+ (bool)name, ERROR, name, description, info);
+ if (err) return err;
+ pni_unmap_local_handle(link);
+ }
+
+ pn_clear_modified(transport->connection, endpoint);
+ }
+
+ return 0;
+}
+
+static bool pni_pointful_buffering(pn_transport_t *transport, pn_session_t *session)
+{
+ if (transport->close_rcvd) return false;
+ if (!transport->open_rcvd) return true;
+
+ pn_connection_t *conn = transport->connection;
+ pn_link_t *link = pn_link_head(conn, 0);
+ while (link) {
+ if (pn_link_is_sender(link) && pn_link_queued(link) > 0) {
+ pn_session_t *ssn = link->session;
+ if (session && session == ssn) {
+ if ((int32_t) link->state.remote_handle != -2 &&
+ (int16_t) session->state.remote_channel != -2) {
+ return true;
+ }
+ }
+ }
+ link = pn_link_next(link, 0);
+ }
+
+ return false;
+}
+
+static void pni_unmap_local_channel(pn_session_t *ssn) {
+ // XXX: should really update link state also
+ pni_delivery_map_clear(&ssn->state.outgoing);
+ pni_transport_unbind_handles(ssn->state.local_handles, false);
+ pn_transport_t *transport = ssn->connection->transport;
+ pn_session_state_t *state = &ssn->state;
+ uintptr_t channel = state->local_channel;
+ state->local_channel = -2;
+ if (pn_hash_get(transport->local_channels, channel)) {
+ pn_ep_decref(&ssn->endpoint);
+ }
+ // may delete session
+ pn_hash_del(transport->local_channels, channel);
+}
+
+static int pni_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == SESSION)
+ {
+ pn_session_t *session = (pn_session_t *) endpoint;
+ pn_session_state_t *state = &session->state;
+ if (endpoint->state & PN_LOCAL_CLOSED && (int16_t) state->local_channel >= 0
+ && !transport->close_sent)
+ {
+ if (pni_pointful_buffering(transport, session)) {
+ return 0;
+ }
+
+ const char *name = NULL;
+ const char *description = NULL;
+ pn_data_t *info = NULL;
+
+ if (pn_condition_is_set(&endpoint->condition)) {
+ name = pn_condition_get_name(&endpoint->condition);
+ description = pn_condition_get_description(&endpoint->condition);
+ info = pn_condition_info(&endpoint->condition);
+ }
+
+ int err = pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?DL[sSC]]", END,
+ (bool) name, ERROR, name, description, info);
+ if (err) return err;
+ pni_unmap_local_channel(session);
+ }
+
+ pn_clear_modified(transport->connection, endpoint);
+ }
+ return 0;
+}
+
+static int pni_process_conn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+ if (endpoint->type == CONNECTION)
+ {
+ if (endpoint->state & PN_LOCAL_CLOSED && !transport->close_sent) {
+ if (pni_pointful_buffering(transport, NULL)) return 0;
+ int err = pni_post_close(transport, NULL);
+ if (err) return err;
+ transport->close_sent = true;
+ }
+
+ pn_clear_modified(transport->connection, endpoint);
+ }
+ return 0;
+}
+
+static int pni_phase(pn_transport_t *transport, int (*phase)(pn_transport_t *, pn_endpoint_t *))
+{
+ pn_connection_t *conn = transport->connection;
+ pn_endpoint_t *endpoint = conn->transport_head;
+ while (endpoint)
+ {
+ pn_endpoint_t *next = endpoint->transport_next;
+ int err = phase(transport, endpoint);
+ if (err) return err;
+ endpoint = next;
+ }
+ return 0;
+}
+
+static int pni_process(pn_transport_t *transport)
+{
+ int err;
+ if ((err = pni_phase(transport, pni_process_conn_setup))) return err;
+ if ((err = pni_phase(transport, pni_process_ssn_setup))) return err;
+ if ((err = pni_phase(transport, pni_process_link_setup))) return err;
+ if ((err = pni_phase(transport, pni_process_flow_receiver))) return err;
+
+ // XXX: this has to happen two times because we might settle stuff
+ // on the first pass and create space for more work to be done on the
+ // second pass
+ if ((err = pni_phase(transport, pni_process_tpwork))) return err;
+ if ((err = pni_phase(transport, pni_process_tpwork))) return err;
+
+ if ((err = pni_phase(transport, pni_process_flush_disp))) return err;
+
+ if ((err = pni_phase(transport, pni_process_flow_sender))) return err;
+ if ((err = pni_phase(transport, pni_process_link_teardown))) return err;
+ if ((err = pni_phase(transport, pni_process_ssn_teardown))) return err;
+ if ((err = pni_phase(transport, pni_process_conn_teardown))) return err;
+
+ if (transport->connection->tpwork_head) {
+ pn_modified(transport->connection, &transport->connection->endpoint, false);
+ }
+
+ return 0;
+}
+
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
+
+static void pn_error_amqp(pn_transport_t* transport, unsigned int layer)
+{
+ if (!transport->close_sent) {
+ if (!transport->open_sent) {
+ pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[S]", OPEN, "");
+ }
+
+ pni_post_close(transport, &transport->condition);
+ transport->close_sent = true;
+ }
+ transport->halt = true;
+ transport->done_processing = true;
+}
+
+static ssize_t pn_input_read_amqp_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
+{
+ bool eos = pn_transport_capacity(transport)==PN_EOS;
+ pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
+ switch (protocol) {
+ case PNI_PROTOCOL_AMQP1:
+ if (transport->io_layers[layer] == &amqp_read_header_layer) {
+ transport->io_layers[layer] = &amqp_layer;
+ } else {
+ transport->io_layers[layer] = &amqp_write_header_layer;
+ }
+ if (transport->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, " <- %s", "AMQP");
+ return 8;
+ case PNI_PROTOCOL_INSUFFICIENT:
+ if (!eos) return 0;
+ /* Fallthru */
+ default:
+ break;
+ }
+ char quoted[1024];
+ pn_quote_data(quoted, 1024, bytes, available);
+ pn_do_error(transport, "amqp:connection:framing-error",
+ "%s header mismatch: %s ['%s']%s", "AMQP", pni_protocol_name(protocol), quoted,
+ !eos ? "" : " (connection aborted)");
+ return PN_EOS;
+}
+
+static ssize_t pn_input_read_amqp(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
+{
+ if (transport->close_rcvd) {
+ if (available > 0) {
+ pn_do_error(transport, "amqp:connection:framing-error", "data after close");
+ return PN_EOS;
+ }
+ }
+
+ if (!transport->close_rcvd && !available) {
+ pn_do_error(transport, "amqp:connection:framing-error", "connection aborted");
+ return PN_EOS;
+ }
+
+
+ ssize_t n = pn_dispatcher_input(transport, bytes, available, true, &transport->halt);
+ if (n < 0) {
+ //return pn_error_set(transport->error, n, "dispatch error");
+ return PN_EOS;
+ } else if (transport->close_rcvd) {
+ return PN_EOS;
+ } else {
+ return n;
+ }
+}
+
+/* process AMQP related timer events */
+static pn_timestamp_t pn_tick_amqp(pn_transport_t* transport, unsigned int layer, pn_timestamp_t now)
+{
+ pn_timestamp_t timeout = 0;
+
+ if (transport->local_idle_timeout) {
+ if (transport->dead_remote_deadline == 0 ||
+ transport->last_bytes_input != transport->bytes_input) {
+ transport->dead_remote_deadline = now + t
<TRUNCATED>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[07/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/io.c b/proton-c/src/reactor/io/windows/io.c
new file mode 100644
index 0000000..3ae6722
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/io.c
@@ -0,0 +1,459 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#define FD_SETSIZE 2048
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selector.h"
+
+#include "platform/platform.h"
+#include "iocp.h"
+#include "core/util.h"
+
+#include <proton/object.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+
+int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code)
+{
+ // Error code can be from GetLastError or WSAGetLastError,
+ char err[1024] = {0};
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL);
+ return pn_error_format(error, PN_ERR, "%s: %s", msg, err);
+}
+
+static void io_log(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fflush(stderr);
+}
+
+struct pn_io_t {
+ char host[NI_MAXHOST];
+ char serv[NI_MAXSERV];
+ pn_error_t *error;
+ bool trace;
+ bool wouldblock;
+ iocp_t *iocp;
+};
+
+void pn_io_initialize(void *obj)
+{
+ pn_io_t *io = (pn_io_t *) obj;
+ io->error = pn_error();
+ io->wouldblock = false;
+ io->trace = pn_env_bool("PN_TRACE_DRV");
+
+ /* Request WinSock 2.2 */
+ WORD wsa_ver = MAKEWORD(2, 2);
+ WSADATA unused;
+ int err = WSAStartup(wsa_ver, &unused);
+ if (err) {
+ pni_win32_error(io->error, "WSAStartup", WSAGetLastError());
+ fprintf(stderr, "Can't load WinSock: %s\n", pn_error_text(io->error));
+ }
+ io->iocp = pni_iocp();
+}
+
+void pn_io_finalize(void *obj)
+{
+ pn_io_t *io = (pn_io_t *) obj;
+ pn_error_free(io->error);
+ pn_free(io->iocp);
+ WSACleanup();
+}
+
+#define pn_io_hashcode NULL
+#define pn_io_compare NULL
+#define pn_io_inspect
+
+pn_io_t *pn_io(void)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_io);
+ pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
+ return io;
+}
+
+void pn_io_free(pn_io_t *io)
+{
+ pn_free(io);
+}
+
+pn_error_t *pn_io_error(pn_io_t *io)
+{
+ assert(io);
+ return io->error;
+}
+
+static void ensure_unique(pn_io_t *io, pn_socket_t new_socket)
+{
+ // A brand new socket can have the same HANDLE value as a previous
+ // one after a socketclose. If the application closes one itself
+ // (i.e. not using pn_close), we don't find out about it until here.
+ iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, new_socket);
+ if (iocpd) {
+ if (io->trace)
+ io_log("Stale external socket reference discarded\n");
+ // Re-use means former socket instance was closed
+ assert(iocpd->ops_in_progress == 0);
+ assert(iocpd->external);
+ // Clean up the straggler as best we can
+ pn_socket_t sock = iocpd->socket;
+ iocpd->socket = INVALID_SOCKET;
+ pni_iocpdesc_map_del(io->iocp, sock); // may free the iocpdesc_t depending on refcount
+ }
+}
+
+
+/*
+ * This heavyweight surrogate pipe could be replaced with a normal Windows pipe
+ * now that select() is no longer used. If interrupt semantics are all that is
+ * needed, a simple user space counter and reserved completion status would
+ * probably suffice.
+ */
+static int pni_socket_pair(pn_io_t *io, SOCKET sv[2]);
+
+int pn_pipe(pn_io_t *io, pn_socket_t *dest)
+{
+ int n = pni_socket_pair(io, dest);
+ if (n) {
+ pni_win32_error(io->error, "pipe", WSAGetLastError());
+ }
+ return n;
+}
+
+static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
+ //
+ // Disable the Nagle algorithm on TCP connections.
+ //
+ int flag = 1;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) != 0) {
+ perror("setsockopt");
+ }
+
+ u_long nonblock = 1;
+ if (ioctlsocket(sock, FIONBIO, &nonblock)) {
+ perror("ioctlsocket");
+ }
+}
+
+static inline pn_socket_t pni_create_socket(int domain, int protocol);
+
+static const char *amqp_service(const char *port) {
+ // Help older Windows to know about amqp[s] ports
+ if (port) {
+ if (!strcmp("amqp", port)) return "5672";
+ if (!strcmp("amqps", port)) return "5671";
+ }
+ return port;
+}
+
+pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
+{
+ struct addrinfo *addr;
+ int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
+ if (code) {
+ pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
+ return INVALID_SOCKET;
+ }
+
+ pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
+ if (sock == INVALID_SOCKET) {
+ pni_win32_error(io->error, "pni_create_socket", WSAGetLastError());
+ return INVALID_SOCKET;
+ }
+ ensure_unique(io, sock);
+
+ bool optval = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *) &optval,
+ sizeof(optval)) == -1) {
+ pni_win32_error(io->error, "setsockopt", WSAGetLastError());
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+
+ if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
+ pni_win32_error(io->error, "bind", WSAGetLastError());
+ freeaddrinfo(addr);
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+ freeaddrinfo(addr);
+
+ if (listen(sock, 50) == -1) {
+ pni_win32_error(io->error, "listen", WSAGetLastError());
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+
+ if (io->iocp->selector) {
+ iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
+ if (!iocpd) {
+ pn_i_error_from_errno(io->error, "register");
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+ pni_iocpdesc_start(iocpd);
+ }
+
+ return sock;
+}
+
+pn_socket_t pn_connect(pn_io_t *io, const char *hostarg, const char *port)
+{
+ // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets
+ const char *host = strcmp("0.0.0.0", hostarg) ? hostarg : "127.0.0.1";
+
+ struct addrinfo *addr;
+ int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
+ if (code) {
+ pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
+ return INVALID_SOCKET;
+ }
+
+ pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
+ if (sock == INVALID_SOCKET) {
+ pni_win32_error(io->error, "proton pni_create_socket", WSAGetLastError());
+ freeaddrinfo(addr);
+ return INVALID_SOCKET;
+ }
+
+ ensure_unique(io, sock);
+ pn_configure_sock(io, sock);
+
+ if (io->iocp->selector) {
+ return pni_iocp_begin_connect(io->iocp, sock, addr, io->error);
+ } else {
+ if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
+ if (WSAGetLastError() != WSAEWOULDBLOCK) {
+ pni_win32_error(io->error, "connect", WSAGetLastError());
+ freeaddrinfo(addr);
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+ }
+
+ freeaddrinfo(addr);
+ return sock;
+ }
+}
+
+pn_socket_t pn_accept(pn_io_t *io, pn_socket_t listen_sock, char *name, size_t size)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ iocpdesc_t *listend = pni_iocpdesc_map_get(io->iocp, listen_sock);
+ pn_socket_t accept_sock;
+
+ *name = '\0';
+ if (listend)
+ accept_sock = pni_iocp_end_accept(listend, (struct sockaddr *) &addr, &addrlen, &io->wouldblock, io->error);
+ else {
+ // User supplied socket
+ accept_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen);
+ if (accept_sock == INVALID_SOCKET)
+ pni_win32_error(io->error, "sync accept", WSAGetLastError());
+ }
+
+ if (accept_sock == INVALID_SOCKET)
+ return accept_sock;
+
+ int code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
+ io->serv, NI_MAXSERV, 0);
+ if (code)
+ code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
+ io->serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (code) {
+ pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
+ pn_close(io, accept_sock);
+ return INVALID_SOCKET;
+ } else {
+ pn_configure_sock(io, accept_sock);
+ pni_snprintf(name, size, "%s:%s", io->host, io->serv);
+ if (listend) {
+ pni_iocpdesc_start(pni_iocpdesc_map_get(io->iocp, accept_sock));
+ }
+ return accept_sock;
+ }
+}
+
+static inline pn_socket_t pni_create_socket(int domain, int protocol) {
+ return socket(domain, SOCK_STREAM, protocol);
+}
+
+ssize_t pn_send(pn_io_t *io, pn_socket_t sockfd, const void *buf, size_t len) {
+ ssize_t count;
+ iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, sockfd);
+ if (iocpd) {
+ count = pni_iocp_begin_write(iocpd, buf, len, &io->wouldblock, io->error);
+ } else {
+ count = send(sockfd, (const char *) buf, len, 0);
+ io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+ }
+ return count;
+}
+
+ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+ ssize_t count;
+ iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
+ if (iocpd) {
+ count = pni_iocp_recv(iocpd, buf, size, &io->wouldblock, io->error);
+ } else {
+ count = recv(socket, (char *) buf, size, 0);
+ io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+ }
+ return count;
+}
+
+ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
+{
+ // non-socket io is mapped to socket io for now. See pn_pipe()
+ return pn_send(io, socket, buf, size);
+}
+
+ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+ return pn_recv(io, socket, buf, size);
+}
+
+void pn_close(pn_io_t *io, pn_socket_t socket)
+{
+ iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
+ if (iocpd)
+ pni_iocp_begin_close(iocpd);
+ else {
+ closesocket(socket);
+ }
+}
+
+bool pn_wouldblock(pn_io_t *io)
+{
+ return io->wouldblock;
+}
+
+pn_selector_t *pn_io_selector(pn_io_t *io)
+{
+ if (io->iocp->selector == NULL)
+ io->iocp->selector = pni_selector_create(io->iocp);
+ return io->iocp->selector;
+}
+
+static void configure_pipe_socket(pn_io_t *io, pn_socket_t sock)
+{
+ u_long v = 1;
+ ioctlsocket (sock, FIONBIO, &v);
+ ensure_unique(io, sock);
+ iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
+ pni_iocpdesc_start(iocpd);
+}
+
+
+static int pni_socket_pair (pn_io_t *io, SOCKET sv[2]) {
+ // no socketpair on windows. provide pipe() semantics using sockets
+ struct protoent * pe_tcp = getprotobyname("tcp");
+ if (pe_tcp == NULL) {
+ perror("getprotobyname");
+ return -1;
+ }
+
+ SOCKET sock = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto);
+ if (sock == INVALID_SOCKET) {
+ perror("socket");
+ return -1;
+ }
+
+ BOOL b = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &b, sizeof(b)) == -1) {
+ perror("setsockopt");
+ closesocket(sock);
+ return -1;
+ }
+ else {
+ struct sockaddr_in addr = {0};
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ perror("bind");
+ closesocket(sock);
+ return -1;
+ }
+ }
+
+ if (listen(sock, 50) == -1) {
+ perror("listen");
+ closesocket(sock);
+ return -1;
+ }
+
+ if ((sv[1] = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto)) == INVALID_SOCKET) {
+ perror("sock1");
+ closesocket(sock);
+ return -1;
+ }
+ else {
+ struct sockaddr addr = {0};
+ int l = sizeof(addr);
+ if (getsockname(sock, &addr, &l) == -1) {
+ perror("getsockname");
+ closesocket(sock);
+ return -1;
+ }
+
+ if (connect(sv[1], &addr, sizeof(addr)) == -1) {
+ int err = WSAGetLastError();
+ fprintf(stderr, "connect wsaerrr %d\n", err);
+ closesocket(sock);
+ closesocket(sv[1]);
+ return -1;
+ }
+
+ if ((sv[0] = accept(sock, &addr, &l)) == INVALID_SOCKET) {
+ perror("accept");
+ closesocket(sock);
+ closesocket(sv[1]);
+ return -1;
+ }
+ }
+
+ configure_pipe_socket(io, sv[0]);
+ configure_pipe_socket(io, sv[1]);
+ closesocket(sock);
+ return 0;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/iocp.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/iocp.c b/proton-c/src/reactor/io/windows/iocp.c
new file mode 100644
index 0000000..8a1a64a
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/iocp.c
@@ -0,0 +1,1179 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selector.h"
+
+#include "iocp.h"
+#include "platform/platform.h"
+#include "core/util.h"
+
+#include <proton/object.h>
+#include <proton/error.h>
+#include <proton/transport.h>
+
+#include <assert.h>
+
+/*
+ * Windows IO Completion Port support for Proton.
+ *
+ * Overlapped writes are used to avoid lengthy stalls between write
+ * completion and starting a new write. Non-overlapped reads are used
+ * since Windows accumulates inbound traffic without stalling and
+ * managing read buffers would not avoid a memory copy at the pn_read
+ * boundary.
+ *
+ * A socket must not get a Windows closesocket() unless the
+ * application has called pn_close on the socket or a global
+ * pn_io_finalize(). On error, the internal accounting for
+ * write_closed or read_closed may be updated along with the external
+ * event notification. A socket may be closed if it is never added to
+ * the iocpdesc_map or is on its way out of the map.
+ */
+
+// Max number of overlapped accepts per listener
+#define IOCP_MAX_ACCEPTS 10
+
+// AcceptEx squishes the local and remote addresses and optional data
+// all together when accepting the connection. Reserve enough for
+// IPv6 addresses, even if the socket is IPv4. The 16 bytes padding
+// per address is required by AcceptEx.
+#define IOCP_SOCKADDRMAXLEN (sizeof(sockaddr_in6) + 16)
+#define IOCP_SOCKADDRBUFLEN (2 * IOCP_SOCKADDRMAXLEN)
+
+static void iocp_log(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fflush(stderr);
+}
+
+static void set_iocp_error_status(pn_error_t *error, int code, HRESULT status)
+{
+ char buf[512];
+ if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, status, 0, buf, sizeof(buf), 0))
+ pn_error_set(error, code, buf);
+ else {
+ fprintf(stderr, "pn internal Windows error: %lu\n", GetLastError());
+ }
+}
+
+static void reap_check(iocpdesc_t *);
+static void bind_to_completion_port(iocpdesc_t *iocpd);
+static void iocp_shutdown(iocpdesc_t *iocpd);
+static void start_reading(iocpdesc_t *iocpd);
+static bool is_listener(iocpdesc_t *iocpd);
+static void release_sys_sendbuf(SOCKET s);
+
+static void iocpdesc_fail(iocpdesc_t *iocpd, HRESULT status, const char* text)
+{
+ pni_win32_error(iocpd->error, text, status);
+ if (iocpd->iocp->iocp_trace) {
+ iocp_log("connection terminated: %s\n", pn_error_text(iocpd->error));
+ }
+ iocpd->write_closed = true;
+ iocpd->read_closed = true;
+ iocpd->poll_error = true;
+ pni_events_update(iocpd, iocpd->events & ~(PN_READABLE | PN_WRITABLE));
+}
+
+// Helper functions to use specialized IOCP AcceptEx() and ConnectEx()
+static LPFN_ACCEPTEX lookup_accept_ex(SOCKET s)
+{
+ GUID guid = WSAID_ACCEPTEX;
+ DWORD bytes = 0;
+ LPFN_ACCEPTEX fn;
+ WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+ &fn, sizeof(fn), &bytes, NULL, NULL);
+ assert(fn);
+ return fn;
+}
+
+static LPFN_CONNECTEX lookup_connect_ex(SOCKET s)
+{
+ GUID guid = WSAID_CONNECTEX;
+ DWORD bytes = 0;
+ LPFN_CONNECTEX fn;
+ WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+ &fn, sizeof(fn), &bytes, NULL, NULL);
+ assert(fn);
+ return fn;
+}
+
+static LPFN_GETACCEPTEXSOCKADDRS lookup_get_accept_ex_sockaddrs(SOCKET s)
+{
+ GUID guid = WSAID_GETACCEPTEXSOCKADDRS;
+ DWORD bytes = 0;
+ LPFN_GETACCEPTEXSOCKADDRS fn;
+ WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+ &fn, sizeof(fn), &bytes, NULL, NULL);
+ assert(fn);
+ return fn;
+}
+
+// match accept socket to listener socket
+static iocpdesc_t *create_same_type_socket(iocpdesc_t *iocpd)
+{
+ sockaddr_storage sa;
+ socklen_t salen = sizeof(sa);
+ if (getsockname(iocpd->socket, (sockaddr*)&sa, &salen) == -1)
+ return NULL;
+ SOCKET s = socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM
+ if (s == INVALID_SOCKET)
+ return NULL;
+ return pni_iocpdesc_create(iocpd->iocp, s, false);
+}
+
+static bool is_listener(iocpdesc_t *iocpd)
+{
+ return iocpd && iocpd->acceptor;
+}
+
+// === Async accept processing
+
+typedef struct {
+ iocp_result_t base;
+ iocpdesc_t *new_sock;
+ char address_buffer[IOCP_SOCKADDRBUFLEN];
+ DWORD unused;
+} accept_result_t;
+
+static accept_result_t *accept_result(iocpdesc_t *listen_sock) {
+ accept_result_t *result = (accept_result_t *)calloc(1, sizeof(accept_result_t));
+ if (result) {
+ result->base.type = IOCP_ACCEPT;
+ result->base.iocpd = listen_sock;
+ }
+ return result;
+}
+
+static void reset_accept_result(accept_result_t *result) {
+ memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+ memset(&result->address_buffer, 0, IOCP_SOCKADDRBUFLEN);
+}
+
+struct pni_acceptor_t {
+ int accept_queue_size;
+ pn_list_t *accepts;
+ iocpdesc_t *listen_sock;
+ bool signalled;
+ LPFN_ACCEPTEX fn_accept_ex;
+ LPFN_GETACCEPTEXSOCKADDRS fn_get_accept_ex_sockaddrs;
+};
+
+#define pni_acceptor_compare NULL
+#define pni_acceptor_inspect NULL
+#define pni_acceptor_hashcode NULL
+
+static void pni_acceptor_initialize(void *object)
+{
+ pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
+ acceptor->accepts = pn_list(PN_VOID, IOCP_MAX_ACCEPTS);
+}
+
+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);
+}
+
+static pni_acceptor_t *pni_acceptor(iocpdesc_t *iocpd)
+{
+ static const pn_cid_t CID_pni_acceptor = CID_pn_void;
+ static const pn_class_t clazz = PN_CLASS(pni_acceptor);
+ pni_acceptor_t *acceptor = (pni_acceptor_t *) pn_class_new(&clazz, sizeof(pni_acceptor_t));
+ acceptor->listen_sock = iocpd;
+ acceptor->accept_queue_size = 0;
+ acceptor->signalled = false;
+ pn_socket_t sock = acceptor->listen_sock->socket;
+ acceptor->fn_accept_ex = lookup_accept_ex(sock);
+ acceptor->fn_get_accept_ex_sockaddrs = lookup_get_accept_ex_sockaddrs(sock);
+ return acceptor;
+}
+
+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");
+ }
+}
+
+static void complete_accept(accept_result_t *result, HRESULT status)
+{
+ result->new_sock->ops_in_progress--;
+ iocpdesc_t *ld = result->base.iocpd;
+ if (ld->read_closed) {
+ if (!result->new_sock->closing)
+ pni_iocp_begin_close(result->new_sock);
+ free(result); // discard
+ reap_check(ld);
+ } else {
+ result->base.status = status;
+ pn_list_add(ld->acceptor->accepts, result);
+ pni_events_update(ld, ld->events | PN_READABLE);
+ }
+}
+
+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;
+}
+
+
+// === Async connect processing
+
+typedef struct {
+ iocp_result_t base;
+ char address_buffer[IOCP_SOCKADDRBUFLEN];
+ struct addrinfo *addrinfo;
+} connect_result_t;
+
+#define connect_result_initialize NULL
+#define connect_result_compare NULL
+#define connect_result_inspect NULL
+#define connect_result_hashcode NULL
+
+static void connect_result_finalize(void *object)
+{
+ connect_result_t *result = (connect_result_t *) object;
+ // Do not release addrinfo until ConnectEx completes
+ if (result->addrinfo)
+ freeaddrinfo(result->addrinfo);
+}
+
+static connect_result_t *connect_result(iocpdesc_t *iocpd, struct addrinfo *addr) {
+ static const pn_cid_t CID_connect_result = CID_pn_void;
+ static const pn_class_t clazz = PN_CLASS(connect_result);
+ connect_result_t *result = (connect_result_t *) pn_class_new(&clazz, sizeof(connect_result_t));
+ if (result) {
+ memset(result, 0, sizeof(connect_result_t));
+ result->base.type = IOCP_CONNECT;
+ result->base.iocpd = iocpd;
+ result->addrinfo = addr;
+ }
+ return result;
+}
+
+pn_socket_t pni_iocp_begin_connect(iocp_t *iocp, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error)
+{
+ // addr lives for the duration of the async connect. Caller has passed ownership here.
+ // See connect_result_finalize().
+ // Use of Windows-specific ConnectEx() requires our socket to be "loosely" pre-bound:
+ sockaddr_storage sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.ss_family = addr->ai_family;
+ if (bind(sock, (SOCKADDR *) &sa, addr->ai_addrlen)) {
+ pni_win32_error(error, "begin async connection", WSAGetLastError());
+ if (iocp->iocp_trace)
+ iocp_log("%s\n", pn_error_text(error));
+ closesocket(sock);
+ freeaddrinfo(addr);
+ return INVALID_SOCKET;
+ }
+
+ iocpdesc_t *iocpd = pni_iocpdesc_create(iocp, sock, false);
+ bind_to_completion_port(iocpd);
+ LPFN_CONNECTEX fn_connect_ex = lookup_connect_ex(iocpd->socket);
+ connect_result_t *result = connect_result(iocpd, addr);
+ DWORD unused;
+ bool success = fn_connect_ex(iocpd->socket, result->addrinfo->ai_addr, result->addrinfo->ai_addrlen,
+ NULL, 0, &unused, (LPOVERLAPPED) result);
+ if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+ pni_win32_error(error, "ConnectEx failure", WSAGetLastError());
+ pn_free(result);
+ iocpd->write_closed = true;
+ iocpd->read_closed = true;
+ if (iocp->iocp_trace)
+ iocp_log("%s\n", pn_error_text(error));
+ } else {
+ iocpd->ops_in_progress++;
+ }
+ return sock;
+}
+
+static void complete_connect(connect_result_t *result, HRESULT status)
+{
+ iocpdesc_t *iocpd = result->base.iocpd;
+ if (iocpd->closing) {
+ pn_free(result);
+ reap_check(iocpd);
+ return;
+ }
+
+ if (status) {
+ iocpdesc_fail(iocpd, status, "Connect failure");
+ // Posix sets selectable events as follows:
+ pni_events_update(iocpd, PN_READABLE | PN_EXPIRED);
+ } else {
+ release_sys_sendbuf(iocpd->socket);
+ if (setsockopt(iocpd->socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0)) {
+ iocpdesc_fail(iocpd, WSAGetLastError(), "Internal connect failure (update context)");
+ } else {
+ pni_events_update(iocpd, PN_WRITABLE);
+ start_reading(iocpd);
+ }
+ }
+ pn_free(result);
+ return;
+}
+
+
+// === Async writes
+
+static bool write_in_progress(iocpdesc_t *iocpd)
+{
+ return pni_write_pipeline_size(iocpd->pipeline) != 0;
+}
+
+write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen)
+{
+ write_result_t *result = (write_result_t *) calloc(sizeof(write_result_t), 1);
+ if (result) {
+ result->base.type = IOCP_WRITE;
+ result->base.iocpd = iocpd;
+ result->buffer.start = buf;
+ result->buffer.size = buflen;
+ }
+ return result;
+}
+
+static int submit_write(write_result_t *result, const void *buf, size_t len)
+{
+ WSABUF wsabuf;
+ wsabuf.buf = (char *) buf;
+ wsabuf.len = len;
+ memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+ return WSASend(result->base.iocpd->socket, &wsabuf, 1, NULL, 0,
+ (LPOVERLAPPED) result, 0);
+}
+
+ssize_t pni_iocp_begin_write(iocpdesc_t *iocpd, const void *buf, size_t len, bool *would_block, pn_error_t *error)
+{
+ if (len == 0) return 0;
+ *would_block = false;
+ if (is_listener(iocpd)) {
+ set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+ return INVALID_SOCKET;
+ }
+ if (iocpd->closing) {
+ set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
+ return SOCKET_ERROR;
+ }
+ if (iocpd->write_closed) {
+ assert(pn_error_code(iocpd->error));
+ pn_error_copy(error, iocpd->error);
+ if (iocpd->iocp->iocp_trace)
+ iocp_log("write error: %s\n", pn_error_text(error));
+ return SOCKET_ERROR;
+ }
+ if (len == 0) return 0;
+ if (!(iocpd->events & PN_WRITABLE)) {
+ *would_block = true;
+ return SOCKET_ERROR;
+ }
+
+ size_t written = 0;
+ size_t requested = len;
+ const char *outgoing = (const char *) buf;
+ size_t available = pni_write_pipeline_reserve(iocpd->pipeline, len);
+ if (!available) {
+ *would_block = true;
+ return SOCKET_ERROR;
+ }
+
+ for (size_t wr_count = 0; wr_count < available; wr_count++) {
+ write_result_t *result = pni_write_pipeline_next(iocpd->pipeline);
+ assert(result);
+ result->base.iocpd = iocpd;
+ ssize_t actual_len = pn_min(len, result->buffer.size);
+ result->requested = actual_len;
+ memmove((void *)result->buffer.start, outgoing, actual_len);
+ outgoing += actual_len;
+ written += actual_len;
+ len -= actual_len;
+
+ int werror = submit_write(result, result->buffer.start, actual_len);
+ if (werror && WSAGetLastError() != ERROR_IO_PENDING) {
+ pni_write_pipeline_return(iocpd->pipeline, result);
+ iocpdesc_fail(iocpd, WSAGetLastError(), "overlapped send");
+ return SOCKET_ERROR;
+ }
+ iocpd->ops_in_progress++;
+ }
+
+ if (!pni_write_pipeline_writable(iocpd->pipeline))
+ pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
+ return written;
+}
+
+/*
+ * Note: iocp write completion is not "bytes on the wire", it is "peer
+ * acked the sent bytes". Completion can be seconds on a slow
+ * consuming peer.
+ */
+static void complete_write(write_result_t *result, DWORD xfer_count, HRESULT status)
+{
+ iocpdesc_t *iocpd = result->base.iocpd;
+ if (iocpd->closing) {
+ pni_write_pipeline_return(iocpd->pipeline, result);
+ if (!iocpd->write_closed && !write_in_progress(iocpd))
+ iocp_shutdown(iocpd);
+ reap_check(iocpd);
+ return;
+ }
+ if (status == 0 && xfer_count > 0) {
+ if (xfer_count != result->requested) {
+ // Is this recoverable? How to preserve order if multiple overlapped writes?
+ pni_write_pipeline_return(iocpd->pipeline, result);
+ iocpdesc_fail(iocpd, WSA_OPERATION_ABORTED, "Partial overlapped write on socket");
+ return;
+ } else {
+ // Success.
+ pni_write_pipeline_return(iocpd->pipeline, result);
+ if (pni_write_pipeline_writable(iocpd->pipeline))
+ pni_events_update(iocpd, iocpd->events | PN_WRITABLE);
+ return;
+ }
+ }
+ // Other error
+ pni_write_pipeline_return(iocpd->pipeline, result);
+ if (status == WSAECONNABORTED || status == WSAECONNRESET || status == WSAENOTCONN
+ || status == ERROR_NETNAME_DELETED) {
+ iocpd->write_closed = true;
+ iocpd->poll_error = true;
+ pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
+ pni_win32_error(iocpd->error, "Remote close or timeout", status);
+ } else {
+ iocpdesc_fail(iocpd, status, "IOCP async write error");
+ }
+}
+
+
+// === Async reads
+
+struct read_result_t {
+ iocp_result_t base;
+ size_t drain_count;
+ char unused_buf[1];
+};
+
+static read_result_t *read_result(iocpdesc_t *iocpd)
+{
+ read_result_t *result = (read_result_t *) calloc(sizeof(read_result_t), 1);
+ if (result) {
+ result->base.type = IOCP_READ;
+ result->base.iocpd = iocpd;
+ }
+ return result;
+}
+
+static void begin_zero_byte_read(iocpdesc_t *iocpd)
+{
+ if (iocpd->read_in_progress) return;
+ if (iocpd->read_closed) {
+ pni_events_update(iocpd, iocpd->events | PN_READABLE);
+ return;
+ }
+
+ read_result_t *result = iocpd->read_result;
+ memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+ DWORD flags = 0;
+ WSABUF wsabuf;
+ wsabuf.buf = result->unused_buf;
+ wsabuf.len = 0;
+ int rc = WSARecv(iocpd->socket, &wsabuf, 1, NULL, &flags,
+ &result->base.overlapped, 0);
+ if (rc && WSAGetLastError() != ERROR_IO_PENDING) {
+ iocpdesc_fail(iocpd, WSAGetLastError(), "IOCP read error");
+ return;
+ }
+ iocpd->ops_in_progress++;
+ iocpd->read_in_progress = true;
+}
+
+static void drain_until_closed(iocpdesc_t *iocpd) {
+ size_t max_drain = 16 * 1024;
+ char buf[512];
+ read_result_t *result = iocpd->read_result;
+ while (result->drain_count < max_drain) {
+ int rv = recv(iocpd->socket, buf, 512, 0);
+ if (rv > 0)
+ result->drain_count += rv;
+ else if (rv == 0) {
+ iocpd->read_closed = true;
+ return;
+ } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
+ // wait a little longer
+ start_reading(iocpd);
+ return;
+ }
+ else
+ break;
+ }
+ // Graceful close indication unlikely, force the issue
+ if (iocpd->iocp->iocp_trace)
+ if (result->drain_count >= max_drain)
+ iocp_log("graceful close on reader abandoned (too many chars)\n");
+ else
+ iocp_log("graceful close on reader abandoned: %d\n", WSAGetLastError());
+ iocpd->read_closed = true;
+}
+
+
+static void complete_read(read_result_t *result, DWORD xfer_count, HRESULT status)
+{
+ iocpdesc_t *iocpd = result->base.iocpd;
+ iocpd->read_in_progress = false;
+
+ if (iocpd->closing) {
+ // Application no longer reading, but we are looking for a zero length read
+ if (!iocpd->read_closed)
+ drain_until_closed(iocpd);
+ reap_check(iocpd);
+ return;
+ }
+
+ if (status == 0 && xfer_count == 0) {
+ // Success.
+ pni_events_update(iocpd, iocpd->events | PN_READABLE);
+ } else {
+ iocpdesc_fail(iocpd, status, "IOCP read complete error");
+ }
+}
+
+ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error)
+{
+ if (size == 0) return 0;
+ *would_block = false;
+ if (is_listener(iocpd)) {
+ set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+ return SOCKET_ERROR;
+ }
+ if (iocpd->closing) {
+ // Previous call to pn_close()
+ set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
+ return SOCKET_ERROR;
+ }
+ if (iocpd->read_closed) {
+ if (pn_error_code(iocpd->error))
+ pn_error_copy(error, iocpd->error);
+ else
+ set_iocp_error_status(error, PN_ERR, WSAENOTCONN);
+ return SOCKET_ERROR;
+ }
+
+ int count = recv(iocpd->socket, (char *) buf, size, 0);
+ if (count > 0) {
+ pni_events_update(iocpd, iocpd->events & ~PN_READABLE);
+ begin_zero_byte_read(iocpd);
+ return (ssize_t) count;
+ } else if (count == 0) {
+ iocpd->read_closed = true;
+ return 0;
+ }
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+ *would_block = true;
+ else {
+ set_iocp_error_status(error, PN_ERR, WSAGetLastError());
+ iocpd->read_closed = true;
+ }
+ return SOCKET_ERROR;
+}
+
+static void start_reading(iocpdesc_t *iocpd)
+{
+ begin_zero_byte_read(iocpd);
+}
+
+
+// === The iocp descriptor
+
+static void pni_iocpdesc_initialize(void *object)
+{
+ iocpdesc_t *iocpd = (iocpdesc_t *) object;
+ memset(iocpd, 0, sizeof(iocpdesc_t));
+ iocpd->socket = INVALID_SOCKET;
+}
+
+static void pni_iocpdesc_finalize(void *object)
+{
+ iocpdesc_t *iocpd = (iocpdesc_t *) object;
+ pn_free(iocpd->acceptor);
+ pn_error_free(iocpd->error);
+ if (iocpd->pipeline)
+ if (write_in_progress(iocpd))
+ iocp_log("iocp descriptor write leak\n");
+ else
+ pn_free(iocpd->pipeline);
+ if (iocpd->read_in_progress)
+ iocp_log("iocp descriptor read leak\n");
+ else
+ free(iocpd->read_result);
+}
+
+static uintptr_t pni_iocpdesc_hashcode(void *object)
+{
+ iocpdesc_t *iocpd = (iocpdesc_t *) object;
+ return iocpd->socket;
+}
+
+#define pni_iocpdesc_compare NULL
+#define pni_iocpdesc_inspect NULL
+
+// Reference counted in the iocpdesc map, zombie_list, selector.
+static iocpdesc_t *pni_iocpdesc(pn_socket_t s)
+{
+ static const pn_cid_t CID_pni_iocpdesc = CID_pn_void;
+ static pn_class_t clazz = PN_CLASS(pni_iocpdesc);
+ iocpdesc_t *iocpd = (iocpdesc_t *) pn_class_new(&clazz, sizeof(iocpdesc_t));
+ assert(iocpd);
+ iocpd->socket = s;
+ return iocpd;
+}
+
+static bool is_listener_socket(pn_socket_t s)
+{
+ BOOL tval = false;
+ int tvalsz = sizeof(tval);
+ int code = getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&tval, &tvalsz);
+ return code == 0 && tval;
+}
+
+iocpdesc_t *pni_iocpdesc_create(iocp_t *iocp, pn_socket_t s, bool external) {
+ assert (s != INVALID_SOCKET);
+ assert(!pni_iocpdesc_map_get(iocp, s));
+ bool listening = is_listener_socket(s);
+ iocpdesc_t *iocpd = pni_iocpdesc(s);
+ iocpd->iocp = iocp;
+ if (iocpd) {
+ iocpd->external = external;
+ iocpd->error = pn_error();
+ if (listening) {
+ iocpd->acceptor = pni_acceptor(iocpd);
+ } else {
+ iocpd->pipeline = pni_write_pipeline(iocpd);
+ iocpd->read_result = read_result(iocpd);
+ }
+ pni_iocpdesc_map_push(iocpd);
+ }
+ return iocpd;
+}
+
+iocpdesc_t *pni_deadline_desc(iocp_t *iocp) {
+ // Non IO descriptor for selector deadlines. Do not add to iocpdesc map or
+ // zombie list. Selector responsible to free/decref object.
+ iocpdesc_t *iocpd = pni_iocpdesc(PN_INVALID_SOCKET);
+ iocpd->iocp = iocp;
+ iocpd->deadline_desc = true;
+ return iocpd;
+}
+
+// === Fast lookup of a socket's iocpdesc_t
+
+iocpdesc_t *pni_iocpdesc_map_get(iocp_t *iocp, pn_socket_t s) {
+ iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_get(iocp->iocpdesc_map, s);
+ return iocpd;
+}
+
+void pni_iocpdesc_map_push(iocpdesc_t *iocpd) {
+ pn_hash_put(iocpd->iocp->iocpdesc_map, iocpd->socket, iocpd);
+ pn_decref(iocpd);
+ assert(pn_refcount(iocpd) == 1);
+}
+
+void pni_iocpdesc_map_del(iocp_t *iocp, pn_socket_t s) {
+ pn_hash_del(iocp->iocpdesc_map, (uintptr_t) s);
+}
+
+static void bind_to_completion_port(iocpdesc_t *iocpd)
+{
+ if (iocpd->bound) return;
+ if (!iocpd->iocp->completion_port) {
+ iocpdesc_fail(iocpd, WSAEINVAL, "Incomplete setup, no completion port.");
+ return;
+ }
+
+ if (CreateIoCompletionPort ((HANDLE) iocpd->socket, iocpd->iocp->completion_port, 0, 0))
+ iocpd->bound = true;
+ else {
+ iocpdesc_fail(iocpd, GetLastError(), "IOCP socket setup.");
+ }
+}
+
+static void release_sys_sendbuf(SOCKET s)
+{
+ // Set the socket's send buffer size to zero.
+ int sz = 0;
+ int status = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char *)&sz, sizeof(int));
+ assert(status == 0);
+}
+
+void pni_iocpdesc_start(iocpdesc_t *iocpd)
+{
+ if (iocpd->bound) return;
+ bind_to_completion_port(iocpd);
+ if (is_listener(iocpd)) {
+ begin_accept(iocpd->acceptor, NULL);
+ }
+ else {
+ release_sys_sendbuf(iocpd->socket);
+ pni_events_update(iocpd, PN_WRITABLE);
+ start_reading(iocpd);
+ }
+}
+
+static void complete(iocp_result_t *result, bool success, DWORD num_transferred) {
+ result->iocpd->ops_in_progress--;
+ DWORD status = success ? 0 : GetLastError();
+
+ switch (result->type) {
+ case IOCP_ACCEPT:
+ complete_accept((accept_result_t *) result, status);
+ break;
+ case IOCP_CONNECT:
+ complete_connect((connect_result_t *) result, status);
+ break;
+ case IOCP_WRITE:
+ complete_write((write_result_t *) result, num_transferred, status);
+ break;
+ case IOCP_READ:
+ complete_read((read_result_t *) result, num_transferred, status);
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void pni_iocp_drain_completions(iocp_t *iocp)
+{
+ while (true) {
+ DWORD timeout_ms = 0;
+ DWORD num_transferred = 0;
+ ULONG_PTR completion_key = 0;
+ OVERLAPPED *overlapped = 0;
+
+ bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
+ &completion_key, &overlapped, timeout_ms);
+ if (!overlapped)
+ return; // timed out
+ iocp_result_t *result = (iocp_result_t *) overlapped;
+ complete(result, good_op, num_transferred);
+ }
+}
+
+// returns: -1 on error, 0 on timeout, 1 successful completion
+int pni_iocp_wait_one(iocp_t *iocp, int timeout, pn_error_t *error) {
+ DWORD win_timeout = (timeout < 0) ? INFINITE : (DWORD) timeout;
+ DWORD num_transferred = 0;
+ ULONG_PTR completion_key = 0;
+ OVERLAPPED *overlapped = 0;
+
+ bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
+ &completion_key, &overlapped, win_timeout);
+ if (!overlapped)
+ if (GetLastError() == WAIT_TIMEOUT)
+ return 0;
+ else {
+ if (error)
+ pni_win32_error(error, "GetQueuedCompletionStatus", GetLastError());
+ return -1;
+ }
+
+ iocp_result_t *result = (iocp_result_t *) overlapped;
+ complete(result, good_op, num_transferred);
+ return 1;
+}
+
+// === Close (graceful and otherwise)
+
+// zombie_list is for sockets transitioning out of iocp on their way to zero ops_in_progress
+// and fully closed.
+
+static void zombie_list_add(iocpdesc_t *iocpd)
+{
+ assert(iocpd->closing);
+ if (!iocpd->ops_in_progress) {
+ // No need to make a zombie.
+ if (iocpd->socket != INVALID_SOCKET) {
+ closesocket(iocpd->socket);
+ iocpd->socket = INVALID_SOCKET;
+ iocpd->read_closed = true;
+ }
+ return;
+ }
+ // Allow 2 seconds for graceful shutdown before releasing socket resource.
+ iocpd->reap_time = pn_i_now() + 2000;
+ pn_list_add(iocpd->iocp->zombie_list, iocpd);
+}
+
+static void reap_check(iocpdesc_t *iocpd)
+{
+ if (iocpd->closing && !iocpd->ops_in_progress) {
+ if (iocpd->socket != INVALID_SOCKET) {
+ closesocket(iocpd->socket);
+ iocpd->socket = INVALID_SOCKET;
+ }
+ pn_list_remove(iocpd->iocp->zombie_list, iocpd);
+ // iocpd is decref'ed and possibly released
+ }
+}
+
+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;
+}
+
+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
+ }
+}
+
+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");
+}
+
+static pn_list_t *iocp_map_close_all(iocp_t *iocp)
+{
+ // Zombify stragglers, i.e. no pn_close() from the application.
+ pn_list_t *externals = pn_list(PN_OBJECT, 0);
+ for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
+ entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
+ iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
+ // Just listeners first.
+ if (is_listener(iocpd)) {
+ if (iocpd->external) {
+ // Owned by application, just keep a temporary reference to it.
+ // iocp_result_t structs must not be free'd until completed or
+ // the completion port is closed.
+ if (iocpd->ops_in_progress)
+ pn_list_add(externals, iocpd);
+ pni_iocpdesc_map_del(iocp, iocpd->socket);
+ } else {
+ // Make it a zombie.
+ pni_iocp_begin_close(iocpd);
+ }
+ }
+ }
+ pni_iocp_drain_completions(iocp);
+
+ for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
+ entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
+ iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
+ if (iocpd->external) {
+ iocpd->read_closed = true; // Do not consume from read side
+ iocpd->write_closed = true; // Do not shutdown write side
+ if (iocpd->ops_in_progress)
+ pn_list_add(externals, iocpd);
+ pni_iocpdesc_map_del(iocp, iocpd->socket);
+ } else {
+ // Make it a zombie.
+ pni_iocp_begin_close(iocpd);
+ }
+ }
+ return externals;
+}
+
+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);
+}
+
+static void iocp_shutdown(iocpdesc_t *iocpd)
+{
+ if (iocpd->socket == PN_INVALID_SOCKET)
+ return; // Hard close in progress
+ if (shutdown(iocpd->socket, SD_SEND)) {
+ int err = WSAGetLastError();
+ if (err != WSAECONNABORTED && err != WSAECONNRESET && err != WSAENOTCONN)
+ if (iocpd->iocp->iocp_trace)
+ iocp_log("socket shutdown failed %d\n", err);
+ }
+ iocpd->write_closed = true;
+}
+
+void pni_iocp_begin_close(iocpdesc_t *iocpd)
+{
+ assert (!iocpd->closing);
+ if (is_listener(iocpd)) {
+ // Listening socket is easy. Close the socket which will cancel async ops.
+ pn_socket_t old_sock = iocpd->socket;
+ iocpd->socket = INVALID_SOCKET;
+ iocpd->closing = true;
+ iocpd->read_closed = true;
+ iocpd->write_closed = true;
+ closesocket(old_sock);
+ // Pending accepts will now complete. Zombie can die when all consumed.
+ zombie_list_add(iocpd);
+ pni_iocpdesc_map_del(iocpd->iocp, old_sock); // may pn_free *iocpd
+ } else {
+ // Continue async operation looking for graceful close confirmation or timeout.
+ pn_socket_t old_sock = iocpd->socket;
+ iocpd->closing = true;
+ if (!iocpd->write_closed && !write_in_progress(iocpd))
+ iocp_shutdown(iocpd);
+ zombie_list_add(iocpd);
+ pni_iocpdesc_map_del(iocpd->iocp, old_sock); // may pn_free *iocpd
+ }
+}
+
+
+// === iocp_t
+
+#define pni_iocp_hashcode NULL
+#define pni_iocp_compare NULL
+#define pni_iocp_inspect NULL
+
+void pni_iocp_initialize(void *obj)
+{
+ iocp_t *iocp = (iocp_t *) obj;
+ memset(iocp, 0, sizeof(iocp_t));
+ pni_shared_pool_create(iocp);
+ iocp->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+ assert(iocp->completion_port != NULL);
+ iocp->iocpdesc_map = pn_hash(PN_OBJECT, 0, 0.75);
+ iocp->zombie_list = pn_list(PN_OBJECT, 0);
+ iocp->iocp_trace = pn_env_bool("PN_TRACE_DRV");
+ iocp->selector = NULL;
+}
+
+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);
+}
+
+iocp_t *pni_iocp()
+{
+ static const pn_cid_t CID_pni_iocp = CID_pn_void;
+ static const pn_class_t clazz = PN_CLASS(pni_iocp);
+ iocp_t *iocp = (iocp_t *) pn_class_new(&clazz, sizeof(iocp_t));
+ return iocp;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/iocp.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/iocp.h b/proton-c/src/reactor/io/windows/iocp.h
new file mode 100644
index 0000000..07f47be
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/iocp.h
@@ -0,0 +1,136 @@
+#ifndef PROTON_SRC_IOCP_H
+#define PROTON_SRC_IOCP_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/import_export.h>
+#include <proton/selectable.h>
+#include <proton/type_compat.h>
+
+typedef struct pni_acceptor_t pni_acceptor_t;
+typedef struct write_result_t write_result_t;
+typedef struct read_result_t read_result_t;
+typedef struct write_pipeline_t write_pipeline_t;
+typedef struct iocpdesc_t iocpdesc_t;
+
+
+// One per pn_io_t.
+
+struct iocp_t {
+ HANDLE completion_port;
+ pn_hash_t *iocpdesc_map;
+ pn_list_t *zombie_list;
+ int shared_pool_size;
+ char *shared_pool_memory;
+ write_result_t **shared_results;
+ write_result_t **available_results;
+ size_t shared_available_count;
+ size_t writer_count;
+ int loopback_bufsize;
+ bool iocp_trace;
+ pn_selector_t *selector;
+};
+
+
+// One for each socket.
+// This iocpdesc_t structure is ref counted by the iocpdesc_map, zombie_list,
+// selector->iocp_descriptors list. It should remain ref counted in the
+// zombie_list until ops_in_progress == 0 or the completion port is closed.
+
+struct iocpdesc_t {
+ pn_socket_t socket;
+ iocp_t *iocp;
+ pni_acceptor_t *acceptor;
+ pn_error_t *error;
+ int ops_in_progress;
+ bool read_in_progress;
+ write_pipeline_t *pipeline;
+ read_result_t *read_result;
+ bool external; // true if socket set up outside Proton
+ bool bound; // associted with the completion port
+ bool closing; // pn_close called by application
+ bool read_closed; // EOF or read error
+ bool write_closed; // shutdown sent or write error
+ bool poll_error; // flag posix-like POLLERR/POLLHUP/POLLNVAL
+ bool deadline_desc; // Socket-less deadline descriptor for selectors
+ pn_selector_t *selector;
+ pn_selectable_t *selectable;
+ int events;
+ int interests;
+ pn_timestamp_t deadline;
+ iocpdesc_t *triggered_list_next;
+ iocpdesc_t *triggered_list_prev;
+ iocpdesc_t *deadlines_next;
+ iocpdesc_t *deadlines_prev;
+ pn_timestamp_t reap_time;;
+};
+
+typedef enum { IOCP_ACCEPT, IOCP_CONNECT, IOCP_READ, IOCP_WRITE } iocp_type_t;
+
+typedef struct {
+ OVERLAPPED overlapped;
+ iocp_type_t type;
+ iocpdesc_t *iocpd;
+ HRESULT status;
+} iocp_result_t;
+
+struct write_result_t {
+ iocp_result_t base;
+ size_t requested;
+ bool in_use;
+ pn_bytes_t buffer;
+};
+
+iocpdesc_t *pni_iocpdesc_create(iocp_t *, pn_socket_t s, bool external);
+iocpdesc_t *pni_iocpdesc_map_get(iocp_t *, pn_socket_t s);
+iocpdesc_t *pni_deadline_desc(iocp_t *);
+void pni_iocpdesc_map_del(iocp_t *, pn_socket_t s);
+void pni_iocpdesc_map_push(iocpdesc_t *iocpd);
+void pni_iocpdesc_start(iocpdesc_t *iocpd);
+void pni_iocp_drain_completions(iocp_t *);
+int pni_iocp_wait_one(iocp_t *, int timeout, pn_error_t *);
+void pni_iocp_start_accepting(iocpdesc_t *iocpd);
+pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error);
+pn_socket_t pni_iocp_begin_connect(iocp_t *, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error);
+ssize_t pni_iocp_begin_write(iocpdesc_t *, const void *, size_t, bool *, pn_error_t *);
+ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error);
+void pni_iocp_begin_close(iocpdesc_t *iocpd);
+iocp_t *pni_iocp();
+
+void pni_events_update(iocpdesc_t *iocpd, int events);
+write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen);
+write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd);
+size_t pni_write_pipeline_size(write_pipeline_t *);
+bool pni_write_pipeline_writable(write_pipeline_t *);
+void pni_write_pipeline_return(write_pipeline_t *, write_result_t *);
+size_t pni_write_pipeline_reserve(write_pipeline_t *, size_t);
+write_result_t *pni_write_pipeline_next(write_pipeline_t *);
+void pni_shared_pool_create(iocp_t *);
+void pni_shared_pool_free(iocp_t *);
+void pni_zombie_check(iocp_t *, pn_timestamp_t);
+pn_timestamp_t pni_zombie_deadline(iocp_t *);
+
+pn_selector_t *pni_selector_create(iocp_t *iocp);
+
+int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code);
+
+#endif /* iocp.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/selector.c b/proton-c/src/reactor/io/windows/selector.c
new file mode 100644
index 0000000..15da73b
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/selector.c
@@ -0,0 +1,384 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selectable.h"
+#include "reactor/selector.h"
+
+#include "iocp.h"
+#include "platform/platform.h"
+#include "core/util.h"
+
+#include <proton/object.h>
+#include <proton/error.h>
+#include <assert.h>
+
+static void interests_update(iocpdesc_t *iocpd, int interests);
+static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t t);
+
+struct pn_selector_t {
+ iocp_t *iocp;
+ pn_list_t *selectables;
+ pn_list_t *iocp_descriptors;
+ size_t current;
+ iocpdesc_t *current_triggered;
+ pn_timestamp_t awoken;
+ pn_error_t *error;
+ iocpdesc_t *triggered_list_head;
+ iocpdesc_t *triggered_list_tail;
+ iocpdesc_t *deadlines_head;
+ iocpdesc_t *deadlines_tail;
+};
+
+void pn_selector_initialize(void *obj)
+{
+ pn_selector_t *selector = (pn_selector_t *) obj;
+ selector->iocp = NULL;
+ selector->selectables = pn_list(PN_WEAKREF, 0);
+ selector->iocp_descriptors = pn_list(PN_OBJECT, 0);
+ selector->current = 0;
+ selector->current_triggered = NULL;
+ selector->awoken = 0;
+ selector->error = pn_error();
+ selector->triggered_list_head = NULL;
+ selector->triggered_list_tail = NULL;
+ selector->deadlines_head = NULL;
+ selector->deadlines_tail = NULL;
+}
+
+void pn_selector_finalize(void *obj)
+{
+ pn_selector_t *selector = (pn_selector_t *) obj;
+ pn_free(selector->selectables);
+ pn_free(selector->iocp_descriptors);
+ pn_error_free(selector->error);
+ selector->iocp->selector = NULL;
+}
+
+#define pn_selector_hashcode NULL
+#define pn_selector_compare NULL
+#define pn_selector_inspect NULL
+
+pn_selector_t *pni_selector()
+{
+ static const pn_class_t clazz = PN_CLASS(pn_selector);
+ pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
+ return selector;
+}
+
+pn_selector_t *pni_selector_create(iocp_t *iocp)
+{
+ pn_selector_t *selector = pni_selector();
+ selector->iocp = iocp;
+ return selector;
+}
+
+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);
+}
+
+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);
+ }
+}
+
+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--;
+ }
+}
+
+size_t pn_selector_size(pn_selector_t *selector) {
+ assert(selector);
+ return pn_list_size(selector->selectables);
+}
+
+int pn_selector_select(pn_selector_t *selector, int timeout)
+{
+ assert(selector);
+ pn_error_clear(selector->error);
+ pn_timestamp_t deadline = 0;
+ pn_timestamp_t now = pn_i_now();
+
+ if (timeout) {
+ if (selector->deadlines_head)
+ deadline = selector->deadlines_head->deadline;
+ }
+ if (deadline) {
+ int64_t delta = deadline - now;
+ if (delta < 0) {
+ delta = 0;
+ }
+ if (timeout < 0)
+ timeout = delta;
+ else if (timeout > delta)
+ timeout = delta;
+ }
+ deadline = (timeout >= 0) ? now + timeout : 0;
+
+ // Process all currently available completions, even if matched events available
+ pni_iocp_drain_completions(selector->iocp);
+ pni_zombie_check(selector->iocp, now);
+ // Loop until an interested event is matched, or until deadline
+ while (true) {
+ if (selector->triggered_list_head)
+ break;
+ if (deadline && deadline <= now)
+ break;
+ pn_timestamp_t completion_deadline = deadline;
+ pn_timestamp_t zd = pni_zombie_deadline(selector->iocp);
+ if (zd)
+ completion_deadline = completion_deadline ? pn_min(zd, completion_deadline) : zd;
+
+ int completion_timeout = (!completion_deadline) ? -1 : completion_deadline - now;
+ int rv = pni_iocp_wait_one(selector->iocp, completion_timeout, selector->error);
+ if (rv < 0)
+ return pn_error_code(selector->error);
+
+ now = pn_i_now();
+ if (zd && zd <= now) {
+ pni_zombie_check(selector->iocp, now);
+ }
+ }
+
+ selector->current = 0;
+ selector->awoken = now;
+ for (iocpdesc_t *iocpd = selector->deadlines_head; iocpd; iocpd = iocpd->deadlines_next) {
+ if (iocpd->deadline <= now)
+ pni_events_update(iocpd, iocpd->events | PN_EXPIRED);
+ else
+ break;
+ }
+ selector->current_triggered = selector->triggered_list_head;
+ return pn_error_code(selector->error);
+}
+
+pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
+{
+ if (selector->current_triggered) {
+ iocpdesc_t *iocpd = selector->current_triggered;
+ *events = iocpd->interests & iocpd->events;
+ selector->current_triggered = iocpd->triggered_list_next;
+ return iocpd->selectable;
+ }
+ return NULL;
+}
+
+void pn_selector_free(pn_selector_t *selector)
+{
+ assert(selector);
+ pn_free(selector);
+}
+
+
+static void triggered_list_add(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+ if (iocpd->triggered_list_prev || selector->triggered_list_head == iocpd)
+ return; // already in list
+ LL_ADD(selector, triggered_list, iocpd);
+}
+
+static void triggered_list_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+ if (!iocpd->triggered_list_prev && selector->triggered_list_head != iocpd)
+ return; // not in list
+ LL_REMOVE(selector, triggered_list, iocpd);
+ iocpd->triggered_list_prev = NULL;
+ iocpd->triggered_list_next = NULL;
+}
+
+
+void pni_events_update(iocpdesc_t *iocpd, int events)
+{
+ // If set, a poll error is permanent
+ if (iocpd->poll_error)
+ events |= PN_ERROR;
+ if (iocpd->events == events)
+ return;
+ iocpd->events = events;
+ if (iocpd->selector) {
+ if (iocpd->events & iocpd->interests)
+ triggered_list_add(iocpd->selector, iocpd);
+ else
+ triggered_list_remove(iocpd->selector, iocpd);
+ }
+}
+
+static void interests_update(iocpdesc_t *iocpd, int interests)
+{
+ int old_interests = iocpd->interests;
+ if (old_interests == interests)
+ return;
+ iocpd->interests = interests;
+ if (iocpd->selector) {
+ if (iocpd->events & iocpd->interests)
+ triggered_list_add(iocpd->selector, iocpd);
+ else
+ triggered_list_remove(iocpd->selector, iocpd);
+ }
+}
+
+static void deadlines_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+ if (!iocpd->deadlines_prev && selector->deadlines_head != iocpd)
+ return; // not in list
+ LL_REMOVE(selector, deadlines, iocpd);
+ iocpd->deadlines_prev = NULL;
+ iocpd->deadlines_next = NULL;
+}
+
+
+static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t deadline)
+{
+ if (deadline == iocpd->deadline)
+ return;
+
+ iocpd->deadline = deadline;
+ pn_selector_t *selector = iocpd->selector;
+ if (!deadline) {
+ deadlines_remove(selector, iocpd);
+ pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
+ } else {
+ if (iocpd->deadlines_prev || selector->deadlines_head == iocpd) {
+ deadlines_remove(selector, iocpd);
+ pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
+ }
+ iocpdesc_t *dl_iocpd = LL_HEAD(selector, deadlines);
+ while (dl_iocpd && dl_iocpd->deadline <= deadline)
+ dl_iocpd = dl_iocpd->deadlines_next;
+ if (dl_iocpd) {
+ // insert
+ iocpd->deadlines_prev = dl_iocpd->deadlines_prev;
+ iocpd->deadlines_next = dl_iocpd;
+ dl_iocpd->deadlines_prev = iocpd;
+ if (selector->deadlines_head == dl_iocpd)
+ selector->deadlines_head = iocpd;
+ } else {
+ LL_ADD(selector, deadlines, iocpd); // append
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/write_pipeline.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/write_pipeline.c b/proton-c/src/reactor/io/windows/write_pipeline.c
new file mode 100644
index 0000000..905c7f6
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/write_pipeline.c
@@ -0,0 +1,314 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * A simple write buffer pool. Each socket has a dedicated "primary"
+ * buffer and can borrow from a shared pool with limited size tuning.
+ * Could enhance e.g. with separate pools per network interface and fancier
+ * memory tuning based on interface speed, system resources, and
+ * number of connections, etc.
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selector.h"
+#include "reactor/selectable.h"
+
+#include "iocp.h"
+#include "core/util.h"
+
+#include <proton/error.h>
+#include <proton/object.h>
+
+#include <assert.h>
+
+// Max overlapped writes per socket
+#define IOCP_MAX_OWRITES 16
+// Write buffer size
+#define IOCP_WBUFSIZE 16384
+
+static void pipeline_log(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fflush(stderr);
+}
+
+void pni_shared_pool_create(iocp_t *iocp)
+{
+ // TODO: more pools (or larger one) when using multiple non-loopback interfaces
+ iocp->shared_pool_size = 16;
+ char *env = getenv("PNI_WRITE_BUFFERS"); // Internal: for debugging
+ if (env) {
+ int sz = atoi(env);
+ if (sz >= 0 && sz < 256) {
+ iocp->shared_pool_size = sz;
+ }
+ }
+ iocp->loopback_bufsize = 0;
+ env = getenv("PNI_LB_BUFSIZE"); // Internal: for debugging
+ if (env) {
+ int sz = atoi(env);
+ if (sz >= 0 && sz <= 128 * 1024) {
+ iocp->loopback_bufsize = sz;
+ }
+ }
+
+ if (iocp->shared_pool_size) {
+ iocp->shared_pool_memory = (char *) VirtualAlloc(NULL, IOCP_WBUFSIZE * iocp->shared_pool_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ HRESULT status = GetLastError();
+ if (!iocp->shared_pool_memory) {
+ perror("Proton write buffer pool allocation failure\n");
+ iocp->shared_pool_size = 0;
+ iocp->shared_available_count = 0;
+ return;
+ }
+
+ iocp->shared_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
+ iocp->available_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
+ iocp->shared_available_count = iocp->shared_pool_size;
+ char *mem = iocp->shared_pool_memory;
+ for (int i = 0; i < iocp->shared_pool_size; i++) {
+ iocp->shared_results[i] = iocp->available_results[i] = pni_write_result(NULL, mem, IOCP_WBUFSIZE);
+ mem += IOCP_WBUFSIZE;
+ }
+ }
+}
+
+void pni_shared_pool_free(iocp_t *iocp)
+{
+ for (int i = 0; i < iocp->shared_pool_size; i++) {
+ write_result_t *result = iocp->shared_results[i];
+ if (result->in_use)
+ pipeline_log("Proton buffer pool leak\n");
+ else
+ free(result);
+ }
+ if (iocp->shared_pool_size) {
+ free(iocp->shared_results);
+ free(iocp->available_results);
+ if (iocp->shared_pool_memory) {
+ if (!VirtualFree(iocp->shared_pool_memory, 0, MEM_RELEASE)) {
+ perror("write buffers release failed");
+ }
+ iocp->shared_pool_memory = NULL;
+ }
+ }
+}
+
+static void shared_pool_push(write_result_t *result)
+{
+ iocp_t *iocp = result->base.iocpd->iocp;
+ assert(iocp->shared_available_count < iocp->shared_pool_size);
+ iocp->available_results[iocp->shared_available_count++] = result;
+}
+
+static write_result_t *shared_pool_pop(iocp_t *iocp)
+{
+ return iocp->shared_available_count ? iocp->available_results[--iocp->shared_available_count] : NULL;
+}
+
+struct write_pipeline_t {
+ iocpdesc_t *iocpd;
+ size_t pending_count;
+ write_result_t *primary;
+ size_t reserved_count;
+ size_t next_primary_index;
+ size_t depth;
+ bool is_writer;
+};
+
+#define write_pipeline_compare NULL
+#define write_pipeline_inspect NULL
+#define write_pipeline_hashcode NULL
+
+static void write_pipeline_initialize(void *object)
+{
+ write_pipeline_t *pl = (write_pipeline_t *) object;
+ pl->pending_count = 0;
+ const char *pribuf = (const char *) malloc(IOCP_WBUFSIZE);
+ pl->primary = pni_write_result(NULL, pribuf, IOCP_WBUFSIZE);
+ pl->depth = 0;
+ pl->is_writer = false;
+}
+
+static void write_pipeline_finalize(void *object)
+{
+ write_pipeline_t *pl = (write_pipeline_t *) object;
+ free((void *)pl->primary->buffer.start);
+ free(pl->primary);
+}
+
+write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd)
+{
+ static const pn_cid_t CID_write_pipeline = CID_pn_void;
+ static const pn_class_t clazz = PN_CLASS(write_pipeline);
+ write_pipeline_t *pipeline = (write_pipeline_t *) pn_class_new(&clazz, sizeof(write_pipeline_t));
+ pipeline->iocpd = iocpd;
+ pipeline->primary->base.iocpd = iocpd;
+ return pipeline;
+}
+
+static void confirm_as_writer(write_pipeline_t *pl)
+{
+ if (!pl->is_writer) {
+ iocp_t *iocp = pl->iocpd->iocp;
+ iocp->writer_count++;
+ pl->is_writer = true;
+ }
+}
+
+static void remove_as_writer(write_pipeline_t *pl)
+{
+ if (!pl->is_writer)
+ return;
+ iocp_t *iocp = pl->iocpd->iocp;
+ assert(iocp->writer_count);
+ pl->is_writer = false;
+ iocp->writer_count--;
+}
+
+/*
+ * Optimal depth will depend on properties of the NIC, server, and driver. For now,
+ * just distinguish between loopback interfaces and the rest. Optimizations in the
+ * loopback stack allow decent performance with depth 1 and actually cause major
+ * performance hiccups if set to large values.
+ */
+static void set_depth(write_pipeline_t *pl)
+{
+ pl->depth = 1;
+ sockaddr_storage sa;
+ socklen_t salen = sizeof(sa);
+ char buf[INET6_ADDRSTRLEN];
+ DWORD buflen = sizeof(buf);
+
+ if (getsockname(pl->iocpd->socket,(sockaddr*) &sa, &salen) == 0 &&
+ getnameinfo((sockaddr*) &sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0) {
+ if ((sa.ss_family == AF_INET6 && strcmp(buf, "::1")) ||
+ (sa.ss_family == AF_INET && strncmp(buf, "127.", 4))) {
+ // not loopback
+ pl->depth = IOCP_MAX_OWRITES;
+ } else {
+ iocp_t *iocp = pl->iocpd->iocp;
+ if (iocp->loopback_bufsize) {
+ const char *p = (const char *) realloc((void *) pl->primary->buffer.start, iocp->loopback_bufsize);
+ if (p) {
+ pl->primary->buffer.start = p;
+ pl->primary->buffer.size = iocp->loopback_bufsize;
+ }
+ }
+ }
+ }
+}
+
+// Reserve as many buffers as possible for count bytes.
+size_t pni_write_pipeline_reserve(write_pipeline_t *pl, size_t count)
+{
+ if (pl->primary->in_use)
+ return 0; // I.e. io->wouldblock
+ if (!pl->depth)
+ set_depth(pl);
+ if (pl->depth == 1) {
+ // always use the primary
+ pl->reserved_count = 1;
+ pl->next_primary_index = 0;
+ return 1;
+ }
+
+ iocp_t *iocp = pl->iocpd->iocp;
+ confirm_as_writer(pl);
+ size_t wanted = (count / IOCP_WBUFSIZE);
+ if (count % IOCP_WBUFSIZE)
+ wanted++;
+ size_t pending = pl->pending_count;
+ assert(pending < pl->depth);
+ size_t bufs = pn_min(wanted, pl->depth - pending);
+ // Can draw from shared pool or the primary... but share with others.
+ size_t writers = iocp->writer_count;
+ size_t shared_count = (iocp->shared_available_count + writers - 1) / writers;
+ bufs = pn_min(bufs, shared_count + 1);
+ pl->reserved_count = pending + bufs;
+
+ if (bufs == wanted &&
+ pl->reserved_count < (pl->depth / 2) &&
+ iocp->shared_available_count > (2 * writers + bufs)) {
+ // No shortage: keep the primary as spare for future use
+ pl->next_primary_index = pl->reserved_count;
+ } else if (bufs == 1) {
+ pl->next_primary_index = pending;
+ } else {
+ // let approx 1/3 drain before replenishing
+ pl->next_primary_index = ((pl->reserved_count + 2) / 3) - 1;
+ if (pl->next_primary_index < pending)
+ pl->next_primary_index = pending;
+ }
+ return bufs;
+}
+
+write_result_t *pni_write_pipeline_next(write_pipeline_t *pl)
+{
+ size_t sz = pl->pending_count;
+ if (sz >= pl->reserved_count)
+ return NULL;
+ write_result_t *result;
+ if (sz == pl->next_primary_index) {
+ result = pl->primary;
+ } else {
+ assert(pl->iocpd->iocp->shared_available_count > 0);
+ result = shared_pool_pop(pl->iocpd->iocp);
+ }
+
+ result->in_use = true;
+ pl->pending_count++;
+ return result;
+}
+
+void pni_write_pipeline_return(write_pipeline_t *pl, write_result_t *result)
+{
+ result->in_use = false;
+ pl->pending_count--;
+ pl->reserved_count = 0;
+ if (result != pl->primary)
+ shared_pool_push(result);
+ if (pl->pending_count == 0)
+ remove_as_writer(pl);
+}
+
+bool pni_write_pipeline_writable(write_pipeline_t *pl)
+{
+ // Only writable if not full and we can guarantee a buffer:
+ return pl->pending_count < pl->depth && !pl->primary->in_use;
+}
+
+size_t pni_write_pipeline_size(write_pipeline_t *pl)
+{
+ return pl->pending_count;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/reactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/reactor.c b/proton-c/src/reactor/reactor.c
index a83a881..abf5d1e 100644
--- a/proton-c/src/reactor/reactor.c
+++ b/proton-c/src/reactor/reactor.c
@@ -19,23 +19,24 @@
*
*/
+#include "io.h"
+#include "reactor.h"
+#include "selectable.h"
+#include "platform/platform.h" // pn_i_now
+
#include <proton/object.h>
#include <proton/handlers.h>
-#include <proton/io.h>
#include <proton/event.h>
#include <proton/transport.h>
#include <proton/connection.h>
#include <proton/session.h>
#include <proton/link.h>
#include <proton/delivery.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
-#include "reactor.h"
-#include "selectable.h"
-#include "platform.h"
-
struct pn_reactor_t {
pn_record_t *attachments;
pn_io_t *io;
@@ -164,7 +165,7 @@ void pn_reactor_set_handler(pn_reactor_t *reactor, pn_handler_t *handler) {
pn_incref(reactor->handler);
}
-pn_io_t *pn_reactor_io(pn_reactor_t *reactor) {
+pn_io_t *pni_reactor_io(pn_reactor_t *reactor) {
assert(reactor);
return reactor->io;
}
@@ -389,6 +390,16 @@ bool pn_reactor_quiesced(pn_reactor_t *reactor) {
return pn_event_type(event) == PN_REACTOR_QUIESCED;
}
+pn_handler_t *pn_event_root(pn_event_t *event)
+{
+ pn_handler_t *h = pn_record_get_handler(pn_event_attachments(event));
+ return h;
+}
+
+static void pni_event_set_root(pn_event_t *event, pn_handler_t *handler) {
+ pn_record_set_handler(pn_event_attachments(event), handler);
+}
+
bool pn_reactor_process(pn_reactor_t *reactor) {
assert(reactor);
pn_reactor_mark(reactor);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/reactor.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/reactor.h b/proton-c/src/reactor/reactor.h
index 461e8b3..bfb397c 100644
--- a/proton-c/src/reactor/reactor.h
+++ b/proton-c/src/reactor/reactor.h
@@ -26,9 +26,9 @@
#include <proton/url.h>
void pni_record_init_reactor(pn_record_t *record, pn_reactor_t *reactor);
-void pni_event_set_root(pn_event_t *event, pn_handler_t *handler);
void pni_reactor_set_connection_peer_address(pn_connection_t *connection,
const char *host,
const char *port);
+pn_io_t *pni_reactor_io(pn_reactor_t *reactor);
#endif /* src/reactor.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/selectable.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/selectable.c b/proton-c/src/reactor/selectable.c
new file mode 100644
index 0000000..b42ad1f
--- /dev/null
+++ b/proton-c/src/reactor/selectable.c
@@ -0,0 +1,300 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "selectable.h"
+
+#include <proton/error.h>
+
+#include "io.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+pn_selectables_t *pn_selectables(void)
+{
+ return pn_iterator();
+}
+
+pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables)
+{
+ return (pn_selectable_t *) pn_iterator_next(selectables);
+}
+
+void pn_selectables_free(pn_selectables_t *selectables)
+{
+ pn_free(selectables);
+}
+
+struct pn_selectable_t {
+ pn_socket_t fd;
+ int index;
+ pn_record_t *attachments;
+ void (*readable)(pn_selectable_t *);
+ void (*writable)(pn_selectable_t *);
+ void (*error)(pn_selectable_t *);
+ void (*expired)(pn_selectable_t *);
+ void (*release) (pn_selectable_t *);
+ void (*finalize)(pn_selectable_t *);
+ pn_collector_t *collector;
+ pn_timestamp_t deadline;
+ bool reading;
+ bool writing;
+ bool registered;
+ bool terminal;
+};
+
+void pn_selectable_initialize(pn_selectable_t *sel)
+{
+ sel->fd = PN_INVALID_SOCKET;
+ sel->index = -1;
+ sel->attachments = pn_record();
+ sel->readable = NULL;
+ sel->writable = NULL;
+ sel->error = NULL;
+ sel->expired = NULL;
+ sel->release = NULL;
+ sel->finalize = NULL;
+ sel->collector = NULL;
+ sel->deadline = 0;
+ sel->reading = false;
+ sel->writing = false;
+ sel->registered = false;
+ sel->terminal = false;
+}
+
+void pn_selectable_finalize(pn_selectable_t *sel)
+{
+ if (sel->finalize) {
+ sel->finalize(sel);
+ }
+ pn_decref(sel->attachments);
+ pn_decref(sel->collector);
+}
+
+#define pn_selectable_hashcode NULL
+#define pn_selectable_inspect NULL
+#define pn_selectable_compare NULL
+
+PN_CLASSDEF(pn_selectable)
+
+pn_selectable_t *pn_selectable(void)
+{
+ return pn_selectable_new();
+}
+
+bool pn_selectable_is_reading(pn_selectable_t *sel) {
+ assert(sel);
+ return sel->reading;
+}
+
+void pn_selectable_set_reading(pn_selectable_t *sel, bool reading) {
+ assert(sel);
+ sel->reading = reading;
+}
+
+bool pn_selectable_is_writing(pn_selectable_t *sel) {
+ assert(sel);
+ return sel->writing;
+}
+
+void pn_selectable_set_writing(pn_selectable_t *sel, bool writing) {
+ assert(sel);
+ sel->writing = writing;
+}
+
+pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *sel) {
+ assert(sel);
+ return sel->deadline;
+}
+
+void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline) {
+ assert(sel);
+ sel->deadline = deadline;
+}
+
+void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *)) {
+ assert(sel);
+ sel->readable = readable;
+}
+
+void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *)) {
+ assert(sel);
+ sel->writable = writable;
+}
+
+void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *)) {
+ assert(sel);
+ sel->error = error;
+}
+
+void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *)) {
+ assert(sel);
+ sel->expired = expired;
+}
+
+void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *)) {
+ assert(sel);
+ sel->release = release;
+}
+
+void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *)) {
+ assert(sel);
+ sel->finalize = finalize;
+}
+
+pn_record_t *pn_selectable_attachments(pn_selectable_t *sel) {
+ return sel->attachments;
+}
+
+void *pni_selectable_get_context(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ return pn_record_get(selectable->attachments, PN_LEGCTX);
+}
+
+void pni_selectable_set_context(pn_selectable_t *selectable, void *context)
+{
+ assert(selectable);
+ pn_record_set(selectable->attachments, PN_LEGCTX, context);
+}
+
+int pni_selectable_get_index(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ return selectable->index;
+}
+
+void pni_selectable_set_index(pn_selectable_t *selectable, int index)
+{
+ assert(selectable);
+ selectable->index = index;
+}
+
+pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ return selectable->fd;
+}
+
+void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd)
+{
+ assert(selectable);
+ selectable->fd = fd;
+}
+
+void pn_selectable_readable(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ if (selectable->readable) {
+ selectable->readable(selectable);
+ }
+}
+
+void pn_selectable_writable(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ if (selectable->writable) {
+ selectable->writable(selectable);
+ }
+}
+
+void pn_selectable_error(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ if (selectable->error) {
+ selectable->error(selectable);
+ }
+}
+
+void pn_selectable_expired(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ if (selectable->expired) {
+ selectable->expired(selectable);
+ }
+}
+
+bool pn_selectable_is_registered(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ return selectable->registered;
+}
+
+void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered)
+{
+ assert(selectable);
+ selectable->registered = registered;
+}
+
+bool pn_selectable_is_terminal(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ return selectable->terminal;
+}
+
+void pn_selectable_terminate(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ selectable->terminal = true;
+}
+
+void pn_selectable_release(pn_selectable_t *selectable)
+{
+ assert(selectable);
+ if (selectable->release) {
+ selectable->release(selectable);
+ }
+}
+
+void pn_selectable_free(pn_selectable_t *selectable)
+{
+ pn_decref(selectable);
+}
+
+static void pni_readable(pn_selectable_t *selectable) {
+ pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_READABLE);
+}
+
+static void pni_writable(pn_selectable_t *selectable) {
+ pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_WRITABLE);
+}
+
+static void pni_error(pn_selectable_t *selectable) {
+ pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_ERROR);
+}
+
+static void pni_expired(pn_selectable_t *selectable) {
+ pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_EXPIRED);
+}
+
+void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector) {
+ assert(selectable);
+ pn_decref(selectable->collector);
+ selectable->collector = collector;
+ pn_incref(selectable->collector);
+
+ if (collector) {
+ pn_selectable_on_readable(selectable, pni_readable);
+ pn_selectable_on_writable(selectable, pni_writable);
+ pn_selectable_on_error(selectable, pni_error);
+ pn_selectable_on_expired(selectable, pni_expired);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[10/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/engine/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine.c b/proton-c/src/engine/engine.c
deleted file mode 100644
index cb1f479..0000000
--- a/proton-c/src/engine/engine.c
+++ /dev/null
@@ -1,2231 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "engine-internal.h"
-#include <stdlib.h>
-#include <string.h>
-#include "protocol.h"
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "platform.h"
-#include "platform_fmt.h"
-#include "transport/transport.h"
-
-
-static void pni_session_bound(pn_session_t *ssn);
-static void pni_link_bound(pn_link_t *link);
-
-
-// endpoints
-
-static pn_connection_t *pni_ep_get_connection(pn_endpoint_t *endpoint)
-{
- switch (endpoint->type) {
- case CONNECTION:
- return (pn_connection_t *) endpoint;
- case SESSION:
- return ((pn_session_t *) endpoint)->connection;
- case SENDER:
- case RECEIVER:
- return ((pn_link_t *) endpoint)->session->connection;
- }
-
- return NULL;
-}
-
-static pn_event_type_t endpoint_event(pn_endpoint_type_t type, bool open) {
- switch (type) {
- case CONNECTION:
- return open ? PN_CONNECTION_LOCAL_OPEN : PN_CONNECTION_LOCAL_CLOSE;
- case SESSION:
- return open ? PN_SESSION_LOCAL_OPEN : PN_SESSION_LOCAL_CLOSE;
- case SENDER:
- case RECEIVER:
- return open ? PN_LINK_LOCAL_OPEN : PN_LINK_LOCAL_CLOSE;
- default:
- assert(false);
- return PN_EVENT_NONE;
- }
-}
-
-static void pn_endpoint_open(pn_endpoint_t *endpoint)
-{
- if (!(endpoint->state & PN_LOCAL_ACTIVE)) {
- PN_SET_LOCAL(endpoint->state, PN_LOCAL_ACTIVE);
- pn_connection_t *conn = pni_ep_get_connection(endpoint);
- pn_collector_put(conn->collector, PN_OBJECT, endpoint,
- endpoint_event(endpoint->type, true));
- pn_modified(conn, endpoint, true);
- }
-}
-
-static void pn_endpoint_close(pn_endpoint_t *endpoint)
-{
- if (!(endpoint->state & PN_LOCAL_CLOSED)) {
- PN_SET_LOCAL(endpoint->state, PN_LOCAL_CLOSED);
- pn_connection_t *conn = pni_ep_get_connection(endpoint);
- pn_collector_put(conn->collector, PN_OBJECT, endpoint,
- endpoint_event(endpoint->type, false));
- pn_modified(conn, endpoint, true);
- }
-}
-
-void pn_connection_reset(pn_connection_t *connection)
-{
- assert(connection);
- pn_endpoint_t *endpoint = &connection->endpoint;
- endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
-}
-
-void pn_connection_open(pn_connection_t *connection)
-{
- assert(connection);
- pn_endpoint_open(&connection->endpoint);
-}
-
-void pn_connection_close(pn_connection_t *connection)
-{
- assert(connection);
- pn_endpoint_close(&connection->endpoint);
-}
-
-static void pni_endpoint_tini(pn_endpoint_t *endpoint);
-
-void pn_connection_release(pn_connection_t *connection)
-{
- assert(!connection->endpoint.freed);
- // free those endpoints that haven't been freed by the application
- LL_REMOVE(connection, endpoint, &connection->endpoint);
- while (connection->endpoint_head) {
- pn_endpoint_t *ep = connection->endpoint_head;
- switch (ep->type) {
- case SESSION:
- // note: this will free all child links:
- pn_session_free((pn_session_t *)ep);
- break;
- case SENDER:
- case RECEIVER:
- pn_link_free((pn_link_t *)ep);
- break;
- default:
- assert(false);
- }
- }
- connection->endpoint.freed = true;
- if (!connection->transport) {
- // no transport available to consume transport work items,
- // so manually clear them:
- pn_ep_incref(&connection->endpoint);
- pn_connection_unbound(connection);
- }
- pn_ep_decref(&connection->endpoint);
-}
-
-void pn_connection_free(pn_connection_t *connection) {
- pn_connection_release(connection);
- pn_decref(connection);
-}
-
-void pn_connection_bound(pn_connection_t *connection)
-{
- pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_BOUND);
- pn_ep_incref(&connection->endpoint);
-
- size_t nsessions = pn_list_size(connection->sessions);
- for (size_t i = 0; i < nsessions; i++) {
- pni_session_bound((pn_session_t *) pn_list_get(connection->sessions, i));
- }
-}
-
-// invoked when transport has been removed:
-void pn_connection_unbound(pn_connection_t *connection)
-{
- connection->transport = NULL;
- if (connection->endpoint.freed) {
- // connection has been freed prior to unbinding, thus it
- // cannot be re-assigned to a new transport. Clear the
- // transport work lists to allow the connection to be freed.
- while (connection->transport_head) {
- pn_clear_modified(connection, connection->transport_head);
- }
- while (connection->tpwork_head) {
- pn_clear_tpwork(connection->tpwork_head);
- }
- }
- pn_ep_decref(&connection->endpoint);
-}
-
-pn_record_t *pn_connection_attachments(pn_connection_t *connection)
-{
- assert(connection);
- return connection->context;
-}
-
-void *pn_connection_get_context(pn_connection_t *conn)
-{
- // XXX: we should really assert on conn here, but this causes
- // messenger tests to fail
- return conn ? pn_record_get(conn->context, PN_LEGCTX) : NULL;
-}
-
-void pn_connection_set_context(pn_connection_t *conn, void *context)
-{
- assert(conn);
- pn_record_set(conn->context, PN_LEGCTX, context);
-}
-
-pn_transport_t *pn_connection_transport(pn_connection_t *connection)
-{
- assert(connection);
- return connection->transport;
-}
-
-void pn_condition_init(pn_condition_t *condition)
-{
- condition->name = pn_string(NULL);
- condition->description = pn_string(NULL);
- condition->info = pn_data(0);
-}
-
-void pn_condition_tini(pn_condition_t *condition)
-{
- pn_data_free(condition->info);
- pn_free(condition->description);
- pn_free(condition->name);
-}
-
-static void pni_add_session(pn_connection_t *conn, pn_session_t *ssn)
-{
- pn_list_add(conn->sessions, ssn);
- ssn->connection = conn;
- pn_incref(conn); // keep around until finalized
- pn_ep_incref(&conn->endpoint);
-}
-
-static void pni_remove_session(pn_connection_t *conn, pn_session_t *ssn)
-{
- if (pn_list_remove(conn->sessions, ssn)) {
- pn_ep_decref(&conn->endpoint);
- LL_REMOVE(conn, endpoint, &ssn->endpoint);
- }
-}
-
-pn_connection_t *pn_session_connection(pn_session_t *session)
-{
- if (!session) return NULL;
- return session->connection;
-}
-
-void pn_session_open(pn_session_t *session)
-{
- assert(session);
- pn_endpoint_open(&session->endpoint);
-}
-
-void pn_session_close(pn_session_t *session)
-{
- assert(session);
- pn_endpoint_close(&session->endpoint);
-}
-
-void pn_session_free(pn_session_t *session)
-{
- assert(!session->endpoint.freed);
- while(pn_list_size(session->links)) {
- pn_link_t *link = (pn_link_t *)pn_list_get(session->links, 0);
- pn_link_free(link);
- }
- pni_remove_session(session->connection, session);
- pn_list_add(session->connection->freed, session);
- session->endpoint.freed = true;
- pn_ep_decref(&session->endpoint);
-
- // the finalize logic depends on endpoint.freed, so we incref/decref
- // to give it a chance to rerun
- pn_incref(session);
- pn_decref(session);
-}
-
-pn_record_t *pn_session_attachments(pn_session_t *session)
-{
- assert(session);
- return session->context;
-}
-
-void *pn_session_get_context(pn_session_t *session)
-{
- return session ? pn_record_get(session->context, PN_LEGCTX) : 0;
-}
-
-void pn_session_set_context(pn_session_t *session, void *context)
-{
- assert(context);
- pn_record_set(session->context, PN_LEGCTX, context);
-}
-
-
-static void pni_add_link(pn_session_t *ssn, pn_link_t *link)
-{
- pn_list_add(ssn->links, link);
- link->session = ssn;
- pn_ep_incref(&ssn->endpoint);
-}
-
-static void pni_remove_link(pn_session_t *ssn, pn_link_t *link)
-{
- if (pn_list_remove(ssn->links, link)) {
- pn_ep_decref(&ssn->endpoint);
- LL_REMOVE(ssn->connection, endpoint, &link->endpoint);
- }
-}
-
-void pn_link_open(pn_link_t *link)
-{
- assert(link);
- pn_endpoint_open(&link->endpoint);
-}
-
-void pn_link_close(pn_link_t *link)
-{
- assert(link);
- pn_endpoint_close(&link->endpoint);
-}
-
-void pn_link_detach(pn_link_t *link)
-{
- assert(link);
- if (link->detached) return;
-
- link->detached = true;
- pn_collector_put(link->session->connection->collector, PN_OBJECT, link, PN_LINK_LOCAL_DETACH);
- pn_modified(link->session->connection, &link->endpoint, true);
-
-}
-
-static void pni_terminus_free(pn_terminus_t *terminus)
-{
- pn_free(terminus->address);
- pn_free(terminus->properties);
- pn_free(terminus->capabilities);
- pn_free(terminus->outcomes);
- pn_free(terminus->filter);
-}
-
-void pn_link_free(pn_link_t *link)
-{
- assert(!link->endpoint.freed);
- pni_remove_link(link->session, link);
- pn_list_add(link->session->freed, link);
- pn_delivery_t *delivery = link->unsettled_head;
- while (delivery) {
- pn_delivery_t *next = delivery->unsettled_next;
- pn_delivery_settle(delivery);
- delivery = next;
- }
- link->endpoint.freed = true;
- pn_ep_decref(&link->endpoint);
-
- // the finalize logic depends on endpoint.freed (modified above), so
- // we incref/decref to give it a chance to rerun
- pn_incref(link);
- pn_decref(link);
-}
-
-void *pn_link_get_context(pn_link_t *link)
-{
- assert(link);
- return pn_record_get(link->context, PN_LEGCTX);
-}
-
-void pn_link_set_context(pn_link_t *link, void *context)
-{
- assert(link);
- pn_record_set(link->context, PN_LEGCTX, context);
-}
-
-pn_record_t *pn_link_attachments(pn_link_t *link)
-{
- assert(link);
- return link->context;
-}
-
-void pn_endpoint_init(pn_endpoint_t *endpoint, int type, pn_connection_t *conn)
-{
- endpoint->type = (pn_endpoint_type_t) type;
- endpoint->referenced = true;
- endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
- endpoint->error = pn_error();
- pn_condition_init(&endpoint->condition);
- pn_condition_init(&endpoint->remote_condition);
- endpoint->endpoint_next = NULL;
- endpoint->endpoint_prev = NULL;
- endpoint->transport_next = NULL;
- endpoint->transport_prev = NULL;
- endpoint->modified = false;
- endpoint->freed = false;
- endpoint->refcount = 1;
- //fprintf(stderr, "initting 0x%lx\n", (uintptr_t) endpoint);
-
- LL_ADD(conn, endpoint, endpoint);
-}
-
-void pn_ep_incref(pn_endpoint_t *endpoint)
-{
- endpoint->refcount++;
-}
-
-static pn_event_type_t pn_final_type(pn_endpoint_type_t type) {
- switch (type) {
- case CONNECTION:
- return PN_CONNECTION_FINAL;
- case SESSION:
- return PN_SESSION_FINAL;
- case SENDER:
- case RECEIVER:
- return PN_LINK_FINAL;
- default:
- assert(false);
- return PN_EVENT_NONE;
- }
-}
-
-static pn_endpoint_t *pn_ep_parent(pn_endpoint_t *endpoint) {
- switch (endpoint->type) {
- case CONNECTION:
- return NULL;
- case SESSION:
- return &((pn_session_t *) endpoint)->connection->endpoint;
- case SENDER:
- case RECEIVER:
- return &((pn_link_t *) endpoint)->session->endpoint;
- default:
- assert(false);
- return NULL;
- }
-}
-
-void pn_ep_decref(pn_endpoint_t *endpoint)
-{
- assert(endpoint->refcount > 0);
- endpoint->refcount--;
- if (endpoint->refcount == 0) {
- pn_connection_t *conn = pni_ep_get_connection(endpoint);
- pn_collector_put(conn->collector, PN_OBJECT, endpoint, pn_final_type(endpoint->type));
- }
-}
-
-static void pni_endpoint_tini(pn_endpoint_t *endpoint)
-{
- pn_error_free(endpoint->error);
- pn_condition_tini(&endpoint->remote_condition);
- pn_condition_tini(&endpoint->condition);
-}
-
-static void pni_free_children(pn_list_t *children, pn_list_t *freed)
-{
- while (pn_list_size(children) > 0) {
- pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(children, 0);
- assert(!endpoint->referenced);
- pn_free(endpoint);
- }
-
- while (pn_list_size(freed) > 0) {
- pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(freed, 0);
- assert(!endpoint->referenced);
- pn_free(endpoint);
- }
-
- pn_free(children);
- pn_free(freed);
-}
-
-static void pn_connection_finalize(void *object)
-{
- pn_connection_t *conn = (pn_connection_t *) object;
- pn_endpoint_t *endpoint = &conn->endpoint;
-
- if (conn->transport) {
- assert(!conn->transport->referenced);
- pn_free(conn->transport);
- }
-
- // freeing the transport could post events
- if (pn_refcount(conn) > 0) {
- return;
- }
-
- pni_free_children(conn->sessions, conn->freed);
- pn_free(conn->context);
- pn_decref(conn->collector);
-
- pn_free(conn->container);
- pn_free(conn->hostname);
- pn_free(conn->auth_user);
- pn_free(conn->auth_password);
- pn_free(conn->offered_capabilities);
- pn_free(conn->desired_capabilities);
- pn_free(conn->properties);
- pni_endpoint_tini(endpoint);
- pn_free(conn->delivery_pool);
-}
-
-#define pn_connection_initialize NULL
-#define pn_connection_hashcode NULL
-#define pn_connection_compare NULL
-#define pn_connection_inspect NULL
-
-pn_connection_t *pn_connection(void)
-{
- static const pn_class_t clazz = PN_CLASS(pn_connection);
- pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, sizeof(pn_connection_t));
- if (!conn) return NULL;
-
- conn->endpoint_head = NULL;
- conn->endpoint_tail = NULL;
- pn_endpoint_init(&conn->endpoint, CONNECTION, conn);
- conn->transport_head = NULL;
- conn->transport_tail = NULL;
- conn->sessions = pn_list(PN_WEAKREF, 0);
- conn->freed = pn_list(PN_WEAKREF, 0);
- conn->transport = NULL;
- conn->work_head = NULL;
- conn->work_tail = NULL;
- conn->tpwork_head = NULL;
- conn->tpwork_tail = NULL;
- conn->container = pn_string(NULL);
- conn->hostname = pn_string(NULL);
- conn->auth_user = pn_string(NULL);
- conn->auth_password = pn_string(NULL);
- conn->offered_capabilities = pn_data(0);
- conn->desired_capabilities = pn_data(0);
- conn->properties = pn_data(0);
- conn->collector = NULL;
- conn->context = pn_record();
- conn->delivery_pool = pn_list(PN_OBJECT, 0);
-
- return conn;
-}
-
-static const pn_event_type_t endpoint_init_event_map[] = {
- PN_CONNECTION_INIT, /* CONNECTION */
- PN_SESSION_INIT, /* SESSION */
- PN_LINK_INIT, /* SENDER */
- PN_LINK_INIT}; /* RECEIVER */
-
-void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collector)
-{
- pn_decref(connection->collector);
- connection->collector = collector;
- pn_incref(connection->collector);
- pn_endpoint_t *endpoint = connection->endpoint_head;
- while (endpoint) {
- pn_collector_put(connection->collector, PN_OBJECT, endpoint, endpoint_init_event_map[endpoint->type]);
- endpoint = endpoint->endpoint_next;
- }
-}
-
-pn_state_t pn_connection_state(pn_connection_t *connection)
-{
- return connection ? connection->endpoint.state : 0;
-}
-
-pn_error_t *pn_connection_error(pn_connection_t *connection)
-{
- return connection ? connection->endpoint.error : NULL;
-}
-
-const char *pn_connection_get_container(pn_connection_t *connection)
-{
- assert(connection);
- return pn_string_get(connection->container);
-}
-
-void pn_connection_set_container(pn_connection_t *connection, const char *container)
-{
- assert(connection);
- pn_string_set(connection->container, container);
-}
-
-const char *pn_connection_get_hostname(pn_connection_t *connection)
-{
- assert(connection);
- return pn_string_get(connection->hostname);
-}
-
-void pn_connection_set_hostname(pn_connection_t *connection, const char *hostname)
-{
- assert(connection);
- pn_string_set(connection->hostname, hostname);
-}
-
-const char *pn_connection_get_user(pn_connection_t *connection)
-{
- assert(connection);
- return pn_string_get(connection->auth_user);
-}
-
-void pn_connection_set_user(pn_connection_t *connection, const char *user)
-{
- assert(connection);
- pn_string_set(connection->auth_user, user);
-}
-
-void pn_connection_set_password(pn_connection_t *connection, const char *password)
-{
- assert(connection);
- // Make sure the previous password is erased, if there was one.
- size_t n = pn_string_size(connection->auth_password);
- const char* s = pn_string_get(connection->auth_password);
- if (n > 0 && s) memset((void*)s, 0, n);
- pn_string_set(connection->auth_password, password);
-}
-
-pn_data_t *pn_connection_offered_capabilities(pn_connection_t *connection)
-{
- assert(connection);
- return connection->offered_capabilities;
-}
-
-pn_data_t *pn_connection_desired_capabilities(pn_connection_t *connection)
-{
- assert(connection);
- return connection->desired_capabilities;
-}
-
-pn_data_t *pn_connection_properties(pn_connection_t *connection)
-{
- assert(connection);
- return connection->properties;
-}
-
-pn_data_t *pn_connection_remote_offered_capabilities(pn_connection_t *connection)
-{
- assert(connection);
- return connection->transport ? connection->transport->remote_offered_capabilities : NULL;
-}
-
-pn_data_t *pn_connection_remote_desired_capabilities(pn_connection_t *connection)
-{
- assert(connection);
- return connection->transport ? connection->transport->remote_desired_capabilities : NULL;
-}
-
-pn_data_t *pn_connection_remote_properties(pn_connection_t *connection)
-{
- assert(connection);
- return connection->transport ? connection->transport->remote_properties : NULL;
-}
-
-const char *pn_connection_remote_container(pn_connection_t *connection)
-{
- assert(connection);
- return connection->transport ? connection->transport->remote_container : NULL;
-}
-
-const char *pn_connection_remote_hostname(pn_connection_t *connection)
-{
- assert(connection);
- return connection->transport ? connection->transport->remote_hostname : NULL;
-}
-
-pn_delivery_t *pn_work_head(pn_connection_t *connection)
-{
- assert(connection);
- return connection->work_head;
-}
-
-pn_delivery_t *pn_work_next(pn_delivery_t *delivery)
-{
- assert(delivery);
-
- if (delivery->work)
- return delivery->work_next;
- else
- return pn_work_head(delivery->link->session->connection);
-}
-
-static void pni_add_work(pn_connection_t *connection, pn_delivery_t *delivery)
-{
- if (!delivery->work)
- {
- assert(!delivery->local.settled); // never allow settled deliveries
- LL_ADD(connection, work, delivery);
- delivery->work = true;
- }
-}
-
-static void pni_clear_work(pn_connection_t *connection, pn_delivery_t *delivery)
-{
- if (delivery->work)
- {
- LL_REMOVE(connection, work, delivery);
- delivery->work = false;
- }
-}
-
-void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery)
-{
- pn_link_t *link = pn_delivery_link(delivery);
- pn_delivery_t *current = pn_link_current(link);
- if (delivery->updated && !delivery->local.settled) {
- pni_add_work(connection, delivery);
- } else if (delivery == current) {
- if (link->endpoint.type == SENDER) {
- if (pn_link_credit(link) > 0) {
- pni_add_work(connection, delivery);
- } else {
- pni_clear_work(connection, delivery);
- }
- } else {
- pni_add_work(connection, delivery);
- }
- } else {
- pni_clear_work(connection, delivery);
- }
-}
-
-static void pni_add_tpwork(pn_delivery_t *delivery)
-{
- pn_connection_t *connection = delivery->link->session->connection;
- if (!delivery->tpwork)
- {
- LL_ADD(connection, tpwork, delivery);
- delivery->tpwork = true;
- }
- pn_modified(connection, &connection->endpoint, true);
-}
-
-void pn_clear_tpwork(pn_delivery_t *delivery)
-{
- pn_connection_t *connection = delivery->link->session->connection;
- if (delivery->tpwork)
- {
- LL_REMOVE(connection, tpwork, delivery);
- delivery->tpwork = false;
- if (pn_refcount(delivery) > 0) {
- pn_incref(delivery);
- pn_decref(delivery);
- }
- }
-}
-
-void pn_dump(pn_connection_t *conn)
-{
- pn_endpoint_t *endpoint = conn->transport_head;
- while (endpoint)
- {
- printf("%p", (void *) endpoint);
- endpoint = endpoint->transport_next;
- if (endpoint)
- printf(" -> ");
- }
- printf("\n");
-}
-
-void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit)
-{
- if (!endpoint->modified) {
- LL_ADD(connection, transport, endpoint);
- endpoint->modified = true;
- }
-
- if (emit && connection->transport) {
- pn_collector_put(connection->collector, PN_OBJECT, connection->transport,
- PN_TRANSPORT);
- }
-}
-
-void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint)
-{
- if (endpoint->modified) {
- LL_REMOVE(connection, transport, endpoint);
- endpoint->transport_next = NULL;
- endpoint->transport_prev = NULL;
- endpoint->modified = false;
- }
-}
-
-static bool pni_matches(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
-{
- if (endpoint->type != type) return false;
-
- if (!state) return true;
-
- int st = endpoint->state;
- if ((state & PN_REMOTE_MASK) == 0 || (state & PN_LOCAL_MASK) == 0)
- return st & state;
- else
- return st == state;
-}
-
-pn_endpoint_t *pn_find(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
-{
- while (endpoint)
- {
- if (pni_matches(endpoint, type, state))
- return endpoint;
- endpoint = endpoint->endpoint_next;
- }
- return NULL;
-}
-
-pn_session_t *pn_session_head(pn_connection_t *conn, pn_state_t state)
-{
- if (conn)
- return (pn_session_t *) pn_find(conn->endpoint_head, SESSION, state);
- else
- return NULL;
-}
-
-pn_session_t *pn_session_next(pn_session_t *ssn, pn_state_t state)
-{
- if (ssn)
- return (pn_session_t *) pn_find(ssn->endpoint.endpoint_next, SESSION, state);
- else
- return NULL;
-}
-
-pn_link_t *pn_link_head(pn_connection_t *conn, pn_state_t state)
-{
- if (!conn) return NULL;
-
- pn_endpoint_t *endpoint = conn->endpoint_head;
-
- while (endpoint)
- {
- if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
- return (pn_link_t *) endpoint;
- endpoint = endpoint->endpoint_next;
- }
-
- return NULL;
-}
-
-pn_link_t *pn_link_next(pn_link_t *link, pn_state_t state)
-{
- if (!link) return NULL;
-
- pn_endpoint_t *endpoint = link->endpoint.endpoint_next;
-
- while (endpoint)
- {
- if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
- return (pn_link_t *) endpoint;
- endpoint = endpoint->endpoint_next;
- }
-
- return NULL;
-}
-
-static void pn_session_incref(void *object)
-{
- pn_session_t *session = (pn_session_t *) object;
- if (!session->endpoint.referenced) {
- session->endpoint.referenced = true;
- pn_incref(session->connection);
- } else {
- pn_object_incref(object);
- }
-}
-
-static bool pn_ep_bound(pn_endpoint_t *endpoint)
-{
- pn_connection_t *conn = pni_ep_get_connection(endpoint);
- pn_session_t *ssn;
- pn_link_t *lnk;
-
- if (!conn->transport) return false;
- if (endpoint->modified) return true;
-
- switch (endpoint->type) {
- case CONNECTION:
- return ((pn_connection_t *)endpoint)->transport;
- case SESSION:
- ssn = (pn_session_t *) endpoint;
- return (((int16_t) ssn->state.local_channel) >= 0 || ((int16_t) ssn->state.remote_channel) >= 0);
- case SENDER:
- case RECEIVER:
- lnk = (pn_link_t *) endpoint;
- return ((int32_t) lnk->state.local_handle) >= 0 || ((int32_t) lnk->state.remote_handle) >= 0;
- default:
- assert(false);
- return false;
- }
-}
-
-static bool pni_connection_live(pn_connection_t *conn) {
- return pn_refcount(conn) > 1;
-}
-
-static bool pni_session_live(pn_session_t *ssn) {
- return pni_connection_live(ssn->connection) || pn_refcount(ssn) > 1;
-}
-
-static bool pni_link_live(pn_link_t *link) {
- return pni_session_live(link->session) || pn_refcount(link) > 1;
-}
-
-static bool pni_endpoint_live(pn_endpoint_t *endpoint) {
- switch (endpoint->type) {
- case CONNECTION:
- return pni_connection_live((pn_connection_t *)endpoint);
- case SESSION:
- return pni_session_live((pn_session_t *) endpoint);
- case SENDER:
- case RECEIVER:
- return pni_link_live((pn_link_t *) endpoint);
- default:
- assert(false);
- return false;
- }
-}
-
-static bool pni_preserve_child(pn_endpoint_t *endpoint)
-{
- pn_connection_t *conn = pni_ep_get_connection(endpoint);
- pn_endpoint_t *parent = pn_ep_parent(endpoint);
- if (pni_endpoint_live(parent) && (!endpoint->freed || (pn_ep_bound(endpoint)))
- && endpoint->referenced) {
- pn_object_incref(endpoint);
- endpoint->referenced = false;
- pn_decref(parent);
- return true;
- } else {
- LL_REMOVE(conn, transport, endpoint);
- return false;
- }
-}
-
-static void pn_session_finalize(void *object)
-{
- pn_session_t *session = (pn_session_t *) object;
- pn_endpoint_t *endpoint = &session->endpoint;
-
- if (pni_preserve_child(endpoint)) {
- return;
- }
-
- pn_free(session->context);
- pni_free_children(session->links, session->freed);
- pni_endpoint_tini(endpoint);
- pn_delivery_map_free(&session->state.incoming);
- pn_delivery_map_free(&session->state.outgoing);
- pn_free(session->state.local_handles);
- pn_free(session->state.remote_handles);
- pni_remove_session(session->connection, session);
- pn_list_remove(session->connection->freed, session);
-
- if (session->connection->transport) {
- pn_transport_t *transport = session->connection->transport;
- pn_hash_del(transport->local_channels, session->state.local_channel);
- pn_hash_del(transport->remote_channels, session->state.remote_channel);
- }
-
- if (endpoint->referenced) {
- pn_decref(session->connection);
- }
-}
-
-#define pn_session_new pn_object_new
-#define pn_session_refcount pn_object_refcount
-#define pn_session_decref pn_object_decref
-#define pn_session_reify pn_object_reify
-#define pn_session_initialize NULL
-#define pn_session_hashcode NULL
-#define pn_session_compare NULL
-#define pn_session_inspect NULL
-
-pn_session_t *pn_session(pn_connection_t *conn)
-{
- assert(conn);
-
-
- pn_transport_t * transport = pn_connection_transport(conn);
-
- if(transport) {
- // channel_max is an index, not a count.
- if(pn_hash_size(transport->local_channels) > (size_t)transport->channel_max) {
- pn_transport_logf(transport,
- "pn_session: too many sessions: %d channel_max is %d",
- pn_hash_size(transport->local_channels),
- transport->channel_max);
- return (pn_session_t *) 0;
- }
- }
-
-#define pn_session_free pn_object_free
- static const pn_class_t clazz = PN_METACLASS(pn_session);
-#undef pn_session_free
- pn_session_t *ssn = (pn_session_t *) pn_class_new(&clazz, sizeof(pn_session_t));
- if (!ssn) return NULL;
- pn_endpoint_init(&ssn->endpoint, SESSION, conn);
- pni_add_session(conn, ssn);
- ssn->links = pn_list(PN_WEAKREF, 0);
- ssn->freed = pn_list(PN_WEAKREF, 0);
- ssn->context = pn_record();
- ssn->incoming_capacity = 1024*1024;
- ssn->incoming_bytes = 0;
- ssn->outgoing_bytes = 0;
- ssn->incoming_deliveries = 0;
- ssn->outgoing_deliveries = 0;
- ssn->outgoing_window = 2147483647;
-
- // begin transport state
- memset(&ssn->state, 0, sizeof(ssn->state));
- ssn->state.local_channel = (uint16_t)-1;
- ssn->state.remote_channel = (uint16_t)-1;
- pn_delivery_map_init(&ssn->state.incoming, 0);
- pn_delivery_map_init(&ssn->state.outgoing, 0);
- ssn->state.local_handles = pn_hash(PN_WEAKREF, 0, 0.75);
- ssn->state.remote_handles = pn_hash(PN_WEAKREF, 0, 0.75);
- // end transport state
-
- pn_collector_put(conn->collector, PN_OBJECT, ssn, PN_SESSION_INIT);
- if (conn->transport) {
- pni_session_bound(ssn);
- }
- pn_decref(ssn);
- return ssn;
-}
-
-static void pni_session_bound(pn_session_t *ssn)
-{
- assert(ssn);
- size_t nlinks = pn_list_size(ssn->links);
- for (size_t i = 0; i < nlinks; i++) {
- pni_link_bound((pn_link_t *) pn_list_get(ssn->links, i));
- }
-}
-
-void pn_session_unbound(pn_session_t* ssn)
-{
- assert(ssn);
- ssn->state.local_channel = (uint16_t)-1;
- ssn->state.remote_channel = (uint16_t)-1;
- ssn->incoming_bytes = 0;
- ssn->outgoing_bytes = 0;
- ssn->incoming_deliveries = 0;
- ssn->outgoing_deliveries = 0;
-}
-
-size_t pn_session_get_incoming_capacity(pn_session_t *ssn)
-{
- assert(ssn);
- return ssn->incoming_capacity;
-}
-
-void pn_session_set_incoming_capacity(pn_session_t *ssn, size_t capacity)
-{
- assert(ssn);
- // XXX: should this trigger a flow?
- ssn->incoming_capacity = capacity;
-}
-
-size_t pn_session_get_outgoing_window(pn_session_t *ssn)
-{
- assert(ssn);
- return ssn->outgoing_window;
-}
-
-void pn_session_set_outgoing_window(pn_session_t *ssn, size_t window)
-{
- assert(ssn);
- ssn->outgoing_window = window;
-}
-
-size_t pn_session_outgoing_bytes(pn_session_t *ssn)
-{
- assert(ssn);
- return ssn->outgoing_bytes;
-}
-
-size_t pn_session_incoming_bytes(pn_session_t *ssn)
-{
- assert(ssn);
- return ssn->incoming_bytes;
-}
-
-pn_state_t pn_session_state(pn_session_t *session)
-{
- return session->endpoint.state;
-}
-
-pn_error_t *pn_session_error(pn_session_t *session)
-{
- return session->endpoint.error;
-}
-
-static void pni_terminus_init(pn_terminus_t *terminus, pn_terminus_type_t type)
-{
- terminus->type = type;
- terminus->address = pn_string(NULL);
- terminus->durability = PN_NONDURABLE;
- terminus->expiry_policy = PN_EXPIRE_WITH_SESSION;
- terminus->timeout = 0;
- terminus->dynamic = false;
- terminus->distribution_mode = PN_DIST_MODE_UNSPECIFIED;
- terminus->properties = pn_data(0);
- terminus->capabilities = pn_data(0);
- terminus->outcomes = pn_data(0);
- terminus->filter = pn_data(0);
-}
-
-static void pn_link_incref(void *object)
-{
- pn_link_t *link = (pn_link_t *) object;
- if (!link->endpoint.referenced) {
- link->endpoint.referenced = true;
- pn_incref(link->session);
- } else {
- pn_object_incref(object);
- }
-}
-
-static void pn_link_finalize(void *object)
-{
- pn_link_t *link = (pn_link_t *) object;
- pn_endpoint_t *endpoint = &link->endpoint;
-
- if (pni_preserve_child(endpoint)) {
- return;
- }
-
- while (link->unsettled_head) {
- assert(!link->unsettled_head->referenced);
- pn_free(link->unsettled_head);
- }
-
- pn_free(link->context);
- pni_terminus_free(&link->source);
- pni_terminus_free(&link->target);
- pni_terminus_free(&link->remote_source);
- pni_terminus_free(&link->remote_target);
- pn_free(link->name);
- pni_endpoint_tini(endpoint);
- pni_remove_link(link->session, link);
- pn_hash_del(link->session->state.local_handles, link->state.local_handle);
- pn_hash_del(link->session->state.remote_handles, link->state.remote_handle);
- pn_list_remove(link->session->freed, link);
- if (endpoint->referenced) {
- pn_decref(link->session);
- }
-}
-
-#define pn_link_refcount pn_object_refcount
-#define pn_link_decref pn_object_decref
-#define pn_link_reify pn_object_reify
-#define pn_link_initialize NULL
-#define pn_link_hashcode NULL
-#define pn_link_compare NULL
-#define pn_link_inspect NULL
-
-pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
-{
-#define pn_link_new pn_object_new
-#define pn_link_free pn_object_free
- static const pn_class_t clazz = PN_METACLASS(pn_link);
-#undef pn_link_new
-#undef pn_link_free
- pn_link_t *link = (pn_link_t *) pn_class_new(&clazz, sizeof(pn_link_t));
-
- pn_endpoint_init(&link->endpoint, type, session->connection);
- pni_add_link(session, link);
- pn_incref(session); // keep session until link finalized
- link->name = pn_string(name);
- pni_terminus_init(&link->source, PN_SOURCE);
- pni_terminus_init(&link->target, PN_TARGET);
- pni_terminus_init(&link->remote_source, PN_UNSPECIFIED);
- pni_terminus_init(&link->remote_target, PN_UNSPECIFIED);
- link->unsettled_head = link->unsettled_tail = link->current = NULL;
- link->unsettled_count = 0;
- link->available = 0;
- link->credit = 0;
- link->queued = 0;
- link->drain = false;
- link->drain_flag_mode = true;
- link->drained = 0;
- link->context = pn_record();
- link->snd_settle_mode = PN_SND_MIXED;
- link->rcv_settle_mode = PN_RCV_FIRST;
- link->remote_snd_settle_mode = PN_SND_MIXED;
- link->remote_rcv_settle_mode = PN_RCV_FIRST;
- link->detached = false;
-
- // begin transport state
- link->state.local_handle = -1;
- link->state.remote_handle = -1;
- link->state.delivery_count = 0;
- link->state.link_credit = 0;
- // end transport state
-
- pn_collector_put(session->connection->collector, PN_OBJECT, link, PN_LINK_INIT);
- if (session->connection->transport) {
- pni_link_bound(link);
- }
- pn_decref(link);
- return link;
-}
-
-static void pni_link_bound(pn_link_t *link)
-{
-}
-
-void pn_link_unbound(pn_link_t* link)
-{
- assert(link);
- link->state.local_handle = -1;
- link->state.remote_handle = -1;
- link->state.delivery_count = 0;
- link->state.link_credit = 0;
-}
-
-pn_terminus_t *pn_link_source(pn_link_t *link)
-{
- return link ? &link->source : NULL;
-}
-
-pn_terminus_t *pn_link_target(pn_link_t *link)
-{
- return link ? &link->target : NULL;
-}
-
-pn_terminus_t *pn_link_remote_source(pn_link_t *link)
-{
- return link ? &link->remote_source : NULL;
-}
-
-pn_terminus_t *pn_link_remote_target(pn_link_t *link)
-{
- return link ? &link->remote_target : NULL;
-}
-
-int pn_terminus_set_type(pn_terminus_t *terminus, pn_terminus_type_t type)
-{
- if (!terminus) return PN_ARG_ERR;
- terminus->type = type;
- return 0;
-}
-
-pn_terminus_type_t pn_terminus_get_type(pn_terminus_t *terminus)
-{
- return terminus ? terminus->type : (pn_terminus_type_t) 0;
-}
-
-const char *pn_terminus_get_address(pn_terminus_t *terminus)
-{
- assert(terminus);
- return pn_string_get(terminus->address);
-}
-
-int pn_terminus_set_address(pn_terminus_t *terminus, const char *address)
-{
- assert(terminus);
- return pn_string_set(terminus->address, address);
-}
-
-pn_durability_t pn_terminus_get_durability(pn_terminus_t *terminus)
-{
- return terminus ? terminus->durability : (pn_durability_t) 0;
-}
-
-int pn_terminus_set_durability(pn_terminus_t *terminus, pn_durability_t durability)
-{
- if (!terminus) return PN_ARG_ERR;
- terminus->durability = durability;
- return 0;
-}
-
-pn_expiry_policy_t pn_terminus_get_expiry_policy(pn_terminus_t *terminus)
-{
- return terminus ? terminus->expiry_policy : (pn_expiry_policy_t) 0;
-}
-
-int pn_terminus_set_expiry_policy(pn_terminus_t *terminus, pn_expiry_policy_t expiry_policy)
-{
- if (!terminus) return PN_ARG_ERR;
- terminus->expiry_policy = expiry_policy;
- return 0;
-}
-
-pn_seconds_t pn_terminus_get_timeout(pn_terminus_t *terminus)
-{
- return terminus ? terminus->timeout : 0;
-}
-
-int pn_terminus_set_timeout(pn_terminus_t *terminus, pn_seconds_t timeout)
-{
- if (!terminus) return PN_ARG_ERR;
- terminus->timeout = timeout;
- return 0;
-}
-
-bool pn_terminus_is_dynamic(pn_terminus_t *terminus)
-{
- return terminus ? terminus->dynamic : false;
-}
-
-int pn_terminus_set_dynamic(pn_terminus_t *terminus, bool dynamic)
-{
- if (!terminus) return PN_ARG_ERR;
- terminus->dynamic = dynamic;
- return 0;
-}
-
-pn_data_t *pn_terminus_properties(pn_terminus_t *terminus)
-{
- return terminus ? terminus->properties : NULL;
-}
-
-pn_data_t *pn_terminus_capabilities(pn_terminus_t *terminus)
-{
- return terminus ? terminus->capabilities : NULL;
-}
-
-pn_data_t *pn_terminus_outcomes(pn_terminus_t *terminus)
-{
- return terminus ? terminus->outcomes : NULL;
-}
-
-pn_data_t *pn_terminus_filter(pn_terminus_t *terminus)
-{
- return terminus ? terminus->filter : NULL;
-}
-
-pn_distribution_mode_t pn_terminus_get_distribution_mode(const pn_terminus_t *terminus)
-{
- return terminus ? terminus->distribution_mode : PN_DIST_MODE_UNSPECIFIED;
-}
-
-int pn_terminus_set_distribution_mode(pn_terminus_t *terminus, pn_distribution_mode_t m)
-{
- if (!terminus) return PN_ARG_ERR;
- terminus->distribution_mode = m;
- return 0;
-}
-
-int pn_terminus_copy(pn_terminus_t *terminus, pn_terminus_t *src)
-{
- if (!terminus || !src) {
- return PN_ARG_ERR;
- }
-
- terminus->type = src->type;
- int err = pn_terminus_set_address(terminus, pn_terminus_get_address(src));
- if (err) return err;
- terminus->durability = src->durability;
- terminus->expiry_policy = src->expiry_policy;
- terminus->timeout = src->timeout;
- terminus->dynamic = src->dynamic;
- terminus->distribution_mode = src->distribution_mode;
- err = pn_data_copy(terminus->properties, src->properties);
- if (err) return err;
- err = pn_data_copy(terminus->capabilities, src->capabilities);
- if (err) return err;
- err = pn_data_copy(terminus->outcomes, src->outcomes);
- if (err) return err;
- err = pn_data_copy(terminus->filter, src->filter);
- if (err) return err;
- return 0;
-}
-
-pn_link_t *pn_sender(pn_session_t *session, const char *name)
-{
- return pn_link_new(SENDER, session, name);
-}
-
-pn_link_t *pn_receiver(pn_session_t *session, const char *name)
-{
- return pn_link_new(RECEIVER, session, name);
-}
-
-pn_state_t pn_link_state(pn_link_t *link)
-{
- return link->endpoint.state;
-}
-
-pn_error_t *pn_link_error(pn_link_t *link)
-{
- return link->endpoint.error;
-}
-
-const char *pn_link_name(pn_link_t *link)
-{
- assert(link);
- return pn_string_get(link->name);
-}
-
-bool pn_link_is_sender(pn_link_t *link)
-{
- return link->endpoint.type == SENDER;
-}
-
-bool pn_link_is_receiver(pn_link_t *link)
-{
- return link->endpoint.type == RECEIVER;
-}
-
-pn_session_t *pn_link_session(pn_link_t *link)
-{
- assert(link);
- return link->session;
-}
-
-static void pn_disposition_finalize(pn_disposition_t *ds)
-{
- pn_free(ds->data);
- pn_free(ds->annotations);
- pn_condition_tini(&ds->condition);
-}
-
-static void pn_delivery_incref(void *object)
-{
- pn_delivery_t *delivery = (pn_delivery_t *) object;
- if (delivery->link && !delivery->referenced) {
- delivery->referenced = true;
- pn_incref(delivery->link);
- } else {
- pn_object_incref(object);
- }
-}
-
-static bool pni_preserve_delivery(pn_delivery_t *delivery)
-{
- pn_connection_t *conn = delivery->link->session->connection;
- return !delivery->local.settled || (conn->transport && (delivery->state.init || delivery->tpwork));
-}
-
-static void pn_delivery_finalize(void *object)
-{
- pn_delivery_t *delivery = (pn_delivery_t *) object;
- pn_link_t *link = delivery->link;
- // assert(!delivery->state.init);
-
- bool pooled = false;
- bool referenced = true;
- if (link) {
- if (pni_link_live(link) && pni_preserve_delivery(delivery) && delivery->referenced) {
- delivery->referenced = false;
- pn_object_incref(delivery);
- pn_decref(link);
- return;
- }
- referenced = delivery->referenced;
-
- pn_clear_tpwork(delivery);
- LL_REMOVE(link, unsettled, delivery);
- pn_delivery_map_del(pn_link_is_sender(link)
- ? &link->session->state.outgoing
- : &link->session->state.incoming,
- delivery);
- pn_buffer_clear(delivery->tag);
- pn_buffer_clear(delivery->bytes);
- pn_record_clear(delivery->context);
- delivery->settled = true;
- pn_connection_t *conn = link->session->connection;
- assert(pn_refcount(delivery) == 0);
- if (pni_connection_live(conn)) {
- pn_list_t *pool = link->session->connection->delivery_pool;
- delivery->link = NULL;
- pn_list_add(pool, delivery);
- pooled = true;
- assert(pn_refcount(delivery) == 1);
- }
- }
-
- if (!pooled) {
- pn_free(delivery->context);
- pn_buffer_free(delivery->tag);
- pn_buffer_free(delivery->bytes);
- pn_disposition_finalize(&delivery->local);
- pn_disposition_finalize(&delivery->remote);
- }
-
- if (referenced) {
- pn_decref(link);
- }
-}
-
-static void pn_disposition_init(pn_disposition_t *ds)
-{
- ds->data = pn_data(0);
- ds->annotations = pn_data(0);
- pn_condition_init(&ds->condition);
-}
-
-static void pn_disposition_clear(pn_disposition_t *ds)
-{
- ds->type = 0;
- ds->section_number = 0;
- ds->section_offset = 0;
- ds->failed = false;
- ds->undeliverable = false;
- ds->settled = false;
- pn_data_clear(ds->data);
- pn_data_clear(ds->annotations);
- pn_condition_clear(&ds->condition);
-}
-
-#define pn_delivery_new pn_object_new
-#define pn_delivery_refcount pn_object_refcount
-#define pn_delivery_decref pn_object_decref
-#define pn_delivery_free pn_object_free
-#define pn_delivery_reify pn_object_reify
-#define pn_delivery_initialize NULL
-#define pn_delivery_hashcode NULL
-#define pn_delivery_compare NULL
-#define pn_delivery_inspect NULL
-
-pn_delivery_tag_t pn_dtag(const char *bytes, size_t size) {
- pn_delivery_tag_t dtag = {size, bytes};
- return dtag;
-}
-
-pn_delivery_t *pn_delivery(pn_link_t *link, pn_delivery_tag_t tag)
-{
- assert(link);
- pn_list_t *pool = link->session->connection->delivery_pool;
- pn_delivery_t *delivery = (pn_delivery_t *) pn_list_pop(pool);
- if (!delivery) {
- static const pn_class_t clazz = PN_METACLASS(pn_delivery);
- delivery = (pn_delivery_t *) pn_class_new(&clazz, sizeof(pn_delivery_t));
- if (!delivery) return NULL;
- delivery->tag = pn_buffer(16);
- delivery->bytes = pn_buffer(64);
- pn_disposition_init(&delivery->local);
- pn_disposition_init(&delivery->remote);
- delivery->context = pn_record();
- } else {
- assert(!delivery->state.init);
- }
- delivery->link = link;
- pn_incref(delivery->link); // keep link until finalized
- pn_buffer_clear(delivery->tag);
- pn_buffer_append(delivery->tag, tag.start, tag.size);
- pn_disposition_clear(&delivery->local);
- pn_disposition_clear(&delivery->remote);
- delivery->updated = false;
- delivery->settled = false;
- LL_ADD(link, unsettled, delivery);
- delivery->referenced = true;
- delivery->work_next = NULL;
- delivery->work_prev = NULL;
- delivery->work = false;
- delivery->tpwork_next = NULL;
- delivery->tpwork_prev = NULL;
- delivery->tpwork = false;
- pn_buffer_clear(delivery->bytes);
- delivery->done = false;
- pn_record_clear(delivery->context);
-
- // begin delivery state
- delivery->state.init = false;
- delivery->state.sent = false;
- // end delivery state
-
- if (!link->current)
- link->current = delivery;
-
- link->unsettled_count++;
-
- pn_work_update(link->session->connection, delivery);
-
- // XXX: could just remove incref above
- pn_decref(delivery);
-
- return delivery;
-}
-
-bool pn_delivery_buffered(pn_delivery_t *delivery)
-{
- assert(delivery);
- if (delivery->settled) return false;
- if (pn_link_is_sender(delivery->link)) {
- pn_delivery_state_t *state = &delivery->state;
- if (state->sent) {
- return false;
- } else {
- return delivery->done || (pn_buffer_size(delivery->bytes) > 0);
- }
- } else {
- return false;
- }
-}
-
-int pn_link_unsettled(pn_link_t *link)
-{
- return link->unsettled_count;
-}
-
-pn_delivery_t *pn_unsettled_head(pn_link_t *link)
-{
- pn_delivery_t *d = link->unsettled_head;
- while (d && d->local.settled) {
- d = d->unsettled_next;
- }
- return d;
-}
-
-pn_delivery_t *pn_unsettled_next(pn_delivery_t *delivery)
-{
- pn_delivery_t *d = delivery->unsettled_next;
- while (d && d->local.settled) {
- d = d->unsettled_next;
- }
- return d;
-}
-
-bool pn_delivery_current(pn_delivery_t *delivery)
-{
- pn_link_t *link = delivery->link;
- return pn_link_current(link) == delivery;
-}
-
-void pn_delivery_dump(pn_delivery_t *d)
-{
- char tag[1024];
- pn_bytes_t bytes = pn_buffer_bytes(d->tag);
- pn_quote_data(tag, 1024, bytes.start, bytes.size);
- printf("{tag=%s, local.type=%" PRIu64 ", remote.type=%" PRIu64 ", local.settled=%u, "
- "remote.settled=%u, updated=%u, current=%u, writable=%u, readable=%u, "
- "work=%u}",
- tag, d->local.type, d->remote.type, d->local.settled,
- d->remote.settled, d->updated, pn_delivery_current(d),
- pn_delivery_writable(d), pn_delivery_readable(d), d->work);
-}
-
-void *pn_delivery_get_context(pn_delivery_t *delivery)
-{
- assert(delivery);
- return pn_record_get(delivery->context, PN_LEGCTX);
-}
-
-void pn_delivery_set_context(pn_delivery_t *delivery, void *context)
-{
- assert(delivery);
- pn_record_set(delivery->context, PN_LEGCTX, context);
-}
-
-pn_record_t *pn_delivery_attachments(pn_delivery_t *delivery)
-{
- assert(delivery);
- return delivery->context;
-}
-
-uint64_t pn_disposition_type(pn_disposition_t *disposition)
-{
- assert(disposition);
- return disposition->type;
-}
-
-pn_data_t *pn_disposition_data(pn_disposition_t *disposition)
-{
- assert(disposition);
- return disposition->data;
-}
-
-uint32_t pn_disposition_get_section_number(pn_disposition_t *disposition)
-{
- assert(disposition);
- return disposition->section_number;
-}
-
-void pn_disposition_set_section_number(pn_disposition_t *disposition, uint32_t section_number)
-{
- assert(disposition);
- disposition->section_number = section_number;
-}
-
-uint64_t pn_disposition_get_section_offset(pn_disposition_t *disposition)
-{
- assert(disposition);
- return disposition->section_offset;
-}
-
-void pn_disposition_set_section_offset(pn_disposition_t *disposition, uint64_t section_offset)
-{
- assert(disposition);
- disposition->section_offset = section_offset;
-}
-
-bool pn_disposition_is_failed(pn_disposition_t *disposition)
-{
- assert(disposition);
- return disposition->failed;
-}
-
-void pn_disposition_set_failed(pn_disposition_t *disposition, bool failed)
-{
- assert(disposition);
- disposition->failed = failed;
-}
-
-bool pn_disposition_is_undeliverable(pn_disposition_t *disposition)
-{
- assert(disposition);
- return disposition->undeliverable;
-}
-
-void pn_disposition_set_undeliverable(pn_disposition_t *disposition, bool undeliverable)
-{
- assert(disposition);
- disposition->undeliverable = undeliverable;
-}
-
-pn_data_t *pn_disposition_annotations(pn_disposition_t *disposition)
-{
- assert(disposition);
- return disposition->annotations;
-}
-
-pn_condition_t *pn_disposition_condition(pn_disposition_t *disposition)
-{
- assert(disposition);
- return &disposition->condition;
-}
-
-pn_delivery_tag_t pn_delivery_tag(pn_delivery_t *delivery)
-{
- if (delivery) {
- pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
- return pn_dtag(tag.start, tag.size);
- } else {
- return pn_dtag(0, 0);
- }
-}
-
-pn_delivery_t *pn_link_current(pn_link_t *link)
-{
- if (!link) return NULL;
- return link->current;
-}
-
-static void pni_advance_sender(pn_link_t *link)
-{
- link->current->done = true;
- link->queued++;
- link->credit--;
- link->session->outgoing_deliveries++;
- pni_add_tpwork(link->current);
- link->current = link->current->unsettled_next;
-}
-
-static void pni_advance_receiver(pn_link_t *link)
-{
- link->credit--;
- link->queued--;
- link->session->incoming_deliveries--;
-
- pn_delivery_t *current = link->current;
- link->session->incoming_bytes -= pn_buffer_size(current->bytes);
- pn_buffer_clear(current->bytes);
-
- if (!link->session->state.incoming_window) {
- pni_add_tpwork(current);
- }
-
- link->current = link->current->unsettled_next;
-}
-
-bool pn_link_advance(pn_link_t *link)
-{
- if (link && link->current) {
- pn_delivery_t *prev = link->current;
- if (link->endpoint.type == SENDER) {
- pni_advance_sender(link);
- } else {
- pni_advance_receiver(link);
- }
- pn_delivery_t *next = link->current;
- pn_work_update(link->session->connection, prev);
- if (next) pn_work_update(link->session->connection, next);
- return prev != next;
- } else {
- return false;
- }
-}
-
-int pn_link_credit(pn_link_t *link)
-{
- return link ? link->credit : 0;
-}
-
-int pn_link_available(pn_link_t *link)
-{
- return link ? link->available : 0;
-}
-
-int pn_link_queued(pn_link_t *link)
-{
- return link ? link->queued : 0;
-}
-
-int pn_link_remote_credit(pn_link_t *link)
-{
- assert(link);
- return link->credit - link->queued;
-}
-
-bool pn_link_get_drain(pn_link_t *link)
-{
- assert(link);
- return link->drain;
-}
-
-pn_snd_settle_mode_t pn_link_snd_settle_mode(pn_link_t *link)
-{
- return link ? (pn_snd_settle_mode_t)link->snd_settle_mode
- : PN_SND_MIXED;
-}
-
-pn_rcv_settle_mode_t pn_link_rcv_settle_mode(pn_link_t *link)
-{
- return link ? (pn_rcv_settle_mode_t)link->rcv_settle_mode
- : PN_RCV_FIRST;
-}
-
-pn_snd_settle_mode_t pn_link_remote_snd_settle_mode(pn_link_t *link)
-{
- return link ? (pn_snd_settle_mode_t)link->remote_snd_settle_mode
- : PN_SND_MIXED;
-}
-
-pn_rcv_settle_mode_t pn_link_remote_rcv_settle_mode(pn_link_t *link)
-{
- return link ? (pn_rcv_settle_mode_t)link->remote_rcv_settle_mode
- : PN_RCV_FIRST;
-}
-void pn_link_set_snd_settle_mode(pn_link_t *link, pn_snd_settle_mode_t mode)
-{
- if (link)
- link->snd_settle_mode = (uint8_t)mode;
-}
-void pn_link_set_rcv_settle_mode(pn_link_t *link, pn_rcv_settle_mode_t mode)
-{
- if (link)
- link->rcv_settle_mode = (uint8_t)mode;
-}
-
-void pn_delivery_settle(pn_delivery_t *delivery)
-{
- assert(delivery);
- if (!delivery->local.settled) {
- pn_link_t *link = delivery->link;
- if (pn_delivery_current(delivery)) {
- pn_link_advance(link);
- }
-
- link->unsettled_count--;
- delivery->local.settled = true;
- pni_add_tpwork(delivery);
- pn_work_update(delivery->link->session->connection, delivery);
- pn_incref(delivery);
- pn_decref(delivery);
- }
-}
-
-void pn_link_offered(pn_link_t *sender, int credit)
-{
- sender->available = credit;
-}
-
-ssize_t pn_link_send(pn_link_t *sender, const char *bytes, size_t n)
-{
- pn_delivery_t *current = pn_link_current(sender);
- if (!current) return PN_EOS;
- if (!bytes || !n) return 0;
- pn_buffer_append(current->bytes, bytes, n);
- sender->session->outgoing_bytes += n;
- pni_add_tpwork(current);
- return n;
-}
-
-int pn_link_drained(pn_link_t *link)
-{
- assert(link);
- int drained = 0;
-
- if (pn_link_is_sender(link)) {
- if (link->drain && link->credit > 0) {
- link->drained = link->credit;
- link->credit = 0;
- pn_modified(link->session->connection, &link->endpoint, true);
- drained = link->drained;
- }
- } else {
- drained = link->drained;
- link->drained = 0;
- }
-
- return drained;
-}
-
-ssize_t pn_link_recv(pn_link_t *receiver, char *bytes, size_t n)
-{
- if (!receiver) return PN_ARG_ERR;
-
- pn_delivery_t *delivery = receiver->current;
- if (delivery) {
- size_t size = pn_buffer_get(delivery->bytes, 0, n, bytes);
- pn_buffer_trim(delivery->bytes, size, 0);
- if (size) {
- receiver->session->incoming_bytes -= size;
- if (!receiver->session->state.incoming_window) {
- pni_add_tpwork(delivery);
- }
- return size;
- } else {
- return delivery->done ? PN_EOS : 0;
- }
- } else {
- return PN_STATE_ERR;
- }
-}
-
-void pn_link_flow(pn_link_t *receiver, int credit)
-{
- assert(receiver);
- assert(pn_link_is_receiver(receiver));
- receiver->credit += credit;
- pn_modified(receiver->session->connection, &receiver->endpoint, true);
- if (!receiver->drain_flag_mode) {
- pn_link_set_drain(receiver, false);
- receiver->drain_flag_mode = false;
- }
-}
-
-void pn_link_drain(pn_link_t *receiver, int credit)
-{
- assert(receiver);
- assert(pn_link_is_receiver(receiver));
- pn_link_set_drain(receiver, true);
- pn_link_flow(receiver, credit);
- receiver->drain_flag_mode = false;
-}
-
-void pn_link_set_drain(pn_link_t *receiver, bool drain)
-{
- assert(receiver);
- assert(pn_link_is_receiver(receiver));
- receiver->drain = drain;
- pn_modified(receiver->session->connection, &receiver->endpoint, true);
- receiver->drain_flag_mode = true;
-}
-
-bool pn_link_draining(pn_link_t *receiver)
-{
- assert(receiver);
- assert(pn_link_is_receiver(receiver));
- return receiver->drain && (pn_link_credit(receiver) > pn_link_queued(receiver));
-}
-
-pn_link_t *pn_delivery_link(pn_delivery_t *delivery)
-{
- assert(delivery);
- return delivery->link;
-}
-
-pn_disposition_t *pn_delivery_local(pn_delivery_t *delivery)
-{
- assert(delivery);
- return &delivery->local;
-}
-
-uint64_t pn_delivery_local_state(pn_delivery_t *delivery)
-{
- assert(delivery);
- return delivery->local.type;
-}
-
-pn_disposition_t *pn_delivery_remote(pn_delivery_t *delivery)
-{
- assert(delivery);
- return &delivery->remote;
-}
-
-uint64_t pn_delivery_remote_state(pn_delivery_t *delivery)
-{
- assert(delivery);
- return delivery->remote.type;
-}
-
-bool pn_delivery_settled(pn_delivery_t *delivery)
-{
- return delivery ? delivery->remote.settled : false;
-}
-
-bool pn_delivery_updated(pn_delivery_t *delivery)
-{
- return delivery ? delivery->updated : false;
-}
-
-void pn_delivery_clear(pn_delivery_t *delivery)
-{
- delivery->updated = false;
- pn_work_update(delivery->link->session->connection, delivery);
-}
-
-void pn_delivery_update(pn_delivery_t *delivery, uint64_t state)
-{
- if (!delivery) return;
- delivery->local.type = state;
- pni_add_tpwork(delivery);
-}
-
-bool pn_delivery_writable(pn_delivery_t *delivery)
-{
- if (!delivery) return false;
-
- pn_link_t *link = delivery->link;
- return pn_link_is_sender(link) && pn_delivery_current(delivery) && pn_link_credit(link) > 0;
-}
-
-bool pn_delivery_readable(pn_delivery_t *delivery)
-{
- if (delivery) {
- pn_link_t *link = delivery->link;
- return pn_link_is_receiver(link) && pn_delivery_current(delivery);
- } else {
- return false;
- }
-}
-
-size_t pn_delivery_pending(pn_delivery_t *delivery)
-{
- return pn_buffer_size(delivery->bytes);
-}
-
-bool pn_delivery_partial(pn_delivery_t *delivery)
-{
- return !delivery->done;
-}
-
-pn_condition_t *pn_connection_condition(pn_connection_t *connection)
-{
- assert(connection);
- return &connection->endpoint.condition;
-}
-
-pn_condition_t *pn_connection_remote_condition(pn_connection_t *connection)
-{
- assert(connection);
- pn_transport_t *transport = connection->transport;
- return transport ? &transport->remote_condition : NULL;
-}
-
-pn_condition_t *pn_session_condition(pn_session_t *session)
-{
- assert(session);
- return &session->endpoint.condition;
-}
-
-pn_condition_t *pn_session_remote_condition(pn_session_t *session)
-{
- assert(session);
- return &session->endpoint.remote_condition;
-}
-
-pn_condition_t *pn_link_condition(pn_link_t *link)
-{
- assert(link);
- return &link->endpoint.condition;
-}
-
-pn_condition_t *pn_link_remote_condition(pn_link_t *link)
-{
- assert(link);
- return &link->endpoint.remote_condition;
-}
-
-bool pn_condition_is_set(pn_condition_t *condition)
-{
- return condition && pn_string_get(condition->name);
-}
-
-void pn_condition_clear(pn_condition_t *condition)
-{
- assert(condition);
- pn_string_clear(condition->name);
- pn_string_clear(condition->description);
- pn_data_clear(condition->info);
-}
-
-const char *pn_condition_get_name(pn_condition_t *condition)
-{
- assert(condition);
- return pn_string_get(condition->name);
-}
-
-int pn_condition_set_name(pn_condition_t *condition, const char *name)
-{
- assert(condition);
- return pn_string_set(condition->name, name);
-}
-
-const char *pn_condition_get_description(pn_condition_t *condition)
-{
- assert(condition);
- return pn_string_get(condition->description);
-}
-
-int pn_condition_set_description(pn_condition_t *condition, const char *description)
-{
- assert(condition);
- return pn_string_set(condition->description, description);
-}
-
-int pn_condition_vformat(pn_condition_t *condition, const char *name, const char *fmt, va_list ap)
-{
- assert(condition);
- int err = pn_condition_set_name(condition, name);
- if (err)
- return err;
-
- char text[1024];
- size_t n = vsnprintf(text, 1024, fmt, ap);
- if (n >= sizeof(text))
- text[sizeof(text)-1] = '\0';
- err = pn_condition_set_description(condition, text);
- return err;
-}
-
-int pn_condition_format(pn_condition_t *condition, const char *name, const char *fmt, ...)
-{
- assert(condition);
- va_list ap;
- va_start(ap, fmt);
- int err = pn_condition_vformat(condition, name, fmt, ap);
- va_end(ap);
- return err;
-}
-
-pn_data_t *pn_condition_info(pn_condition_t *condition)
-{
- assert(condition);
- return condition->info;
-}
-
-bool pn_condition_is_redirect(pn_condition_t *condition)
-{
- const char *name = pn_condition_get_name(condition);
- return name && (!strcmp(name, "amqp:connection:redirect") ||
- !strcmp(name, "amqp:link:redirect"));
-}
-
-const char *pn_condition_redirect_host(pn_condition_t *condition)
-{
- pn_data_t *data = pn_condition_info(condition);
- pn_data_rewind(data);
- pn_data_next(data);
- pn_data_enter(data);
- pn_data_lookup(data, "network-host");
- pn_bytes_t host = pn_data_get_bytes(data);
- pn_data_rewind(data);
- return host.start;
-}
-
-int pn_condition_redirect_port(pn_condition_t *condition)
-{
- pn_data_t *data = pn_condition_info(condition);
- pn_data_rewind(data);
- pn_data_next(data);
- pn_data_enter(data);
- pn_data_lookup(data, "port");
- int port = pn_data_get_int(data);
- pn_data_rewind(data);
- return port;
-}
-
-pn_connection_t *pn_event_connection(pn_event_t *event)
-{
- pn_session_t *ssn;
- pn_transport_t *transport;
-
- switch (pn_class_id(pn_event_class(event))) {
- case CID_pn_connection:
- return (pn_connection_t *) pn_event_context(event);
- case CID_pn_transport:
- transport = pn_event_transport(event);
- if (transport)
- return transport->connection;
- return NULL;
- default:
- ssn = pn_event_session(event);
- if (ssn)
- return pn_session_connection(ssn);
- }
- return NULL;
-}
-
-pn_session_t *pn_event_session(pn_event_t *event)
-{
- pn_link_t *link;
- switch (pn_class_id(pn_event_class(event))) {
- case CID_pn_session:
- return (pn_session_t *) pn_event_context(event);
- default:
- link = pn_event_link(event);
- if (link)
- return pn_link_session(link);
- }
- return NULL;
-}
-
-pn_link_t *pn_event_link(pn_event_t *event)
-{
- pn_delivery_t *dlv;
- switch (pn_class_id(pn_event_class(event))) {
- case CID_pn_link:
- return (pn_link_t *) pn_event_context(event);
- default:
- dlv = pn_event_delivery(event);
- if (dlv)
- return pn_delivery_link(dlv);
- }
- return NULL;
-}
-
-pn_delivery_t *pn_event_delivery(pn_event_t *event)
-{
- switch (pn_class_id(pn_event_class(event))) {
- case CID_pn_delivery:
- return (pn_delivery_t *) pn_event_context(event);
- default:
- return NULL;
- }
-}
-
-pn_transport_t *pn_event_transport(pn_event_t *event)
-{
- switch (pn_class_id(pn_event_class(event))) {
- case CID_pn_transport:
- return (pn_transport_t *) pn_event_context(event);
- default:
- {
- pn_connection_t *conn = pn_event_connection(event);
- if (conn)
- return pn_connection_transport(conn);
- return NULL;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/error.c
----------------------------------------------------------------------
diff --git a/proton-c/src/error.c b/proton-c/src/error.c
deleted file mode 100644
index 9bef0fc..0000000
--- a/proton-c/src/error.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/error.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include "util.h"
-#include "platform.h"
-
-struct pn_error_t {
- char *text;
- pn_error_t *root;
- int code;
-};
-
-pn_error_t *pn_error()
-{
- pn_error_t *error = (pn_error_t *) malloc(sizeof(pn_error_t));
- if (error != NULL) {
- error->code = 0;
- error->text = NULL;
- error->root = NULL;
- }
- return error;
-}
-
-void pn_error_free(pn_error_t *error)
-{
- if (error) {
- free(error->text);
- free(error);
- }
-}
-
-void pn_error_clear(pn_error_t *error)
-{
- if (error) {
- error->code = 0;
- free(error->text);
- error->text = NULL;
- error->root = NULL;
- }
-}
-
-int pn_error_set(pn_error_t *error, int code, const char *text)
-{
- assert(error);
- pn_error_clear(error);
- if (code) {
- error->code = code;
- error->text = pn_strdup(text);
- }
- return code;
-}
-
-int pn_error_vformat(pn_error_t *error, int code, const char *fmt, va_list ap)
-{
- assert(error);
- char text[1024];
- int n = vsnprintf(text, 1024, fmt, ap);
- if (n >= 1024) {
- text[1023] = '\0';
- }
- return pn_error_set(error, code, text);
-}
-
-int pn_error_format(pn_error_t *error, int code, const char *fmt, ...)
-{
- assert(error);
- va_list ap;
- va_start(ap, fmt);
- int rcode = pn_error_vformat(error, code, fmt, ap);
- va_end(ap);
- return rcode;
-}
-
-int pn_error_code(pn_error_t *error)
-{
- assert(error);
- return error->code;
-}
-
-const char *pn_error_text(pn_error_t *error)
-{
- assert(error);
- return error->text;
-}
-
-int pn_error_copy(pn_error_t *error, pn_error_t *src)
-{
- assert(error);
- if (src) {
- return pn_error_set(error, pn_error_code(src), pn_error_text(src));
- } else {
- pn_error_clear(error);
- return 0;
- }
-}
-
-const char *pn_code(int code)
-{
- switch (code)
- {
- case 0: return "<ok>";
- case PN_EOS: return "PN_EOS";
- case PN_ERR: return "PN_ERR";
- case PN_OVERFLOW: return "PN_OVERFLOW";
- case PN_UNDERFLOW: return "PN_UNDERFLOW";
- case PN_STATE_ERR: return "PN_STATE_ERR";
- case PN_ARG_ERR: return "PN_ARG_ERR";
- case PN_TIMEOUT: return "PN_TIMEOUT";
- case PN_INTR: return "PN_INTR";
- case PN_OUT_OF_MEMORY: return "PN_OUT_OF_MEMORY";
- default: return "<unknown>";
- }
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/events/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/events/event.c b/proton-c/src/events/event.c
deleted file mode 100644
index 5ad718e..0000000
--- a/proton-c/src/events/event.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include <stdio.h>
-#include <proton/object.h>
-#include <proton/event.h>
-#include <proton/reactor.h>
-#include <assert.h>
-
-struct pn_collector_t {
- pn_list_t *pool;
- pn_event_t *head;
- pn_event_t *tail;
- bool freed;
-};
-
-struct pn_event_t {
- pn_list_t *pool;
- const pn_class_t *clazz;
- void *context; // depends on clazz
- pn_record_t *attachments;
- pn_event_t *next;
- pn_event_type_t type;
-};
-
-static void pn_collector_initialize(pn_collector_t *collector)
-{
- collector->pool = pn_list(PN_OBJECT, 0);
- collector->head = NULL;
- collector->tail = NULL;
- collector->freed = false;
-}
-
-static void pn_collector_drain(pn_collector_t *collector)
-{
- assert(collector);
-
- while (pn_collector_peek(collector)) {
- pn_collector_pop(collector);
- }
-
- assert(!collector->head);
- assert(!collector->tail);
-}
-
-static void pn_collector_shrink(pn_collector_t *collector)
-{
- assert(collector);
- pn_list_clear(collector->pool);
-}
-
-static void pn_collector_finalize(pn_collector_t *collector)
-{
- pn_collector_drain(collector);
- pn_decref(collector->pool);
-}
-
-static int pn_collector_inspect(pn_collector_t *collector, pn_string_t *dst)
-{
- assert(collector);
- int err = pn_string_addf(dst, "EVENTS[");
- if (err) return err;
- pn_event_t *event = collector->head;
- bool first = true;
- while (event) {
- if (first) {
- first = false;
- } else {
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- }
- err = pn_inspect(event, dst);
- if (err) return err;
- event = event->next;
- }
- return pn_string_addf(dst, "]");
-}
-
-#define pn_collector_hashcode NULL
-#define pn_collector_compare NULL
-
-PN_CLASSDEF(pn_collector)
-
-pn_collector_t *pn_collector(void)
-{
- return pn_collector_new();
-}
-
-void pn_collector_free(pn_collector_t *collector)
-{
- assert(collector);
- pn_collector_release(collector);
- pn_decref(collector);
-}
-
-void pn_collector_release(pn_collector_t *collector)
-{
- assert(collector);
- if (!collector->freed) {
- collector->freed = true;
- pn_collector_drain(collector);
- pn_collector_shrink(collector);
- }
-}
-
-pn_event_t *pn_event(void);
-
-pn_event_t *pn_collector_put(pn_collector_t *collector,
- const pn_class_t *clazz, void *context,
- pn_event_type_t type)
-{
- if (!collector) {
- return NULL;
- }
-
- assert(context);
-
- if (collector->freed) {
- return NULL;
- }
-
- pn_event_t *tail = collector->tail;
- if (tail && tail->type == type && tail->context == context) {
- return NULL;
- }
-
- clazz = clazz->reify(context);
-
- pn_event_t *event = (pn_event_t *) pn_list_pop(collector->pool);
-
- if (!event) {
- event = pn_event();
- }
-
- event->pool = collector->pool;
- pn_incref(event->pool);
-
- if (tail) {
- tail->next = event;
- collector->tail = event;
- } else {
- collector->tail = event;
- collector->head = event;
- }
-
- event->clazz = clazz;
- event->context = context;
- event->type = type;
- pn_class_incref(clazz, event->context);
-
- return event;
-}
-
-pn_event_t *pn_collector_peek(pn_collector_t *collector)
-{
- return collector->head;
-}
-
-bool pn_collector_pop(pn_collector_t *collector)
-{
- pn_event_t *event = collector->head;
- if (event) {
- collector->head = event->next;
- } else {
- return false;
- }
-
- if (!collector->head) {
- collector->tail = NULL;
- }
-
- pn_decref(event);
- return true;
-}
-
-bool pn_collector_more(pn_collector_t *collector)
-{
- assert(collector);
- return collector->head && collector->head->next;
-}
-
-static void pn_event_initialize(pn_event_t *event)
-{
- event->pool = NULL;
- event->type = PN_EVENT_NONE;
- event->clazz = NULL;
- event->context = NULL;
- event->next = NULL;
- event->attachments = pn_record();
-}
-
-static void pn_event_finalize(pn_event_t *event) {
- // decref before adding to the free list
- if (event->clazz && event->context) {
- pn_class_decref(event->clazz, event->context);
- }
-
- pn_list_t *pool = event->pool;
-
- if (pool && pn_refcount(pool) > 1) {
- event->pool = NULL;
- event->type = PN_EVENT_NONE;
- event->clazz = NULL;
- event->context = NULL;
- event->next = NULL;
- pn_record_clear(event->attachments);
- pn_list_add(pool, event);
- } else {
- pn_decref(event->attachments);
- }
-
- pn_decref(pool);
-}
-
-static int pn_event_inspect(pn_event_t *event, pn_string_t *dst)
-{
- assert(event);
- assert(dst);
- const char *name = pn_event_type_name(event->type);
- int err;
- if (name) {
- err = pn_string_addf(dst, "(%s", pn_event_type_name(event->type));
- } else {
- err = pn_string_addf(dst, "(<%u>", (unsigned int) event->type);
- }
- if (err) return err;
- if (event->context) {
- err = pn_string_addf(dst, ", ");
- if (err) return err;
- err = pn_class_inspect(event->clazz, event->context, dst);
- if (err) return err;
- }
-
- return pn_string_addf(dst, ")");
-}
-
-#define pn_event_hashcode NULL
-#define pn_event_compare NULL
-
-PN_CLASSDEF(pn_event)
-
-pn_event_t *pn_event(void)
-{
- return pn_event_new();
-}
-
-pn_event_type_t pn_event_type(pn_event_t *event)
-{
- return event->type;
-}
-
-const pn_class_t *pn_event_class(pn_event_t *event)
-{
- assert(event);
- return event->clazz;
-}
-
-void *pn_event_context(pn_event_t *event)
-{
- assert(event);
- return event->context;
-}
-
-pn_record_t *pn_event_attachments(pn_event_t *event)
-{
- assert(event);
- return event->attachments;
-}
-
-pn_handler_t *pn_event_root(pn_event_t *event)
-{
- assert(event);
- pn_handler_t *h = pn_record_get_handler(event->attachments);
- return h;
-}
-
-void pni_event_set_root(pn_event_t *event, pn_handler_t *handler) {
- pn_record_set_handler(event->attachments, handler);
-}
-
-const char *pn_event_type_name(pn_event_type_t type)
-{
- switch (type) {
- case PN_EVENT_NONE:
- return "PN_EVENT_NONE";
- case PN_REACTOR_INIT:
- return "PN_REACTOR_INIT";
- case PN_REACTOR_QUIESCED:
- return "PN_REACTOR_QUIESCED";
- case PN_REACTOR_FINAL:
- return "PN_REACTOR_FINAL";
- case PN_TIMER_TASK:
- return "PN_TIMER_TASK";
- case PN_CONNECTION_INIT:
- return "PN_CONNECTION_INIT";
- case PN_CONNECTION_BOUND:
- return "PN_CONNECTION_BOUND";
- case PN_CONNECTION_UNBOUND:
- return "PN_CONNECTION_UNBOUND";
- case PN_CONNECTION_REMOTE_OPEN:
- return "PN_CONNECTION_REMOTE_OPEN";
- case PN_CONNECTION_LOCAL_OPEN:
- return "PN_CONNECTION_LOCAL_OPEN";
- case PN_CONNECTION_REMOTE_CLOSE:
- return "PN_CONNECTION_REMOTE_CLOSE";
- case PN_CONNECTION_LOCAL_CLOSE:
- return "PN_CONNECTION_LOCAL_CLOSE";
- case PN_CONNECTION_FINAL:
- return "PN_CONNECTION_FINAL";
- case PN_SESSION_INIT:
- return "PN_SESSION_INIT";
- case PN_SESSION_REMOTE_OPEN:
- return "PN_SESSION_REMOTE_OPEN";
- case PN_SESSION_LOCAL_OPEN:
- return "PN_SESSION_LOCAL_OPEN";
- case PN_SESSION_REMOTE_CLOSE:
- return "PN_SESSION_REMOTE_CLOSE";
- case PN_SESSION_LOCAL_CLOSE:
- return "PN_SESSION_LOCAL_CLOSE";
- case PN_SESSION_FINAL:
- return "PN_SESSION_FINAL";
- case PN_LINK_INIT:
- return "PN_LINK_INIT";
- case PN_LINK_REMOTE_OPEN:
- return "PN_LINK_REMOTE_OPEN";
- case PN_LINK_LOCAL_OPEN:
- return "PN_LINK_LOCAL_OPEN";
- case PN_LINK_REMOTE_CLOSE:
- return "PN_LINK_REMOTE_CLOSE";
- case PN_LINK_LOCAL_DETACH:
- return "PN_LINK_LOCAL_DETACH";
- case PN_LINK_REMOTE_DETACH:
- return "PN_LINK_REMOTE_DETACH";
- case PN_LINK_LOCAL_CLOSE:
- return "PN_LINK_LOCAL_CLOSE";
- case PN_LINK_FLOW:
- return "PN_LINK_FLOW";
- case PN_LINK_FINAL:
- return "PN_LINK_FINAL";
- case PN_DELIVERY:
- return "PN_DELIVERY";
- case PN_TRANSPORT:
- return "PN_TRANSPORT";
- case PN_TRANSPORT_AUTHENTICATED:
- return "PN_TRANSPORT_AUTHENTICATED";
- case PN_TRANSPORT_ERROR:
- return "PN_TRANSPORT_ERROR";
- case PN_TRANSPORT_HEAD_CLOSED:
- return "PN_TRANSPORT_HEAD_CLOSED";
- case PN_TRANSPORT_TAIL_CLOSED:
- return "PN_TRANSPORT_TAIL_CLOSED";
- case PN_TRANSPORT_CLOSED:
- return "PN_TRANSPORT_CLOSED";
- case PN_SELECTABLE_INIT:
- return "PN_SELECTABLE_INIT";
- case PN_SELECTABLE_UPDATED:
- return "PN_SELECTABLE_UPDATED";
- case PN_SELECTABLE_READABLE:
- return "PN_SELECTABLE_READABLE";
- case PN_SELECTABLE_WRITABLE:
- return "PN_SELECTABLE_WRITABLE";
- case PN_SELECTABLE_ERROR:
- return "PN_SELECTABLE_ERROR";
- case PN_SELECTABLE_EXPIRED:
- return "PN_SELECTABLE_EXPIRED";
- case PN_SELECTABLE_FINAL:
- return "PN_SELECTABLE_FINAL";
- }
-
- return NULL;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/parser.c
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/parser.c b/proton-c/src/extra/parser.c
new file mode 100644
index 0000000..36fb4fb
--- /dev/null
+++ b/proton-c/src/extra/parser.c
@@ -0,0 +1,423 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/parser.h>
+
+#include "platform/platform.h"
+#include "scanner.h"
+
+#include <proton/error.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+struct pn_parser_t {
+ pn_scanner_t *scanner;
+ char *atoms;
+ size_t size;
+ size_t capacity;
+ int error_code;
+};
+
+pn_parser_t *pn_parser()
+{
+ pn_parser_t *parser = (pn_parser_t *) malloc(sizeof(pn_parser_t));
+ if (parser != NULL) {
+ parser->scanner = pn_scanner();
+ parser->atoms = NULL;
+ parser->size = 0;
+ parser->capacity = 0;
+ }
+ return parser;
+}
+
+static void pni_parser_ensure(pn_parser_t *parser, size_t size)
+{
+ while (parser->capacity - parser->size < size) {
+ parser->capacity = parser->capacity ? 2 * parser->capacity : 1024;
+ parser->atoms = (char *) realloc(parser->atoms, parser->capacity);
+ }
+}
+
+int pn_parser_err(pn_parser_t *parser, int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int err = pn_scanner_verr(parser->scanner, code, fmt, ap);
+ va_end(ap);
+ return err;
+}
+
+int pn_parser_errno(pn_parser_t *parser)
+{
+ return pn_scanner_errno(parser->scanner);
+}
+
+const char *pn_parser_error(pn_parser_t *parser)
+{
+ return pn_scanner_error(parser->scanner);
+}
+
+void pn_parser_free(pn_parser_t *parser)
+{
+ if (parser) {
+ pn_scanner_free(parser->scanner);
+ free(parser->atoms);
+ free(parser);
+ }
+}
+
+static int pni_parser_shift(pn_parser_t *parser)
+{
+ return pn_scanner_shift(parser->scanner);
+}
+
+static pn_token_t pni_parser_token(pn_parser_t *parser)
+{
+ return pn_scanner_token(parser->scanner);
+}
+
+static int pni_parser_value(pn_parser_t *parser, pn_data_t *data);
+
+static int pni_parser_descriptor(pn_parser_t *parser, pn_data_t *data)
+{
+ if (pni_parser_token(parser).type == PN_TOK_AT) {
+ int err = pni_parser_shift(parser);
+ if (err) return err;
+
+ err = pn_data_put_described(data);
+ if (err) return pn_parser_err(parser, err, "error writing described");
+ pn_data_enter(data);
+ for (int i = 0; i < 2; i++) {
+ err = pni_parser_value(parser, data);
+ if (err) return err;
+ }
+ pn_data_exit(data);
+ return 0;
+ } else {
+ return pn_parser_err(parser, PN_ERR, "expecting '@'");
+ }
+}
+
+static int pni_parser_map(pn_parser_t *parser, pn_data_t *data)
+{
+ if (pni_parser_token(parser).type == PN_TOK_LBRACE) {
+ int err = pni_parser_shift(parser);
+ if (err) return err;
+
+ err = pn_data_put_map(data);
+ if (err) return pn_parser_err(parser, err, "error writing map");
+
+ pn_data_enter(data);
+
+ if (pni_parser_token(parser).type != PN_TOK_RBRACE) {
+ while (true) {
+ err = pni_parser_value(parser, data);
+ if (err) return err;
+
+ if (pni_parser_token(parser).type == PN_TOK_EQUAL) {
+ err = pni_parser_shift(parser);
+ if (err) return err;
+ } else {
+ return pn_parser_err(parser, PN_ERR, "expecting '='");
+ }
+
+ err = pni_parser_value(parser, data);
+ if (err) return err;
+
+ if (pni_parser_token(parser).type == PN_TOK_COMMA) {
+ err = pni_parser_shift(parser);
+ if (err) return err;
+ } else {
+ break;
+ }
+ }
+ }
+
+ pn_data_exit(data);
+
+ if (pni_parser_token(parser).type == PN_TOK_RBRACE) {
+ return pni_parser_shift(parser);
+ } else {
+ return pn_parser_err(parser, PN_ERR, "expecting '}'");
+ }
+ } else {
+ return pn_parser_err(parser, PN_ERR, "expecting '{'");
+ }
+}
+
+static int pni_parser_list(pn_parser_t *parser, pn_data_t *data)
+{
+ int err;
+
+ if (pni_parser_token(parser).type == PN_TOK_LBRACKET) {
+ err = pni_parser_shift(parser);
+ if (err) return err;
+
+ err = pn_data_put_list(data);
+ if (err) return pn_parser_err(parser, err, "error writing list");
+
+ pn_data_enter(data);
+
+ if (pni_parser_token(parser).type != PN_TOK_RBRACKET) {
+ while (true) {
+ err = pni_parser_value(parser, data);
+ if (err) return err;
+
+ if (pni_parser_token(parser).type == PN_TOK_COMMA) {
+ err = pni_parser_shift(parser);
+ if (err) return err;
+ } else {
+ break;
+ }
+ }
+ }
+
+ pn_data_exit(data);
+
+ if (pni_parser_token(parser).type == PN_TOK_RBRACKET) {
+ return pni_parser_shift(parser);
+ } else {
+ return pn_parser_err(parser, PN_ERR, "expecting ']'");
+ }
+ } else {
+ return pn_parser_err(parser, PN_ERR, "expecting '['");
+ }
+}
+
+static void pni_parser_append_tok(pn_parser_t *parser, char *dst, int *idx)
+{
+ memcpy(dst + *idx, pni_parser_token(parser).start, pni_parser_token(parser).size);
+ *idx += pni_parser_token(parser).size;
+}
+
+static int pni_parser_number(pn_parser_t *parser, pn_data_t *data)
+{
+ bool dbl = false;
+ char number[1024];
+ int idx = 0;
+ int err;
+
+ bool negate = false;
+
+ if (pni_parser_token(parser).type == PN_TOK_NEG || pni_parser_token(parser).type == PN_TOK_POS) {
+ if (pni_parser_token(parser).type == PN_TOK_NEG)
+ negate = !negate;
+ err = pni_parser_shift(parser);
+ if (err) return err;
+ }
+
+ if (pni_parser_token(parser).type == PN_TOK_FLOAT || pni_parser_token(parser).type == PN_TOK_INT) {
+ dbl = pni_parser_token(parser).type == PN_TOK_FLOAT;
+ pni_parser_append_tok(parser, number, &idx);
+ err = pni_parser_shift(parser);
+ if (err) return err;
+ } else {
+ return pn_parser_err(parser, PN_ERR, "expecting FLOAT or INT");
+ }
+
+ number[idx] = '\0';
+
+ if (dbl) {
+ double value = atof(number);
+ if (negate) {
+ value = -value;
+ }
+ err = pn_data_put_double(data, value);
+ if (err) return pn_parser_err(parser, err, "error writing double");
+ } else {
+ int64_t value = pn_i_atoll(number);
+ if (negate) {
+ value = -value;
+ }
+ err = pn_data_put_long(data, value);
+ if (err) return pn_parser_err(parser, err, "error writing long");
+ }
+
+ return 0;
+}
+
+static int pni_parser_unquote(pn_parser_t *parser, char *dst, const char *src, size_t *n)
+{
+ size_t idx = 0;
+ bool escape = false;
+ int start, end;
+ if (src[0] != '"') {
+ if (src[1] == '"') {
+ start = 2;
+ end = *n - 1;
+ } else {
+ start = 1;
+ end = *n;
+ }
+ } else {
+ start = 1;
+ end = *n - 1;
+ }
+ for (int i = start; i < end; i++)
+ {
+ char c = src[i];
+ if (escape) {
+ switch (c) {
+ case '"':
+ case '\\':
+ case '/':
+ dst[idx++] = c;
+ escape = false;
+ break;
+ case 'b':
+ dst[idx++] = '\b';
+ break;
+ case 'f':
+ dst[idx++] = '\f';
+ break;
+ case 'n':
+ dst[idx++] = '\n';
+ break;
+ case 'r':
+ dst[idx++] = '\r';
+ break;
+ case 't':
+ dst[idx++] = '\t';
+ break;
+ case 'x':
+ {
+ char n1 = toupper(src[i+1]);
+ char n2 = n1 ? toupper(src[i+2]) : 0;
+ if (!n2) {
+ return pn_parser_err(parser, PN_ERR, "truncated escape code");
+ }
+ int d1 = isdigit(n1) ? n1 - '0' : n1 - 'A' + 10;
+ int d2 = isdigit(n2) ? n2 - '0' : n2 - 'A' + 10;
+ dst[idx++] = d1*16 + d2;
+ i += 2;
+ }
+ break;
+ // XXX: need to handle unicode escapes: 'u'
+ default:
+ return pn_parser_err(parser, PN_ERR, "unrecognized escape code");
+ }
+ escape = false;
+ } else {
+ switch (c)
+ {
+ case '\\':
+ escape = true;
+ break;
+ default:
+ dst[idx++] = c;
+ break;
+ }
+ }
+ }
+ dst[idx++] = '\0';
+ *n = idx;
+ return 0;
+}
+
+static int pni_parser_value(pn_parser_t *parser, pn_data_t *data)
+{
+ int err;
+ size_t n;
+ char *dst;
+
+ pn_token_t tok = pni_parser_token(parser);
+
+ switch (tok.type)
+ {
+ case PN_TOK_AT:
+ return pni_parser_descriptor(parser, data);
+ case PN_TOK_LBRACE:
+ return pni_parser_map(parser, data);
+ case PN_TOK_LBRACKET:
+ return pni_parser_list(parser, data);
+ case PN_TOK_BINARY:
+ case PN_TOK_SYMBOL:
+ case PN_TOK_STRING:
+ n = tok.size;
+ pni_parser_ensure(parser, n);
+ dst = parser->atoms + parser->size;
+ err = pni_parser_unquote(parser, dst, tok.start, &n);
+ if (err) return err;
+ parser->size += n;
+ switch (tok.type) {
+ case PN_TOK_BINARY:
+ err = pn_data_put_binary(data, pn_bytes(n - 1, dst));
+ break;
+ case PN_TOK_STRING:
+ err = pn_data_put_string(data, pn_bytes(n - 1, dst));
+ break;
+ case PN_TOK_SYMBOL:
+ err = pn_data_put_symbol(data, pn_bytes(n - 1, dst));
+ break;
+ default:
+ return pn_parser_err(parser, PN_ERR, "internal error");
+ }
+ if (err) return pn_parser_err(parser, err, "error writing string/binary/symbol");
+ return pni_parser_shift(parser);
+ case PN_TOK_POS:
+ case PN_TOK_NEG:
+ case PN_TOK_FLOAT:
+ case PN_TOK_INT:
+ return pni_parser_number(parser, data);
+ case PN_TOK_TRUE:
+ err = pn_data_put_bool(data, true);
+ if (err) return pn_parser_err(parser, err, "error writing boolean");
+ return pni_parser_shift(parser);
+ case PN_TOK_FALSE:
+ err = pn_data_put_bool(data, false);
+ if (err) return pn_parser_err(parser, err, "error writing boolean");
+ return pni_parser_shift(parser);
+ case PN_TOK_NULL:
+ err = pn_data_put_null(data);
+ if (err) return pn_parser_err(parser, err, "error writing null");
+ return pni_parser_shift(parser);
+ default:
+ return pn_parser_err(parser, PN_ERR, "expecting one of '[', '{', STRING, "
+ "SYMBOL, BINARY, true, false, null, NUMBER");
+ }
+}
+
+static int pni_parser_parse_r(pn_parser_t *parser, pn_data_t *data)
+{
+ while (true) {
+ int err;
+ switch (pni_parser_token(parser).type)
+ {
+ case PN_TOK_EOS:
+ return 0;
+ case PN_TOK_ERR:
+ return PN_ERR;
+ default:
+ err = pni_parser_value(parser, data);
+ if (err) return err;
+ }
+ }
+}
+
+int pn_parser_parse(pn_parser_t *parser, const char *str, pn_data_t *data)
+{
+ int err = pn_scanner_start(parser->scanner, str);
+ if (err) return err;
+ parser->size = 0;
+ return pni_parser_parse_r(parser, data);
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[19/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
PROTON-1350 PROTON-1351: Introduce proton-c core library
- Created new core proton library qpid-proton-core which only contains
protocol processsing and no IO.
- Rearranged source tree to separate core protocol code and io/reactor/extra code
- Rearranged code so that compiler dependent code is isolated and platform (OS)
dependent code is isolated
This is a large change, but the majority is moving files around and fixing up the header
includes. There is a small amount of internal API changing so support the core searation.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a5850716
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a5850716
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a5850716
Branch: refs/heads/master
Commit: a58507161cb839d14ecd3c36477747de59725554
Parents: efd033c
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Nov 14 12:55:01 2016 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 14 12:55:01 2016 -0500
----------------------------------------------------------------------
proton-c/CMakeLists.txt | 162 +-
proton-c/bindings/python/proton/reactor.py | 4 +-
proton-c/bindings/python/setup.py | 10 +-
proton-c/bindings/ruby/lib/reactor/reactor.rb | 6 +-
proton-c/include/proton/cproton.i | 2 -
proton-c/include/proton/event.h | 5 -
proton-c/include/proton/handlers.h | 6 +-
proton-c/include/proton/import_export.h | 10 +-
proton-c/include/proton/io.h | 114 -
proton-c/include/proton/messenger.h | 124 +-
proton-c/include/proton/reactor.h | 112 +-
proton-c/include/proton/scanner.h | 82 -
proton-c/include/proton/selectable.h | 89 +-
proton-c/include/proton/selector.h | 51 -
proton-c/include/proton/types.h | 4 -
proton-c/include/proton/url.h | 34 +-
proton-c/src/ProtonConfig.cmake.in | 3 +
proton-c/src/buffer.c | 310 --
proton-c/src/buffer.h | 54 -
proton-c/src/codec/codec.c | 2142 -------------
proton-c/src/codec/data.h | 75 -
proton-c/src/codec/decoder.c | 497 ---
proton-c/src/codec/decoder.h | 30 -
proton-c/src/codec/encoder.c | 383 ---
proton-c/src/codec/encoder.h | 31 -
proton-c/src/codec/encodings.h.py | 42 -
proton-c/src/codec/types.xml | 125 -
proton-c/src/compiler/msvc/snprintf.c | 52 +
proton-c/src/config.h | 32 -
proton-c/src/core/autodetect.c | 135 +
proton-c/src/core/autodetect.h | 40 +
proton-c/src/core/buffer.c | 310 ++
proton-c/src/core/buffer.h | 54 +
proton-c/src/core/codec.c | 2141 +++++++++++++
proton-c/src/core/config.h | 32 +
proton-c/src/core/connection_engine.c | 124 +
proton-c/src/core/data.h | 75 +
proton-c/src/core/decoder.c | 497 +++
proton-c/src/core/decoder.h | 30 +
proton-c/src/core/dispatch_actions.h | 49 +
proton-c/src/core/dispatcher.c | 158 +
proton-c/src/core/dispatcher.h | 37 +
proton-c/src/core/encoder.c | 383 +++
proton-c/src/core/encoder.h | 31 +
proton-c/src/core/engine-internal.h | 375 +++
proton-c/src/core/engine.c | 2231 +++++++++++++
proton-c/src/core/error.c | 136 +
proton-c/src/core/event.c | 377 +++
proton-c/src/core/framing.c | 103 +
proton-c/src/core/framing.h | 44 +
proton-c/src/core/log.c | 71 +
proton-c/src/core/log_private.h | 54 +
proton-c/src/core/message.c | 862 +++++
proton-c/src/core/object/iterator.c | 78 +
proton-c/src/core/object/list.c | 267 ++
proton-c/src/core/object/map.c | 461 +++
proton-c/src/core/object/object.c | 312 ++
proton-c/src/core/object/record.c | 153 +
proton-c/src/core/object/string.c | 269 ++
proton-c/src/core/transport.c | 3019 ++++++++++++++++++
proton-c/src/core/transport.h | 31 +
proton-c/src/core/types.c | 34 +
proton-c/src/core/util.c | 165 +
proton-c/src/core/util.h | 123 +
proton-c/src/dispatch_actions.h | 49 -
proton-c/src/dispatcher/dispatcher.c | 158 -
proton-c/src/dispatcher/dispatcher.h | 37 -
proton-c/src/encodings.h.py | 42 +
proton-c/src/engine/connection_engine.c | 124 -
proton-c/src/engine/engine-internal.h | 374 ---
proton-c/src/engine/engine.c | 2231 -------------
proton-c/src/error.c | 135 -
proton-c/src/events/event.c | 388 ---
proton-c/src/extra/parser.c | 423 +++
proton-c/src/extra/scanner.c | 399 +++
proton-c/src/extra/scanner.h | 74 +
proton-c/src/extra/url.c | 272 ++
proton-c/src/framing/framing.c | 103 -
proton-c/src/framing/framing.h | 52 -
proton-c/src/handlers/iohandler.c | 7 +-
proton-c/src/libqpid-proton-core.pc.in | 30 +
proton-c/src/log.c | 70 -
proton-c/src/log_private.h | 54 -
proton-c/src/message/message.c | 861 -----
proton-c/src/messenger/messenger.c | 18 +-
proton-c/src/messenger/store.c | 2 +-
proton-c/src/messenger/store.h | 2 +-
proton-c/src/messenger/transform.h | 3 +-
proton-c/src/object/iterator.c | 78 -
proton-c/src/object/list.c | 267 --
proton-c/src/object/map.c | 461 ---
proton-c/src/object/object.c | 312 --
proton-c/src/object/record.c | 153 -
proton-c/src/object/string.c | 270 --
proton-c/src/parser.c | 420 ---
proton-c/src/platform.c | 134 -
proton-c/src/platform.h | 101 -
proton-c/src/platform/platform.c | 122 +
proton-c/src/platform/platform.h | 93 +
proton-c/src/platform/platform_fmt.h | 85 +
proton-c/src/platform_fmt.h | 85 -
proton-c/src/posix/io.c | 342 --
proton-c/src/posix/selector.c | 211 --
proton-c/src/reactor/acceptor.c | 13 +-
proton-c/src/reactor/connection.c | 19 +-
proton-c/src/reactor/io.h | 70 +
proton-c/src/reactor/io/posix/io.c | 342 ++
proton-c/src/reactor/io/posix/selector.c | 214 ++
proton-c/src/reactor/io/windows/io.c | 459 +++
proton-c/src/reactor/io/windows/iocp.c | 1179 +++++++
proton-c/src/reactor/io/windows/iocp.h | 136 +
proton-c/src/reactor/io/windows/selector.c | 384 +++
.../src/reactor/io/windows/write_pipeline.c | 314 ++
proton-c/src/reactor/reactor.c | 23 +-
proton-c/src/reactor/reactor.h | 2 +-
proton-c/src/reactor/selectable.c | 300 ++
proton-c/src/reactor/selectable.h | 36 +
proton-c/src/reactor/selector.h | 53 +
proton-c/src/sasl/cyrus_sasl.c | 4 +-
proton-c/src/sasl/none_sasl.c | 2 +-
proton-c/src/sasl/sasl-internal.h | 5 +-
proton-c/src/sasl/sasl.c | 9 +-
proton-c/src/scanner.c | 397 ---
proton-c/src/selectable.c | 297 --
proton-c/src/selectable.h | 36 -
proton-c/src/ssl/openssl.c | 13 +-
proton-c/src/ssl/schannel.c | 2239 +++++++++++++
proton-c/src/ssl/ssl_stub.c | 2 +-
proton-c/src/tests/data.c | 2 +-
proton-c/src/transport/autodetect.c | 135 -
proton-c/src/transport/autodetect.h | 40 -
proton-c/src/transport/transport.c | 3018 -----------------
proton-c/src/transport/transport.h | 31 -
proton-c/src/types.c | 41 -
proton-c/src/types.xml | 125 +
proton-c/src/url.c | 186 --
proton-c/src/util.c | 274 --
proton-c/src/util.h | 126 -
proton-c/src/windows/io.c | 457 ---
proton-c/src/windows/iocp.c | 1176 -------
proton-c/src/windows/iocp.h | 144 -
proton-c/src/windows/schannel.c | 2239 -------------
proton-c/src/windows/selector.c | 382 ---
proton-c/src/windows/write_pipeline.c | 312 --
tools/cmake/Modules/WindowsC99SymbolCheck.py | 2 +-
145 files changed, 21103 insertions(+), 21029 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index cba043a..3cf01cd 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -81,8 +81,8 @@ set (env_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py)
add_custom_command (
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
- COMMAND ${env_py} PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py
+ COMMAND ${env_py} PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/encodings.h.py
)
add_custom_command (
@@ -93,11 +93,11 @@ add_custom_command (
# Select IO impl
if(PN_WINAPI)
- set (pn_io_impl src/windows/io.c src/windows/iocp.c src/windows/write_pipeline.c)
- set (pn_selector_impl src/windows/selector.c)
+ set (pn_io_impl src/reactor/io/windows/io.c src/reactor/io/windows/iocp.c src/reactor/io/windows/write_pipeline.c)
+ set (pn_selector_impl src/reactor/io/windows/selector.c)
else(PN_WINAPI)
- set (pn_io_impl src/posix/io.c)
- set (pn_selector_impl src/posix/selector.c)
+ set (pn_io_impl src/reactor/io/posix/io.c)
+ set (pn_selector_impl src/reactor/io/posix/selector.c)
endif(PN_WINAPI)
# Link in SASL if present
@@ -124,7 +124,7 @@ if (SSL_IMPL STREQUAL openssl)
include_directories (${OPENSSL_INCLUDE_DIR})
set (SSL_LIB ${OPENSSL_LIBRARIES})
elseif (SSL_IMPL STREQUAL schannel)
- set (pn_ssl_impl src/windows/schannel.c)
+ set (pn_ssl_impl src/ssl/schannel.c)
set (SSL_LIB Crypt32.lib Secur32.lib)
else ()
set (pn_ssl_impl src/ssl/ssl_stub.c)
@@ -281,6 +281,7 @@ if (MSVC)
/wd4800
/wd4996
)
+ set (qpid-proton-platform src/compiler/msvc/snprintf.c)
endif (MSVC)
macro (pn_absolute_install_dir NAME VALUE PREFIX)
@@ -303,49 +304,61 @@ add_subdirectory(bindings)
add_subdirectory(docs/api)
add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
-set (qpid-proton-platform
+set (qpid-proton-platform-io
+ src/platform/platform.c
${pn_io_impl}
${pn_selector_impl}
- src/platform.c
+ )
+
+set (qpid-proton-layers
${pn_sasl_impl}
${pn_ssl_impl}
)
set (qpid-proton-core
- src/object/object.c
- src/object/list.c
- src/object/map.c
- src/object/string.c
- src/object/iterator.c
- src/object/record.c
-
- src/log.c
- src/util.c
- src/url.c
- src/error.c
- src/buffer.c
- src/parser.c
- src/scanner.c
- src/types.c
-
- src/framing/framing.c
-
- src/codec/codec.c
- src/codec/decoder.c
- src/codec/encoder.c
-
- src/dispatcher/dispatcher.c
- src/engine/connection_engine.c
- src/engine/engine.c
- src/events/event.c
- src/transport/autodetect.c
- src/transport/transport.c
- src/message/message.c
+ src/core/object/object.c
+ src/core/object/list.c
+ src/core/object/map.c
+ src/core/object/string.c
+ src/core/object/iterator.c
+ src/core/object/record.c
+
+ src/core/log.c
+ src/core/util.c
+ src/core/error.c
+ src/core/buffer.c
+ src/core/types.c
+
+ src/core/framing.c
+
+ src/core/codec.c
+ src/core/decoder.c
+ src/core/encoder.c
+
+ src/core/dispatcher.c
+ src/core/connection_engine.c
+ src/core/engine.c
+ src/core/event.c
+ src/core/autodetect.c
+ src/core/transport.c
+ src/core/message.c
+ )
+
+set (qpid-proton-include-generated
+ ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+ ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
+ )
+
+set (qpid-proton-extra
+ src/extra/parser.c
+ src/extra/scanner.c
+ src/extra/url.c
src/reactor/reactor.c
src/reactor/handler.c
src/reactor/connection.c
src/reactor/acceptor.c
+ src/reactor/selectable.c
src/reactor/timer.c
src/handlers/handshaker.c
@@ -356,12 +369,6 @@ set (qpid-proton-core
src/messenger/subscription.c
src/messenger/store.c
src/messenger/transform.c
- src/selectable.c
- )
-
-set (qpid-proton-extra-deps
- ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
- ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
)
set (qpid-proton-include
@@ -374,39 +381,42 @@ set (qpid-proton-include
include/proton/engine.h
include/proton/error.h
include/proton/event.h
- include/proton/handlers.h
include/proton/import_export.h
- include/proton/io.h
include/proton/link.h
include/proton/log.h
include/proton/message.h
- include/proton/messenger.h
include/proton/object.h
- include/proton/parser.h
- include/proton/reactor.h
include/proton/sasl.h
- include/proton/scanner.h
- include/proton/selectable.h
- include/proton/selector.h
include/proton/session.h
include/proton/ssl.h
include/proton/terminus.h
include/proton/transport.h
include/proton/type_compat.h
include/proton/types.h
+)
+
+set (qpid-proton-include-extra
+ include/proton/handlers.h
+ include/proton/messenger.h
+ include/proton/parser.h
+ include/proton/reactor.h
+ include/proton/selectable.h
include/proton/url.h
)
-source_group("API Header Files" FILES ${qpid-proton-include})
+source_group("API Header Files" FILES ${qpid-proton-include} ${qpid-proton-include-extra})
set_source_files_properties (
${qpid-proton-core}
+ ${qpid-proton-layers}
+ ${qpid-proton-extra}
PROPERTIES
COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS} ${LTO}"
)
set_source_files_properties (
${qpid-proton-platform}
+ ${qpid-proton-platform-io}
PROPERTIES
COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS} ${LTO}"
COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}"
@@ -414,18 +424,47 @@ set_source_files_properties (
if (BUILD_WITH_CXX)
set_source_files_properties (
- ${qpid-proton-core} ${qpid-proton-platform}
+ ${qpid-proton-core}
+ ${qpid-proton-layers}
+ ${qpid-proton-extra}
+ ${qpid-proton-platform}
+ ${qpid-proton-platform-io}
PROPERTIES LANGUAGE CXX
)
endif (BUILD_WITH_CXX)
add_library (
- qpid-proton SHARED
+ qpid-proton-core SHARED
+ ${qpid-proton-core}
+ ${qpid-proton-layers}
+ ${qpid-proton-platform}
+ ${qpid-proton-include}
+ ${qpid-proton-include-generated}
+ )
+
+target_link_libraries (qpid-proton-core ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
+set_target_properties (
+ qpid-proton-core
+ PROPERTIES
+ VERSION "${PN_LIB_SOMAJOR}.${PN_LIB_SOMINOR}"
+ SOVERSION "${PN_LIB_SOMAJOR}"
+ LINK_FLAGS "${CATCH_UNDEFINED} ${LTO}"
+ )
+
+add_library(
+ qpid-proton SHARED
+ # Proton Core
${qpid-proton-core}
+ ${qpid-proton-layers}
${qpid-proton-platform}
${qpid-proton-include}
- ${qpid-proton-extra-deps}
+ ${qpid-proton-include-generated}
+
+ # Proton Reactor/Messenger
+ ${qpid-proton-extra}
+ ${qpid-proton-platform-io}
+ ${qpid-proton-include-extra}
)
target_link_libraries (qpid-proton ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
@@ -471,13 +510,24 @@ configure_file(
install (FILES
${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc
DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/libqpid-proton-core.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton-core.pc @ONLY)
+install (FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton-core.pc
+ DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+
if (DEFINED CMAKE_IMPORT_LIBRARY_PREFIX)
set(PROTONLIB ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_IMPORT_LIBRARY_SUFFIX})
set(PROTONLIBDEBUG ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX})
+set(PROTONCORELIB ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton-core${CMAKE_IMPORT_LIBRARY_SUFFIX})
+set(PROTONCORELIBDEBUG ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton-core${CMAKE_DEBUG_POSTFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX})
else ()
set(PROTONLIB ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_SHARED_LIBRARY_SUFFIX})
set(PROTONLIBDEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
+set(PROTONCORELIB ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton-core${CMAKE_SHARED_LIBRARY_SUFFIX})
+set(PROTONCORELIBDEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton-core${CMAKE_DEBUG_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
endif ()
include(WriteBasicConfigVersionFile)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/bindings/python/proton/reactor.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/reactor.py b/proton-c/bindings/python/proton/reactor.py
index ee9cfde..1a85bd3 100644
--- a/proton-c/bindings/python/proton/reactor.py
+++ b/proton-c/bindings/python/proton/reactor.py
@@ -138,7 +138,7 @@ class Reactor(Wrapper):
def wakeup(self):
n = pn_reactor_wakeup(self._impl)
- if n: raise IOError(pn_error_text(pn_io_error(pn_reactor_io(self._impl))))
+ if n: raise IOError(pn_error_text(pn_reactor_error(self._impl)))
def start(self):
pn_reactor_start(self._impl)
@@ -176,7 +176,7 @@ class Reactor(Wrapper):
if aimpl:
return Acceptor(aimpl)
else:
- raise IOError("%s (%s:%s)" % (pn_error_text(pn_io_error(pn_reactor_io(self._impl))), host, port))
+ raise IOError("%s (%s:%s)" % pn_error_text(pn_reactor_error(self._impl)), host, port)
def connection(self, handler=None):
"""Deprecated: use connection_to_host() instead
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/bindings/python/setup.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py b/proton-c/bindings/python/setup.py
index 1a74f0f..3606bed 100755
--- a/proton-c/bindings/python/setup.py
+++ b/proton-c/bindings/python/setup.py
@@ -194,8 +194,7 @@ class Configure(build_ext):
# Generate `encodings.h` by calling the python
# script found in the source dir.
with open(os.path.join(build_include, 'encodings.h'), 'wb') as header:
- subprocess.Popen([sys.executable,
- os.path.join(proton_src, 'codec', 'encodings.h.py')],
+ subprocess.Popen([sys.executable, os.path.join(proton_src, 'encodings.h.py')],
env=proton_envs, stdout=header)
# Create a custom, temporary, version.h file mapping the
@@ -219,10 +218,9 @@ class Configure(build_ext):
# we don't need.
sources = []
- for subdir in ['object', 'framing', 'codec', 'dispatcher',
- 'engine', 'events', 'transport',
- 'message', 'reactor', 'messenger',
- 'handlers', 'posix']:
+ for subdir in ['core', 'core/object', 'compiler',
+ 'extra', 'message', 'reactor', 'messenger', 'handlers',
+ 'platform', 'reactor/io/posix']:
sources.extend(glob.glob(os.path.join(proton_src, subdir, '*.c')))
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/bindings/ruby/lib/reactor/reactor.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/reactor/reactor.rb b/proton-c/bindings/ruby/lib/reactor/reactor.rb
index 1cf4f6c..a0ff7e0 100644
--- a/proton-c/bindings/ruby/lib/reactor/reactor.rb
+++ b/proton-c/bindings/ruby/lib/reactor/reactor.rb
@@ -128,8 +128,7 @@ module Qpid::Proton::Reactor
def wakeup
n = Cproton.pn_reactor_wakeup(@impl)
unless n.zero?
- io = Cproton.pn_reactor_io(@impl)
- raise IOError.new(Cproton.pn_io_error(io))
+ raise IOError.new(Cproton.pn_reactor_error(@impl))
end
end
@@ -159,8 +158,7 @@ module Qpid::Proton::Reactor
if !aimpl.nil?
return Acceptor.new(aimpl)
else
- io = Cproton.pn_reactor_io(@impl)
- io_error = Cproton.pn_io_error(io)
+ io_error = Cproton.pn_reactor_error(@impl)
error_text = Cproton.pn_error_text(io_error)
text = "(#{Cproton.pn_error_text(io_error)} (#{host}:#{port}))"
raise IOError.new(text)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cproton.i b/proton-c/include/proton/cproton.i
index 6129037..ffcf830 100644
--- a/proton-c/include/proton/cproton.i
+++ b/proton-c/include/proton/cproton.i
@@ -1014,8 +1014,6 @@ typedef unsigned long int uintptr_t;
%include "proton/messenger.h"
-%include "proton/io.h"
-
%include "proton/selectable.h"
%include "proton/ssl.h"
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 16d2bda..d10927b 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -415,11 +415,6 @@ PN_EXTERN const pn_class_t *pn_event_class(pn_event_t *event);
PN_EXTERN void *pn_event_context(pn_event_t *event);
/**
- * Get the root handler the current event was dispatched to.
- */
-PN_EXTERN pn_handler_t *pn_event_root(pn_event_t *event);
-
-/**
* Get the connection associated with an event.
*
* @param[in] event an event object
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/handlers.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/handlers.h b/proton-c/include/proton/handlers.h
index f61e04c..a8a6f77 100644
--- a/proton-c/include/proton/handlers.h
+++ b/proton-c/include/proton/handlers.h
@@ -43,9 +43,9 @@ typedef pn_handler_t pn_handshaker_t;
typedef pn_handler_t pn_iohandler_t;
typedef pn_handler_t pn_flowcontroller_t;
-PN_EXTERN pn_handshaker_t *pn_handshaker(void);
-PN_EXTERN pn_iohandler_t *pn_iohandler(void);
-PN_EXTERN pn_flowcontroller_t *pn_flowcontroller(int window);
+PNX_EXTERN pn_handshaker_t *pn_handshaker(void);
+PNX_EXTERN pn_iohandler_t *pn_iohandler(void);
+PNX_EXTERN pn_flowcontroller_t *pn_flowcontroller(int window);
/** @}
*/
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/import_export.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/import_export.h b/proton-c/include/proton/import_export.h
index 4534d68..0010126 100644
--- a/proton-c/include/proton/import_export.h
+++ b/proton-c/include/proton/import_export.h
@@ -46,12 +46,18 @@
// For core proton library symbols
-
-#ifdef qpid_proton_EXPORTS
+#if defined(qpid_proton_core_EXPORTS) || defined(qpid_proton_EXPORTS)
# define PN_EXTERN PN_EXPORT
#else
# define PN_EXTERN PN_IMPORT
#endif
+// For extra proton symbols
+#if defined(qpid_proton_EXPORTS)
+# define PNX_EXTERN PN_EXPORT
+#else
+# define PNX_EXTERN PN_IMPORT
+#endif
+
#endif /* import_export.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/io.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/io.h b/proton-c/include/proton/io.h
deleted file mode 100644
index 19dfe53..0000000
--- a/proton-c/include/proton/io.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef PROTON_IO_H
-#define PROTON_IO_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <proton/error.h>
-#include <proton/type_compat.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * A ::pn_socket_t provides an abstract handle to an IO stream. The
- * pipe version is uni-directional. The network socket version is
- * bi-directional. Both are non-blocking.
- *
- * pn_socket_t handles from ::pn_pipe() may only be used with
- * ::pn_read(), ::pn_write(), ::pn_close() and pn_selector_select().
- *
- * pn_socket_t handles from ::pn_listen(), ::pn_accept() and
- * ::pn_connect() must perform further IO using Proton functions.
- * Mixing Proton io.h functions with native IO functions on the same
- * handles will result in undefined behavior.
- *
- * pn_socket_t handles may only be used with a single pn_io_t during
- * their lifetime.
- */
-#if defined(_WIN32) && ! defined(__CYGWIN__)
-#ifdef _WIN64
-typedef unsigned __int64 pn_socket_t;
-#else
-typedef unsigned int pn_socket_t;
-#endif
-#define PN_INVALID_SOCKET (pn_socket_t)(~0)
-#else
-typedef int pn_socket_t;
-#define PN_INVALID_SOCKET (-1)
-#endif
-
-/**
- * A ::pn_io_t manages IO for a group of pn_socket_t handles. A
- * pn_io_t object may have zero or one pn_selector_t selectors
- * associated with it (see ::pn_io_selector()). If one is associated,
- * all the pn_socket_t handles managed by a pn_io_t must use that
- * pn_selector_t instance.
- *
- * The pn_io_t interface is single-threaded. All methods are intended
- * to be used by one thread at a time, except that multiple threads
- * may use:
- *
- * ::pn_write()
- * ::pn_send()
- * ::pn_recv()
- * ::pn_close()
- * ::pn_selector_select()
- *
- * provided at most one thread is calling ::pn_selector_select() and
- * the other threads are operating on separate pn_socket_t handles.
- */
-typedef struct pn_io_t pn_io_t;
-
-/**
- * A ::pn_selector_t provides a selection mechanism that allows
- * efficient monitoring of a large number of Proton connections and
- * listeners.
- *
- * External (non-Proton) sockets may also be monitored, either solely
- * for event notification (read, write, and timer) or event
- * notification and use with pn_io_t interfaces.
- */
-typedef struct pn_selector_t pn_selector_t;
-
-PN_EXTERN pn_io_t *pn_io(void);
-PN_EXTERN void pn_io_free(pn_io_t *io);
-PN_EXTERN pn_error_t *pn_io_error(pn_io_t *io);
-PN_EXTERN pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port);
-PN_EXTERN pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port);
-PN_EXTERN pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size);
-PN_EXTERN void pn_close(pn_io_t *io, pn_socket_t socket);
-PN_EXTERN ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
-PN_EXTERN ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
-PN_EXTERN int pn_pipe(pn_io_t *io, pn_socket_t *dest);
-PN_EXTERN ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
-PN_EXTERN ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
-PN_EXTERN bool pn_wouldblock(pn_io_t *io);
-PN_EXTERN pn_selector_t *pn_io_selector(pn_io_t *io);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* io.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/messenger.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/messenger.h b/proton-c/include/proton/messenger.h
index 6d0f58b..8cba51d 100644
--- a/proton-c/include/proton/messenger.h
+++ b/proton-c/include/proton/messenger.h
@@ -195,7 +195,7 @@ typedef enum {
*
* @return pointer to a new ::pn_messenger_t
*/
-PN_EXTERN pn_messenger_t *pn_messenger(const char *name);
+PNX_EXTERN pn_messenger_t *pn_messenger(const char *name);
/**
* Get the name of a messenger.
@@ -203,7 +203,7 @@ PN_EXTERN pn_messenger_t *pn_messenger(const char *name);
* @param[in] messenger a messenger object
* @return the name of the messenger
*/
-PN_EXTERN const char *pn_messenger_name(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_name(pn_messenger_t *messenger);
/**
* Sets the path that will be used to get the certificate that will be
@@ -214,7 +214,7 @@ PN_EXTERN const char *pn_messenger_name(pn_messenger_t *messenger);
* @param[in] certificate a path to a certificate file
* @return an error code of zero if there is no error
*/
-PN_EXTERN int pn_messenger_set_certificate(pn_messenger_t *messenger, const char *certificate);
+PNX_EXTERN int pn_messenger_set_certificate(pn_messenger_t *messenger, const char *certificate);
/**
* Get the certificate path. This value may be set by
@@ -223,7 +223,7 @@ PN_EXTERN int pn_messenger_set_certificate(pn_messenger_t *messenger, const char
* @param[in] messenger the messenger
* @return the certificate file path
*/
-PN_EXTERN const char *pn_messenger_get_certificate(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_certificate(pn_messenger_t *messenger);
/**
* Set path to the private key that was used to sign the certificate.
@@ -233,7 +233,7 @@ PN_EXTERN const char *pn_messenger_get_certificate(pn_messenger_t *messenger);
* @param[in] private_key a path to a private key file
* @return an error code of zero if there is no error
*/
-PN_EXTERN int pn_messenger_set_private_key(pn_messenger_t *messenger, const char *private_key);
+PNX_EXTERN int pn_messenger_set_private_key(pn_messenger_t *messenger, const char *private_key);
/**
* Gets the private key file for a messenger.
@@ -241,7 +241,7 @@ PN_EXTERN int pn_messenger_set_private_key(pn_messenger_t *messenger, const char
* @param[in] messenger a messenger object
* @return the messenger's private key file path
*/
-PN_EXTERN const char *pn_messenger_get_private_key(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_private_key(pn_messenger_t *messenger);
/**
* Sets the private key password for a messenger.
@@ -251,7 +251,7 @@ PN_EXTERN const char *pn_messenger_get_private_key(pn_messenger_t *messenger);
*
* @return an error code of zero if there is no error
*/
-PN_EXTERN int pn_messenger_set_password(pn_messenger_t *messenger, const char *password);
+PNX_EXTERN int pn_messenger_set_password(pn_messenger_t *messenger, const char *password);
/**
* Gets the private key file password for a messenger.
@@ -259,7 +259,7 @@ PN_EXTERN int pn_messenger_set_password(pn_messenger_t *messenger, const char *p
* @param[in] messenger a messenger object
* @return password for the private key file
*/
-PN_EXTERN const char *pn_messenger_get_password(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_password(pn_messenger_t *messenger);
/**
* Sets the trusted certificates database for a messenger.
@@ -272,7 +272,7 @@ PN_EXTERN const char *pn_messenger_get_password(pn_messenger_t *messenger);
*
* @return an error code of zero if there is no error
*/
-PN_EXTERN int pn_messenger_set_trusted_certificates(pn_messenger_t *messenger, const char *cert_db);
+PNX_EXTERN int pn_messenger_set_trusted_certificates(pn_messenger_t *messenger, const char *cert_db);
/**
* Gets the trusted certificates database for a messenger.
@@ -280,7 +280,7 @@ PN_EXTERN int pn_messenger_set_trusted_certificates(pn_messenger_t *messenger, c
* @param[in] messenger a messenger object
* @return path to the trusted certificates database
*/
-PN_EXTERN const char *pn_messenger_get_trusted_certificates(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_trusted_certificates(pn_messenger_t *messenger);
/**
* Set the default timeout for a messenger.
@@ -294,7 +294,7 @@ PN_EXTERN const char *pn_messenger_get_trusted_certificates(pn_messenger_t *mess
* @param[in] timeout a new timeout for the messenger, in milliseconds
* @return an error code or zero if there is no error
*/
-PN_EXTERN int pn_messenger_set_timeout(pn_messenger_t *messenger, int timeout);
+PNX_EXTERN int pn_messenger_set_timeout(pn_messenger_t *messenger, int timeout);
/**
* Gets the timeout for a messenger object.
@@ -304,7 +304,7 @@ PN_EXTERN int pn_messenger_set_timeout(pn_messenger_t *messenger, int timeout);
* @param[in] messenger a messenger object
* @return the timeout for the messenger, in milliseconds
*/
-PN_EXTERN int pn_messenger_get_timeout(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_timeout(pn_messenger_t *messenger);
/**
* Check if a messenger is in blocking mode.
@@ -312,7 +312,7 @@ PN_EXTERN int pn_messenger_get_timeout(pn_messenger_t *messenger);
* @param[in] messenger a messenger object
* @return true if blocking has been enabled, false otherwise
*/
-PN_EXTERN bool pn_messenger_is_blocking(pn_messenger_t *messenger);
+PNX_EXTERN bool pn_messenger_is_blocking(pn_messenger_t *messenger);
/**
* Enable or disable blocking behavior for a messenger during calls to
@@ -322,7 +322,7 @@ PN_EXTERN bool pn_messenger_is_blocking(pn_messenger_t *messenger);
* @param[in] blocking the value of the blocking flag
* @return an error code or zero if there is no error
*/
-PN_EXTERN int pn_messenger_set_blocking(pn_messenger_t *messenger, bool blocking);
+PNX_EXTERN int pn_messenger_set_blocking(pn_messenger_t *messenger, bool blocking);
/**
* Check if a messenger is in passive mode.
@@ -336,7 +336,7 @@ PN_EXTERN int pn_messenger_set_blocking(pn_messenger_t *messenger, bool blocking
* @param[in] messenger a messenger object
* @return true if the messenger is in passive mode, false otherwise
*/
-PN_EXTERN bool pn_messenger_is_passive(pn_messenger_t *messenger);
+PNX_EXTERN bool pn_messenger_is_passive(pn_messenger_t *messenger);
/**
* Set the passive mode for a messenger.
@@ -348,14 +348,14 @@ PN_EXTERN bool pn_messenger_is_passive(pn_messenger_t *messenger);
* passive mode
* @return an error code or zero on success
*/
-PN_EXTERN int pn_messenger_set_passive(pn_messenger_t *messenger, bool passive);
+PNX_EXTERN int pn_messenger_set_passive(pn_messenger_t *messenger, bool passive);
/** Frees a Messenger.
*
* @param[in] messenger the messenger to free (or NULL), no longer
* valid on return
*/
-PN_EXTERN void pn_messenger_free(pn_messenger_t *messenger);
+PNX_EXTERN void pn_messenger_free(pn_messenger_t *messenger);
/**
* Get the code for a messenger's most recent error.
@@ -370,7 +370,7 @@ PN_EXTERN void pn_messenger_free(pn_messenger_t *messenger);
* @return an error code or zero if there is no error
* @see error.h
*/
-PN_EXTERN int pn_messenger_errno(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_errno(pn_messenger_t *messenger);
/**
* Get a messenger's error object.
@@ -383,7 +383,7 @@ PN_EXTERN int pn_messenger_errno(pn_messenger_t *messenger);
* @return a pointer to the messenger's error descriptor
* @see error.h
*/
-PN_EXTERN pn_error_t *pn_messenger_error(pn_messenger_t *messenger);
+PNX_EXTERN pn_error_t *pn_messenger_error(pn_messenger_t *messenger);
/**
* Get the size of a messenger's outgoing window.
@@ -400,7 +400,7 @@ PN_EXTERN pn_error_t *pn_messenger_error(pn_messenger_t *messenger);
* @param[in] messenger a messenger object
* @return the outgoing window for the messenger
*/
-PN_EXTERN int pn_messenger_get_outgoing_window(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_outgoing_window(pn_messenger_t *messenger);
/**
* Set the size of a messenger's outgoing window.
@@ -412,7 +412,7 @@ PN_EXTERN int pn_messenger_get_outgoing_window(pn_messenger_t *messenger);
* @return an error or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_set_outgoing_window(pn_messenger_t *messenger, int window);
+PNX_EXTERN int pn_messenger_set_outgoing_window(pn_messenger_t *messenger, int window);
/**
* Get the size of a messenger's incoming window.
@@ -432,7 +432,7 @@ PN_EXTERN int pn_messenger_set_outgoing_window(pn_messenger_t *messenger, int wi
* @param[in] messenger a messenger object
* @return the incoming window for the messenger
*/
-PN_EXTERN int pn_messenger_get_incoming_window(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_incoming_window(pn_messenger_t *messenger);
/**
* Set the size of a messenger's incoming window.
@@ -444,7 +444,7 @@ PN_EXTERN int pn_messenger_get_incoming_window(pn_messenger_t *messenger);
* @return an error or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_set_incoming_window(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_incoming_window(pn_messenger_t *messenger,
int window);
/**
@@ -455,7 +455,7 @@ PN_EXTERN int pn_messenger_set_incoming_window(pn_messenger_t *messenger,
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_start(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_start(pn_messenger_t *messenger);
/**
* Stops a messenger.
@@ -471,7 +471,7 @@ PN_EXTERN int pn_messenger_start(pn_messenger_t *messenger);
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_stop(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_stop(pn_messenger_t *messenger);
/**
* Returns true if a messenger is in the stopped state. This function
@@ -480,7 +480,7 @@ PN_EXTERN int pn_messenger_stop(pn_messenger_t *messenger);
* @param[in] messenger the messenger to stop
*
*/
-PN_EXTERN bool pn_messenger_stopped(pn_messenger_t *messenger);
+PNX_EXTERN bool pn_messenger_stopped(pn_messenger_t *messenger);
/**
* Subscribes a messenger to messages from the specified source.
@@ -489,7 +489,7 @@ PN_EXTERN bool pn_messenger_stopped(pn_messenger_t *messenger);
* @param[in] source
* @return a subscription
*/
-PN_EXTERN pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, const char *source);
+PNX_EXTERN pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, const char *source);
/**
* Subscribes a messenger to messages from the specified source with the given
@@ -501,7 +501,7 @@ PN_EXTERN pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, c
* link is closed.
* @return a subscription
*/
-PN_EXTERN pn_subscription_t *
+PNX_EXTERN pn_subscription_t *
pn_messenger_subscribe_ttl(pn_messenger_t *messenger, const char *source,
pn_seconds_t timeout);
@@ -514,7 +514,7 @@ pn_messenger_subscribe_ttl(pn_messenger_t *messenger, const char *source,
* receiver
* @return a link, or NULL if no link matches the address / sender parameters
*/
-PN_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
+PNX_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
const char *address, bool sender);
/**
@@ -525,7 +525,7 @@ PN_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
* @param[in] sub a subscription object
* @return the subscription's application context
*/
-PN_EXTERN void *pn_subscription_get_context(pn_subscription_t *sub);
+PNX_EXTERN void *pn_subscription_get_context(pn_subscription_t *sub);
/**
* Set an application context for a subscription.
@@ -533,7 +533,7 @@ PN_EXTERN void *pn_subscription_get_context(pn_subscription_t *sub);
* @param[in] sub a subscription object
* @param[in] context the application context for the subscription
*/
-PN_EXTERN void pn_subscription_set_context(pn_subscription_t *sub, void *context);
+PNX_EXTERN void pn_subscription_set_context(pn_subscription_t *sub, void *context);
/**
* Get the source address of a subscription.
@@ -541,7 +541,7 @@ PN_EXTERN void pn_subscription_set_context(pn_subscription_t *sub, void *context
* @param[in] sub a subscription object
* @return the subscription's source address
*/
-PN_EXTERN const char *pn_subscription_address(pn_subscription_t *sub);
+PNX_EXTERN const char *pn_subscription_address(pn_subscription_t *sub);
/**
* Puts a message onto the messenger's outgoing queue. The message may
@@ -553,7 +553,7 @@ PN_EXTERN const char *pn_subscription_address(pn_subscription_t *sub);
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg);
+PNX_EXTERN int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg);
/**
* Track the status of a delivery.
@@ -566,7 +566,7 @@ PN_EXTERN int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg);
* @param[in] tracker the tracker identifying the delivery
* @return a status code for the delivery
*/
-PN_EXTERN pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_t tracker);
+PNX_EXTERN pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_t tracker);
/**
* Get delivery information about a delivery.
@@ -579,7 +579,7 @@ PN_EXTERN pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_
* @param[in] tracker the tracker identifying the delivery
* @return a pn_delivery_t representing the delivery.
*/
-PN_EXTERN pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
+PNX_EXTERN pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
pn_tracker_t tracker);
/**
@@ -594,7 +594,7 @@ PN_EXTERN pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
*
* @return true if the delivery is still buffered
*/
-PN_EXTERN bool pn_messenger_buffered(pn_messenger_t *messenger, pn_tracker_t tracker);
+PNX_EXTERN bool pn_messenger_buffered(pn_messenger_t *messenger, pn_tracker_t tracker);
/**
* Frees a Messenger from tracking the status associated with a given
@@ -608,7 +608,7 @@ PN_EXTERN bool pn_messenger_buffered(pn_messenger_t *messenger, pn_tracker_t tra
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_settle(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
+PNX_EXTERN int pn_messenger_settle(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
/**
* Get a tracker for the outgoing message most recently given to
@@ -623,7 +623,7 @@ PN_EXTERN int pn_messenger_settle(pn_messenger_t *messenger, pn_tracker_t tracke
* @return a pn_tracker_t or an undefined value if pn_messenger_get
* has never been called for the given messenger
*/
-PN_EXTERN pn_tracker_t pn_messenger_outgoing_tracker(pn_messenger_t *messenger);
+PNX_EXTERN pn_tracker_t pn_messenger_outgoing_tracker(pn_messenger_t *messenger);
/**
* Sends or receives any outstanding messages queued for a messenger.
@@ -635,7 +635,7 @@ PN_EXTERN pn_tracker_t pn_messenger_outgoing_tracker(pn_messenger_t *messenger);
*
* @return 0 if no work to do, < 0 if error, or 1 if work was done.
*/
-PN_EXTERN int pn_messenger_work(pn_messenger_t *messenger, int timeout);
+PNX_EXTERN int pn_messenger_work(pn_messenger_t *messenger, int timeout);
/**
* Interrupt a messenger object that may be blocking in another
@@ -648,7 +648,7 @@ PN_EXTERN int pn_messenger_work(pn_messenger_t *messenger, int timeout);
*
* @param[in] messenger the Messenger to interrupt
*/
-PN_EXTERN int pn_messenger_interrupt(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_interrupt(pn_messenger_t *messenger);
/**
* Send messages from a messenger's outgoing queue.
@@ -682,7 +682,7 @@ PN_EXTERN int pn_messenger_interrupt(pn_messenger_t *messenger);
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_send(pn_messenger_t *messenger, int n);
+PNX_EXTERN int pn_messenger_send(pn_messenger_t *messenger, int n);
/**
* Retrieve messages into a messenger's incoming queue.
@@ -708,7 +708,7 @@ PN_EXTERN int pn_messenger_send(pn_messenger_t *messenger, int n);
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_recv(pn_messenger_t *messenger, int limit);
+PNX_EXTERN int pn_messenger_recv(pn_messenger_t *messenger, int limit);
/**
* Get the capacity of the incoming message queue of a messenger.
@@ -720,7 +720,7 @@ PN_EXTERN int pn_messenger_recv(pn_messenger_t *messenger, int limit);
*
* @param[in] messenger the messenger
*/
-PN_EXTERN int pn_messenger_receiving(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_receiving(pn_messenger_t *messenger);
/**
* Get the next message from the head of a messenger's incoming queue.
@@ -736,7 +736,7 @@ PN_EXTERN int pn_messenger_receiving(pn_messenger_t *messenger);
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_get(pn_messenger_t *messenger, pn_message_t *message);
+PNX_EXTERN int pn_messenger_get(pn_messenger_t *messenger, pn_message_t *message);
/**
* Get a tracker for the message most recently retrieved by
@@ -751,7 +751,7 @@ PN_EXTERN int pn_messenger_get(pn_messenger_t *messenger, pn_message_t *message)
* @return a pn_tracker_t or an undefined value if pn_messenger_get
* has never been called for the given messenger
*/
-PN_EXTERN pn_tracker_t pn_messenger_incoming_tracker(pn_messenger_t *messenger);
+PNX_EXTERN pn_tracker_t pn_messenger_incoming_tracker(pn_messenger_t *messenger);
/**
* Get the subscription of the message most recently retrieved by ::pn_messenger_get().
@@ -762,7 +762,7 @@ PN_EXTERN pn_tracker_t pn_messenger_incoming_tracker(pn_messenger_t *messenger);
* @param[in] messenger a messenger object
* @return a pn_subscription_t or NULL
*/
-PN_EXTERN pn_subscription_t *pn_messenger_incoming_subscription(pn_messenger_t *messenger);
+PNX_EXTERN pn_subscription_t *pn_messenger_incoming_subscription(pn_messenger_t *messenger);
/**
* Indicates that an accept or reject should operate cumulatively.
@@ -790,7 +790,7 @@ PN_EXTERN pn_subscription_t *pn_messenger_incoming_subscription(pn_messenger_t *
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_accept(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
+PNX_EXTERN int pn_messenger_accept(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
/**
* Signal unsuccessful processing of message(s).
@@ -813,7 +813,7 @@ PN_EXTERN int pn_messenger_accept(pn_messenger_t *messenger, pn_tracker_t tracke
* @return an error code or zero on success
* @see error.h
*/
-PN_EXTERN int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
+PNX_EXTERN int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
/**
* Get link for the message referenced by the given tracker.
@@ -822,7 +822,7 @@ PN_EXTERN int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracke
* @param[in] tracker a tracker object
* @return a pn_link_t or NULL if the link could not be determined.
*/
-PN_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
+PNX_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
pn_tracker_t tracker);
/**
@@ -832,7 +832,7 @@ PN_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
* @param[in] messenger a messenger object
* @return the outgoing queue depth
*/
-PN_EXTERN int pn_messenger_outgoing(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_outgoing(pn_messenger_t *messenger);
/**
* Get the number of messages in the incoming message queue of a messenger.
@@ -840,7 +840,7 @@ PN_EXTERN int pn_messenger_outgoing(pn_messenger_t *messenger);
* @param[in] messenger a messenger object
* @return the incoming queue depth
*/
-PN_EXTERN int pn_messenger_incoming(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_incoming(pn_messenger_t *messenger);
//! Adds a routing rule to a Messenger's internal routing table.
//!
@@ -904,7 +904,7 @@ PN_EXTERN int pn_messenger_incoming(pn_messenger_t *messenger);
//!
//! @return an error code or zero on success
//! @see error.h
-PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern,
+PNX_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern,
const char *address);
/**
@@ -929,7 +929,7 @@ PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern,
* @param[in] address an address indicating outgoing address rewrite
* @return an error code or zero on success
*/
-PN_EXTERN int pn_messenger_rewrite(pn_messenger_t *messenger, const char *pattern,
+PNX_EXTERN int pn_messenger_rewrite(pn_messenger_t *messenger, const char *pattern,
const char *address);
/**
@@ -960,7 +960,7 @@ PN_EXTERN int pn_messenger_rewrite(pn_messenger_t *messenger, const char *patter
* @param[in] messenger a messenger object
* @return the next selectable, or NULL if there are none left
*/
-PN_EXTERN pn_selectable_t *pn_messenger_selectable(pn_messenger_t *messenger);
+PNX_EXTERN pn_selectable_t *pn_messenger_selectable(pn_messenger_t *messenger);
/**
* Get the nearest deadline for selectables associated with a messenger.
@@ -968,7 +968,7 @@ PN_EXTERN pn_selectable_t *pn_messenger_selectable(pn_messenger_t *messenger);
* @param[in] messenger a messenger object
* @return the nearest deadline
*/
-PN_EXTERN pn_timestamp_t pn_messenger_deadline(pn_messenger_t *messenger);
+PNX_EXTERN pn_timestamp_t pn_messenger_deadline(pn_messenger_t *messenger);
/**
* @}
@@ -991,7 +991,7 @@ PN_EXTERN pn_timestamp_t pn_messenger_deadline(pn_messenger_t *messenger);
*
* @return an error code of zero if there is no error
*/
-PN_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger,
const int flags);
/** Gets the flags for a Messenger.
@@ -999,7 +999,7 @@ PN_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger,
* @param[in] messenger the messenger
* @return The flags set for the messenger
*/
-PN_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger);
/**
* Set the local sender settle mode for the underlying link.
@@ -1007,7 +1007,7 @@ PN_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger);
* @param[in] messenger the messenger
* @param[in] mode the sender settle mode
*/
-PN_EXTERN int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
const pn_snd_settle_mode_t mode);
/**
@@ -1016,7 +1016,7 @@ PN_EXTERN int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
* @param[in] messenger the messenger
* @param[in] mode the receiver settle mode
*/
-PN_EXTERN int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
const pn_rcv_settle_mode_t mode);
/**
@@ -1025,7 +1025,7 @@ PN_EXTERN int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
* @param[in] messenger a messenger object
* @param[in] tracer the tracer callback
*/
-PN_EXTERN void pn_messenger_set_tracer(pn_messenger_t *messenger,
+PNX_EXTERN void pn_messenger_set_tracer(pn_messenger_t *messenger,
pn_tracer_t tracer);
/**
@@ -1035,7 +1035,7 @@ PN_EXTERN void pn_messenger_set_tracer(pn_messenger_t *messenger,
* @param[in] address of remote service whose idle timeout is required
* @return the timeout in milliseconds or -1 if an error occurs
*/
-PN_EXTERN pn_millis_t
+PNX_EXTERN pn_millis_t
pn_messenger_get_remote_idle_timeout(pn_messenger_t *messenger,
const char *address);
@@ -1048,7 +1048,7 @@ PN_EXTERN pn_millis_t
* enum for valid values)
* @return 0 if successful or -1 if an error occurs
*/
-PN_EXTERN int
+PNX_EXTERN int
pn_messenger_set_ssl_peer_authentication_mode(pn_messenger_t *messenger,
const pn_ssl_verify_mode_t mode);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/reactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/reactor.h b/proton-c/include/proton/reactor.h
index 78fe57b..bfd6de5 100644
--- a/proton-c/include/proton/reactor.h
+++ b/proton-c/include/proton/reactor.h
@@ -1,3 +1,4 @@
+
#ifndef PROTON_REACTOR_H
#define PROTON_REACTOR_H 1
@@ -24,6 +25,7 @@
#include <proton/import_export.h>
#include <proton/type_compat.h>
+#include <proton/error.h>
#include <proton/event.h>
#include <proton/selectable.h>
#include <proton/ssl.h>
@@ -46,35 +48,34 @@ typedef struct pn_acceptor_t pn_acceptor_t;
typedef struct pn_timer_t pn_timer_t;
typedef struct pn_task_t pn_task_t;
-PN_EXTERN pn_handler_t *pn_handler(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t));
-PN_EXTERN pn_handler_t *pn_handler_new(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t), size_t size,
+PNX_EXTERN pn_handler_t *pn_handler(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t));
+PNX_EXTERN pn_handler_t *pn_handler_new(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t), size_t size,
void (*finalize)(pn_handler_t *));
-PN_EXTERN void pn_handler_free(pn_handler_t *handler);
-PN_EXTERN void *pn_handler_mem(pn_handler_t *handler);
-PN_EXTERN void pn_handler_add(pn_handler_t *handler, pn_handler_t *child);
-PN_EXTERN void pn_handler_clear(pn_handler_t *handler);
-PN_EXTERN void pn_handler_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type);
-
-PN_EXTERN pn_reactor_t *pn_reactor(void);
-PN_EXTERN pn_record_t *pn_reactor_attachments(pn_reactor_t *reactor);
-PN_EXTERN pn_millis_t pn_reactor_get_timeout(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_set_timeout(pn_reactor_t *reactor, pn_millis_t timeout);
-PN_EXTERN pn_timestamp_t pn_reactor_mark(pn_reactor_t *reactor);
-PN_EXTERN pn_timestamp_t pn_reactor_now(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_yield(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_free(pn_reactor_t *reactor);
-PN_EXTERN pn_collector_t *pn_reactor_collector(pn_reactor_t *reactor);
-PN_EXTERN pn_handler_t *pn_reactor_get_global_handler(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_set_global_handler(pn_reactor_t *reactor, pn_handler_t *handler);
-PN_EXTERN pn_handler_t *pn_reactor_get_handler(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_set_handler(pn_reactor_t *reactor, pn_handler_t *handler);
-PN_EXTERN pn_io_t *pn_reactor_io(pn_reactor_t *reactor);
-PN_EXTERN pn_list_t *pn_reactor_children(pn_reactor_t *reactor);
-PN_EXTERN pn_selectable_t *pn_reactor_selectable(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_update(pn_reactor_t *reactor, pn_selectable_t *selectable);
-PN_EXTERN pn_acceptor_t *pn_reactor_acceptor(pn_reactor_t *reactor, const char *host, const char *port,
+PNX_EXTERN void pn_handler_free(pn_handler_t *handler);
+PNX_EXTERN void *pn_handler_mem(pn_handler_t *handler);
+PNX_EXTERN void pn_handler_add(pn_handler_t *handler, pn_handler_t *child);
+PNX_EXTERN void pn_handler_clear(pn_handler_t *handler);
+PNX_EXTERN void pn_handler_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type);
+
+PNX_EXTERN pn_reactor_t *pn_reactor(void);
+PNX_EXTERN pn_record_t *pn_reactor_attachments(pn_reactor_t *reactor);
+PNX_EXTERN pn_millis_t pn_reactor_get_timeout(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_set_timeout(pn_reactor_t *reactor, pn_millis_t timeout);
+PNX_EXTERN pn_timestamp_t pn_reactor_mark(pn_reactor_t *reactor);
+PNX_EXTERN pn_timestamp_t pn_reactor_now(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_yield(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_free(pn_reactor_t *reactor);
+PNX_EXTERN pn_collector_t *pn_reactor_collector(pn_reactor_t *reactor);
+PNX_EXTERN pn_handler_t *pn_reactor_get_global_handler(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_set_global_handler(pn_reactor_t *reactor, pn_handler_t *handler);
+PNX_EXTERN pn_handler_t *pn_reactor_get_handler(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_set_handler(pn_reactor_t *reactor, pn_handler_t *handler);
+PNX_EXTERN pn_list_t *pn_reactor_children(pn_reactor_t *reactor);
+PNX_EXTERN pn_selectable_t *pn_reactor_selectable(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_update(pn_reactor_t *reactor, pn_selectable_t *selectable);
+PNX_EXTERN pn_acceptor_t *pn_reactor_acceptor(pn_reactor_t *reactor, const char *host, const char *port,
pn_handler_t *handler);
-PN_EXTERN pn_error_t *pn_reactor_error(pn_reactor_t *reactor);
+PNX_EXTERN pn_error_t *pn_reactor_error(pn_reactor_t *reactor);
/**
* Create an outgoing connection that will be managed by the reactor.
@@ -89,7 +90,7 @@ PN_EXTERN pn_error_t *pn_reactor_error(pn_reactor_t *reactor);
* this connection.
* @return a connection object
*/
-PN_EXTERN pn_connection_t *pn_reactor_connection_to_host(pn_reactor_t *reactor,
+PNX_EXTERN pn_connection_t *pn_reactor_connection_to_host(pn_reactor_t *reactor,
const char *host,
const char *port,
pn_handler_t *handler);
@@ -108,7 +109,7 @@ PN_EXTERN pn_connection_t *pn_reactor_connection_to_host(pn_reactor_t *reactor,
* @return a connection object
* @deprecated Use ::pn_reactor_connection_to_host() instead.
*/
-PN_EXTERN pn_connection_t *pn_reactor_connection(pn_reactor_t *reactor,
+PNX_EXTERN pn_connection_t *pn_reactor_connection(pn_reactor_t *reactor,
pn_handler_t *handler);
/**
@@ -122,7 +123,7 @@ PN_EXTERN pn_connection_t *pn_reactor_connection(pn_reactor_t *reactor,
* @param[in] host the network address or DNS name of the host to connect to.
* @param[in] port the network port to use. Optional - default is "5672"
*/
-PN_EXTERN void pn_reactor_set_connection_host(pn_reactor_t *reactor,
+PNX_EXTERN void pn_reactor_set_connection_host(pn_reactor_t *reactor,
pn_connection_t *connection,
const char *host,
const char *port);
@@ -145,37 +146,42 @@ PN_EXTERN void pn_reactor_set_connection_host(pn_reactor_t *reactor,
* address available. ::pn_url_parse() may be used to create a Proton pn_url_t
* instance from the returned value.
*/
-PN_EXTERN const char *pn_reactor_get_connection_address(pn_reactor_t *reactor,
+PNX_EXTERN const char *pn_reactor_get_connection_address(pn_reactor_t *reactor,
pn_connection_t *connection);
-PN_EXTERN int pn_reactor_wakeup(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_start(pn_reactor_t *reactor);
-PN_EXTERN bool pn_reactor_quiesced(pn_reactor_t *reactor);
-PN_EXTERN bool pn_reactor_process(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_stop(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_run(pn_reactor_t *reactor);
-PN_EXTERN pn_task_t *pn_reactor_schedule(pn_reactor_t *reactor, int delay, pn_handler_t *handler);
+PNX_EXTERN int pn_reactor_wakeup(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_start(pn_reactor_t *reactor);
+PNX_EXTERN bool pn_reactor_quiesced(pn_reactor_t *reactor);
+PNX_EXTERN bool pn_reactor_process(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_stop(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_run(pn_reactor_t *reactor);
+PNX_EXTERN pn_task_t *pn_reactor_schedule(pn_reactor_t *reactor, int delay, pn_handler_t *handler);
+
+PNX_EXTERN void pn_acceptor_set_ssl_domain(pn_acceptor_t *acceptor, pn_ssl_domain_t *domain);
+PNX_EXTERN void pn_acceptor_close(pn_acceptor_t *acceptor);
+PNX_EXTERN pn_acceptor_t *pn_connection_acceptor(pn_connection_t *connection);
-PN_EXTERN void pn_acceptor_set_ssl_domain(pn_acceptor_t *acceptor, pn_ssl_domain_t *domain);
-PN_EXTERN void pn_acceptor_close(pn_acceptor_t *acceptor);
-PN_EXTERN pn_acceptor_t *pn_connection_acceptor(pn_connection_t *connection);
+PNX_EXTERN pn_timer_t *pn_timer(pn_collector_t *collector);
+PNX_EXTERN pn_timestamp_t pn_timer_deadline(pn_timer_t *timer);
+PNX_EXTERN void pn_timer_tick(pn_timer_t *timer, pn_timestamp_t now);
+PNX_EXTERN pn_task_t *pn_timer_schedule(pn_timer_t *timer, pn_timestamp_t deadline);
+PNX_EXTERN int pn_timer_tasks(pn_timer_t *timer);
-PN_EXTERN pn_timer_t *pn_timer(pn_collector_t *collector);
-PN_EXTERN pn_timestamp_t pn_timer_deadline(pn_timer_t *timer);
-PN_EXTERN void pn_timer_tick(pn_timer_t *timer, pn_timestamp_t now);
-PN_EXTERN pn_task_t *pn_timer_schedule(pn_timer_t *timer, pn_timestamp_t deadline);
-PN_EXTERN int pn_timer_tasks(pn_timer_t *timer);
+PNX_EXTERN pn_record_t *pn_task_attachments(pn_task_t *task);
+PNX_EXTERN void pn_task_cancel(pn_task_t *task);
-PN_EXTERN pn_record_t *pn_task_attachments(pn_task_t *task);
-PN_EXTERN void pn_task_cancel(pn_task_t *task);
+PNX_EXTERN pn_reactor_t *pn_class_reactor(const pn_class_t *clazz, void *object);
+PNX_EXTERN pn_reactor_t *pn_object_reactor(void *object);
+PNX_EXTERN pn_reactor_t *pn_event_reactor(pn_event_t *event);
-PN_EXTERN pn_reactor_t *pn_class_reactor(const pn_class_t *clazz, void *object);
-PN_EXTERN pn_reactor_t *pn_object_reactor(void *object);
-PN_EXTERN pn_reactor_t *pn_event_reactor(pn_event_t *event);
+PNX_EXTERN pn_handler_t *pn_record_get_handler(pn_record_t *record);
+PNX_EXTERN void pn_record_set_handler(pn_record_t *record, pn_handler_t *handler);
-PN_EXTERN pn_handler_t *pn_record_get_handler(pn_record_t *record);
-PN_EXTERN void pn_record_set_handler(pn_record_t *record, pn_handler_t *handler);
+/**
+ * Get the root handler the current event was dispatched to.
+ */
+PNX_EXTERN pn_handler_t *pn_event_root(pn_event_t *event);
/** @}
*/
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/scanner.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/scanner.h b/proton-c/include/proton/scanner.h
deleted file mode 100644
index 10d7d32..0000000
--- a/proton-c/include/proton/scanner.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef PROTON_SCANNER_H
-#define PROTON_SCANNER_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <stddef.h>
-#include <stdarg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- PN_TOK_LBRACE,
- PN_TOK_RBRACE,
- PN_TOK_LBRACKET,
- PN_TOK_RBRACKET,
- PN_TOK_EQUAL,
- PN_TOK_COMMA,
- PN_TOK_POS,
- PN_TOK_NEG,
- PN_TOK_DOT,
- PN_TOK_AT,
- PN_TOK_DOLLAR,
- PN_TOK_BINARY,
- PN_TOK_STRING,
- PN_TOK_SYMBOL,
- PN_TOK_ID,
- PN_TOK_FLOAT,
- PN_TOK_INT,
- PN_TOK_TRUE,
- PN_TOK_FALSE,
- PN_TOK_NULL,
- PN_TOK_EOS,
- PN_TOK_ERR
-} pn_token_type_t;
-
-typedef struct pn_scanner_t pn_scanner_t;
-
-typedef struct {
- pn_token_type_t type;
- const char *start;
- size_t size;
-} pn_token_t;
-
-PN_EXTERN pn_scanner_t *pn_scanner(void);
-PN_EXTERN void pn_scanner_free(pn_scanner_t *scanner);
-PN_EXTERN pn_token_t pn_scanner_token(pn_scanner_t *scanner);
-PN_EXTERN int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...);
-PN_EXTERN int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap);
-PN_EXTERN void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col);
-PN_EXTERN int pn_scanner_errno(pn_scanner_t *scanner);
-PN_EXTERN const char *pn_scanner_error(pn_scanner_t *scanner);
-PN_EXTERN int pn_scanner_start(pn_scanner_t *scanner, const char *input);
-PN_EXTERN int pn_scanner_scan(pn_scanner_t *scanner);
-PN_EXTERN int pn_scanner_shift(pn_scanner_t *scanner);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* scanner.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selectable.h b/proton-c/include/proton/selectable.h
index 7b0fa02..fbf3823 100644
--- a/proton-c/include/proton/selectable.h
+++ b/proton-c/include/proton/selectable.h
@@ -25,7 +25,6 @@
#include <proton/import_export.h>
#include <proton/object.h>
#include <proton/event.h>
-#include <proton/io.h>
#include <proton/type_compat.h>
#ifdef __cplusplus
@@ -48,6 +47,34 @@ extern "C" {
typedef pn_iterator_t pn_selectables_t;
/**
+ * A ::pn_socket_t provides an abstract handle to an IO stream. The
+ * pipe version is uni-directional. The network socket version is
+ * bi-directional. Both are non-blocking.
+ *
+ * pn_socket_t handles from ::pn_pipe() may only be used with
+ * ::pn_read(), ::pn_write(), ::pn_close() and pn_selector_select().
+ *
+ * pn_socket_t handles from ::pn_listen(), ::pn_accept() and
+ * ::pn_connect() must perform further IO using Proton functions.
+ * Mixing Proton io.h functions with native IO functions on the same
+ * handles will result in undefined behavior.
+ *
+ * pn_socket_t handles may only be used with a single pn_io_t during
+ * their lifetime.
+ */
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+#ifdef _WIN64
+typedef unsigned __int64 pn_socket_t;
+#else
+typedef unsigned int pn_socket_t;
+#endif
+#define PN_INVALID_SOCKET (pn_socket_t)(~0)
+#else
+typedef int pn_socket_t;
+#define PN_INVALID_SOCKET (-1)
+#endif
+
+/**
* A selectable object provides an interface that can be used to
* incorporate proton's I/O into third party event loops.
*
@@ -72,7 +99,7 @@ typedef struct pn_selectable_t pn_selectable_t;
*
* @return a pointer to a new selectables iterator
*/
-PN_EXTERN pn_selectables_t *pn_selectables(void);
+PNX_EXTERN pn_selectables_t *pn_selectables(void);
/**
* Get the next selectable from an iterator.
@@ -80,25 +107,25 @@ PN_EXTERN pn_selectables_t *pn_selectables(void);
* @param[in] selectables a selectable iterator
* @return the next selectable from the iterator
*/
-PN_EXTERN pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables);
+PNX_EXTERN pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables);
/**
* Free a selectables iterator.
*
* @param[in] selectables a selectables iterator (or NULL)
*/
-PN_EXTERN void pn_selectables_free(pn_selectables_t *selectables);
+PNX_EXTERN void pn_selectables_free(pn_selectables_t *selectables);
-PN_EXTERN pn_selectable_t *pn_selectable(void);
+PNX_EXTERN pn_selectable_t *pn_selectable(void);
-PN_EXTERN void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *));
-PN_EXTERN pn_record_t *pn_selectable_attachments(pn_selectable_t *sel);
+PNX_EXTERN pn_record_t *pn_selectable_attachments(pn_selectable_t *sel);
/**
* Get the file descriptor associated with a selectable.
@@ -106,7 +133,7 @@ PN_EXTERN pn_record_t *pn_selectable_attachments(pn_selectable_t *sel);
* @param[in] selectable a selectable object
* @return the file descriptor associated with the selectable
*/
-PN_EXTERN pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable);
+PNX_EXTERN pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable);
/**
* Set the file descriptor associated with a selectable.
@@ -114,7 +141,7 @@ PN_EXTERN pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable);
* @param[in] selectable a selectable object
* @param[in] fd the file descriptor
*/
-PN_EXTERN void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd);
+PNX_EXTERN void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd);
/**
* Check if a selectable is interested in readable events.
@@ -122,9 +149,9 @@ PN_EXTERN void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd)
* @param[in] selectable a selectable object
* @return true iff the selectable is interested in read events
*/
-PN_EXTERN bool pn_selectable_is_reading(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_reading(pn_selectable_t *selectable);
-PN_EXTERN void pn_selectable_set_reading(pn_selectable_t *sel, bool reading);
+PNX_EXTERN void pn_selectable_set_reading(pn_selectable_t *sel, bool reading);
/**
* Check if a selectable is interested in writable events.
@@ -132,9 +159,9 @@ PN_EXTERN void pn_selectable_set_reading(pn_selectable_t *sel, bool reading);
* @param[in] selectable a selectable object
* @return true iff the selectable is interested in writable events
*/
-PN_EXTERN bool pn_selectable_is_writing(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_writing(pn_selectable_t *selectable);
- PN_EXTERN void pn_selectable_set_writing(pn_selectable_t *sel, bool writing);
+ PNX_EXTERN void pn_selectable_set_writing(pn_selectable_t *sel, bool writing);
/**
* Get the next deadline for a selectable.
@@ -146,37 +173,37 @@ PN_EXTERN bool pn_selectable_is_writing(pn_selectable_t *selectable);
* @param[in] selectable a selectable object
* @return the next deadline or zero
*/
-PN_EXTERN pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *selectable);
+PNX_EXTERN pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *selectable);
-PN_EXTERN void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline);
+PNX_EXTERN void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline);
/**
* Notify a selectable that the file descriptor is readable.
*
* @param[in] selectable a selectable object
*/
-PN_EXTERN void pn_selectable_readable(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_readable(pn_selectable_t *selectable);
/**
* Notify a selectable that the file descriptor is writable.
*
* @param[in] selectable a selectable object
*/
-PN_EXTERN void pn_selectable_writable(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_writable(pn_selectable_t *selectable);
/**
* Notify a selectable that there is an error on the file descriptor.
*
* @param[in] selectable a selectable object
*/
-PN_EXTERN void pn_selectable_error(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_error(pn_selectable_t *selectable);
/**
* Notify a selectable that its deadline has expired.
*
* @param[in] selectable a selectable object
*/
-PN_EXTERN void pn_selectable_expired(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_expired(pn_selectable_t *selectable);
/**
* Check if a selectable is registered.
@@ -188,7 +215,7 @@ PN_EXTERN void pn_selectable_expired(pn_selectable_t *selectable);
* @param[in] selectable
* @return true if the selectable is registered
*/
-PN_EXTERN bool pn_selectable_is_registered(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_registered(pn_selectable_t *selectable);
/**
* Set the registered flag for a selectable.
@@ -198,7 +225,7 @@ PN_EXTERN bool pn_selectable_is_registered(pn_selectable_t *selectable);
* @param[in] selectable a selectable object
* @param[in] registered the registered flag
*/
-PN_EXTERN void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered);
+PNX_EXTERN void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered);
/**
* Check if a selectable is in the terminal state.
@@ -212,23 +239,23 @@ PN_EXTERN void pn_selectable_set_registered(pn_selectable_t *selectable, bool re
* @param[in] selectable a selectable object
* @return true if the selectable is in the terminal state, false otherwise
*/
-PN_EXTERN bool pn_selectable_is_terminal(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_terminal(pn_selectable_t *selectable);
/**
* Terminate a selectable.
*
* @param[in] selectable a selectable object
*/
-PN_EXTERN void pn_selectable_terminate(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_terminate(pn_selectable_t *selectable);
-PN_EXTERN void pn_selectable_release(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_release(pn_selectable_t *selectable);
/**
* Free a selectable object.
*
* @param[in] selectable a selectable object (or NULL)
*/
-PN_EXTERN void pn_selectable_free(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_free(pn_selectable_t *selectable);
/**
* Configure a selectable with a set of callbacks that emit readable,
@@ -237,7 +264,7 @@ PN_EXTERN void pn_selectable_free(pn_selectable_t *selectable);
* @param[in] selectable a selectable objet
* @param[in] collector a collector object
*/
-PN_EXTERN void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector);
+PNX_EXTERN void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector);
/**
* @}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/selector.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selector.h b/proton-c/include/proton/selector.h
deleted file mode 100644
index c942393..0000000
--- a/proton-c/include/proton/selector.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef PROTON_SELECTOR_H
-#define PROTON_SELECTOR_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <proton/selectable.h>
-#include <proton/type_compat.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PN_READABLE (1)
-#define PN_WRITABLE (2)
-#define PN_EXPIRED (4)
-#define PN_ERROR (8)
-
-pn_selector_t *pni_selector(void);
-PN_EXTERN void pn_selector_free(pn_selector_t *selector);
-PN_EXTERN void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable);
-PN_EXTERN void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable);
-PN_EXTERN void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable);
-PN_EXTERN size_t pn_selector_size(pn_selector_t *selector);
-PN_EXTERN int pn_selector_select(pn_selector_t *select, int timeout);
-PN_EXTERN pn_selectable_t *pn_selector_next(pn_selector_t *select, int *events);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* selector.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index 72db6f8..176af47 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -50,10 +50,6 @@ typedef uint32_t pn_seconds_t;
typedef int64_t pn_timestamp_t;
-/** Return a timestamp for the time now. */
-PN_EXTERN pn_timestamp_t pn_timestamp_now(void);
-
-
typedef uint32_t pn_char_t;
typedef uint32_t pn_decimal32_t;
typedef uint64_t pn_decimal64_t;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/url.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/url.h b/proton-c/include/proton/url.h
index 80634c1..2a68bc2 100644
--- a/proton-c/include/proton/url.h
+++ b/proton-c/include/proton/url.h
@@ -37,7 +37,7 @@ extern "C" {
typedef struct pn_url_t pn_url_t;
/** Create an empty URL */
-PN_EXTERN pn_url_t *pn_url(void);
+PNX_EXTERN pn_url_t *pn_url(void);
/** Parse a string URL as a pn_url_t.
*
@@ -56,13 +56,13 @@ PN_EXTERN pn_url_t *pn_url(void);
*@param[in] url A URL string.
*@return The parsed pn_url_t or NULL if url is not a valid URL string.
*/
-PN_EXTERN pn_url_t *pn_url_parse(const char *url);
+PNX_EXTERN pn_url_t *pn_url_parse(const char *url);
/** Free a URL */
-PN_EXTERN void pn_url_free(pn_url_t *url);
+PNX_EXTERN void pn_url_free(pn_url_t *url);
/** Clear the contents of the URL. */
-PN_EXTERN void pn_url_clear(pn_url_t *url);
+PNX_EXTERN void pn_url_clear(pn_url_t *url);
/**
* Return the string form of a URL.
@@ -70,7 +70,7 @@ PN_EXTERN void pn_url_clear(pn_url_t *url);
* The returned string is owned by the pn_url_t and will become invalid if it
* is modified.
*/
-PN_EXTERN const char *pn_url_str(pn_url_t *url);
+PNX_EXTERN const char *pn_url_str(pn_url_t *url);
/**
*@name Getters for parts of the URL.
@@ -79,12 +79,12 @@ PN_EXTERN const char *pn_url_str(pn_url_t *url);
*
*@{
*/
-PN_EXTERN const char *pn_url_get_scheme(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_username(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_password(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_host(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_port(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_path(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_scheme(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_username(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_password(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_host(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_port(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_path(pn_url_t *url);
///@}
/**
@@ -94,12 +94,12 @@ PN_EXTERN const char *pn_url_get_path(pn_url_t *url);
*
*@{
*/
-PN_EXTERN void pn_url_set_scheme(pn_url_t *url, const char *scheme);
-PN_EXTERN void pn_url_set_username(pn_url_t *url, const char *username);
-PN_EXTERN void pn_url_set_password(pn_url_t *url, const char *password);
-PN_EXTERN void pn_url_set_host(pn_url_t *url, const char *host);
-PN_EXTERN void pn_url_set_port(pn_url_t *url, const char *port);
-PN_EXTERN void pn_url_set_path(pn_url_t *url, const char *path);
+PNX_EXTERN void pn_url_set_scheme(pn_url_t *url, const char *scheme);
+PNX_EXTERN void pn_url_set_username(pn_url_t *url, const char *username);
+PNX_EXTERN void pn_url_set_password(pn_url_t *url, const char *password);
+PNX_EXTERN void pn_url_set_host(pn_url_t *url, const char *host);
+PNX_EXTERN void pn_url_set_port(pn_url_t *url, const char *port);
+PNX_EXTERN void pn_url_set_path(pn_url_t *url, const char *path);
///@}
///@}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ProtonConfig.cmake.in
----------------------------------------------------------------------
diff --git a/proton-c/src/ProtonConfig.cmake.in b/proton-c/src/ProtonConfig.cmake.in
index fce1a3a..5e50d7c 100644
--- a/proton-c/src/ProtonConfig.cmake.in
+++ b/proton-c/src/ProtonConfig.cmake.in
@@ -27,4 +27,7 @@ set (Proton_VERSION @PN_VERSION@)
set (Proton_INCLUDE_DIRS @INCLUDEDIR@)
set (Proton_LIBRARIES optimized @LIBDIR@/@PROTONLIB@ debug @LIBDIR@/@PROTONLIBDEBUG@)
+set (ProtonCore_INCLUDE_DIRS @INCLUDEDIR@)
+set (ProtonCore_LIBRARIES optimized @LIBDIR@/@PROTONCORELIB@ debug @LIBDIR@/@PROTONCORELIBDEBUG@)
+
set (Proton_FOUND True)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[05/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ssl/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/schannel.c b/proton-c/src/ssl/schannel.c
new file mode 100644
index 0000000..420e7c5
--- /dev/null
+++ b/proton-c/src/ssl/schannel.c
@@ -0,0 +1,2239 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * SChannel is designed to encrypt and decrypt data in place. So a
+ * given buffer is expected to sometimes contain encrypted data,
+ * sometimes decrypted data, and occasionally both. Outgoing buffers
+ * need to reserve space for the TLS header and trailer. Read
+ * operations need to ignore the same headers and trailers from
+ * incoming buffers. Outgoing is simple because we choose record
+ * boundaries. Incoming is complicated by handling incomplete TLS
+ * records, and buffering contiguous data for the app layer that may
+ * span many records. A lazy double buffering system is used for
+ * the latter.
+ */
+
+#include <proton/ssl.h>
+#include <proton/engine.h>
+#include "core/engine-internal.h"
+#include "platform/platform.h"
+#include "core/util.h"
+#include "core/autodetect.h"
+
+#include <assert.h>
+
+// security.h needs to see this to distinguish from kernel use.
+#include <windows.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <Schnlsp.h>
+#include <WinInet.h>
+#undef SECURITY_WIN32
+
+
+/** @file
+ * SSL/TLS support API.
+ *
+ * This file contains an SChannel-based implemention of the SSL/TLS API for Windows platforms.
+ */
+
+static void ssl_log_error(const char *fmt, ...);
+static void ssl_log(pn_transport_t *transport, const char *fmt, ...);
+static void ssl_log_error_status(HRESULT status, const char *fmt, ...);
+static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error);
+
+/*
+ * win_credential_t: SChannel context that must accompany TLS connections.
+ *
+ * SChannel attempts session resumption for shared CredHandle objects.
+ * To mimic openssl behavior, server CredHandle handles must be shared
+ * by derived connections, client CredHandle handles must be unique
+ * when app's session_id is null and tracked for reuse otherwise
+ * (TODO).
+ *
+ * Ref counted by parent ssl_domain_t and each derived connection.
+ */
+struct win_credential_t {
+ pn_ssl_mode_t mode;
+ PCCERT_CONTEXT cert_context; // Particulars of the certificate (if any)
+ CredHandle cred_handle; // Bound session parameters, certificate, CAs, verification_mode
+ HCERTSTORE trust_store; // Store of root CAs for validating
+ HCERTSTORE server_CA_certs; // CAs advertised by server (may be a duplicate of the trust_store)
+ char *trust_store_name;
+};
+
+#define win_credential_compare NULL
+#define win_credential_inspect NULL
+#define win_credential_hashcode NULL
+
+static void win_credential_initialize(void *object)
+{
+ win_credential_t *c = (win_credential_t *) object;
+ SecInvalidateHandle(&c->cred_handle);
+ c->cert_context = 0;
+ c->trust_store = 0;
+ c->server_CA_certs = 0;
+ c->trust_store_name = 0;
+}
+
+static void win_credential_finalize(void *object)
+{
+ win_credential_t *c = (win_credential_t *) object;
+ if (SecIsValidHandle(&c->cred_handle))
+ FreeCredentialsHandle(&c->cred_handle);
+ if (c->cert_context)
+ CertFreeCertificateContext(c->cert_context);
+ if (c->trust_store)
+ CertCloseStore(c->trust_store, 0);
+ if (c->server_CA_certs)
+ CertCloseStore(c->server_CA_certs, 0);
+ free(c->trust_store_name);
+}
+
+static win_credential_t *win_credential(pn_ssl_mode_t m)
+{
+ static const pn_cid_t CID_win_credential = CID_pn_void;
+ static const pn_class_t clazz = PN_CLASS(win_credential);
+ win_credential_t *c = (win_credential_t *) pn_class_new(&clazz, sizeof(win_credential_t));
+ c->mode = m;
+ return c;
+}
+
+static int win_credential_load_cert(win_credential_t *cred, const char *store_name, const char *cert_name, const char *passwd)
+{
+ if (!store_name)
+ return -2;
+
+ int ec = 0;
+ HCERTSTORE cert_store = open_cert_db(store_name, passwd, &ec);
+ if (!cert_store)
+ return ec;
+
+ // find friendly name that matches cert_name, or sole certificate
+ PCCERT_CONTEXT tmpctx = NULL;
+ PCCERT_CONTEXT found_ctx = NULL;
+ int cert_count = 0;
+ int name_len = cert_name ? strlen(cert_name) : 0;
+ char *fn = name_len ? (char *) malloc(name_len + 1) : 0;
+ while (tmpctx = CertEnumCertificatesInStore(cert_store, tmpctx)) {
+ cert_count++;
+ if (cert_name) {
+ DWORD len = CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
+ 0, NULL, NULL, 0);
+ if (len != name_len + 1)
+ continue;
+ CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
+ 0, NULL, fn, len);
+ if (!strcmp(cert_name, fn)) {
+ found_ctx = tmpctx;
+ tmpctx= NULL;
+ break;
+ }
+ } else {
+ // Test for single certificate
+ if (cert_count == 1) {
+ found_ctx = CertDuplicateCertificateContext(tmpctx);
+ } else {
+ ssl_log_error("Multiple certificates to choose from certificate store %s\n", store_name);
+ found_ctx = NULL;
+ break;
+ }
+ }
+ }
+
+ if (tmpctx) {
+ CertFreeCertificateContext(tmpctx);
+ tmpctx = false;
+ }
+ if (!found_ctx && cert_name && cert_count == 1)
+ ssl_log_error("Could not find certificate %s in store %s\n", cert_name, store_name);
+ cred->cert_context = found_ctx;
+
+ free(fn);
+ CertCloseStore(cert_store, 0);
+ return found_ctx ? 0 : -8;
+}
+
+
+static CredHandle win_credential_cred_handle(win_credential_t *cred, pn_ssl_verify_mode_t verify_mode,
+ const char *session_id, SECURITY_STATUS *status)
+{
+ if (cred->mode == PN_SSL_MODE_SERVER && SecIsValidHandle(&cred->cred_handle)) {
+ *status = SEC_E_OK;
+ return cred->cred_handle; // Server always reuses cached value
+ }
+ // TODO: if (is_client && session_id != NULL) create or use cached value based on
+ // session_id+server_host_name (per domain? reclaimed after X hours?)
+
+ CredHandle tmp_handle;
+ SecInvalidateHandle(&tmp_handle);
+ TimeStamp expiry; // Not used
+ SCHANNEL_CRED descriptor;
+ memset(&descriptor, 0, sizeof(descriptor));
+
+ descriptor.dwVersion = SCHANNEL_CRED_VERSION;
+ descriptor.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
+ if (cred->cert_context != NULL) {
+ // assign the certificate into the credentials
+ descriptor.paCred = &cred->cert_context;
+ descriptor.cCreds = 1;
+ }
+
+ if (cred->mode == PN_SSL_MODE_SERVER) {
+ descriptor.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
+ if (cred->server_CA_certs) {
+ descriptor.hRootStore = cred->server_CA_certs;
+ }
+ }
+
+ ULONG direction = (cred->mode == PN_SSL_MODE_SERVER) ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND;
+ *status = AcquireCredentialsHandle(NULL, UNISP_NAME, direction, NULL,
+ &descriptor, NULL, NULL, &tmp_handle, &expiry);
+ if (cred->mode == PN_SSL_MODE_SERVER && *status == SEC_E_OK)
+ cred->cred_handle = tmp_handle;
+
+ return tmp_handle;
+}
+
+static bool win_credential_has_certificate(win_credential_t *cred)
+{
+ if (!cred) return false;
+ return (cred->cert_context != NULL);
+}
+
+#define SSL_DATA_SIZE 16384
+#define SSL_BUF_SIZE (SSL_DATA_SIZE + 5 + 2048 + 32)
+
+typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
+typedef struct pn_ssl_session_t pn_ssl_session_t;
+
+struct pn_ssl_domain_t {
+ int ref_count;
+ pn_ssl_mode_t mode;
+ bool has_ca_db; // true when CA database configured
+ pn_ssl_verify_mode_t verify_mode;
+ bool allow_unsecured;
+ win_credential_t *cred;
+};
+
+typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
+ RUNNING, SHUTTING_DOWN, SSL_CLOSED } ssl_state_t;
+
+struct pni_ssl_t {
+ pn_ssl_domain_t *domain;
+ const char *session_id;
+ const char *peer_hostname;
+ ssl_state_t state;
+
+ bool protocol_detected;
+ bool queued_shutdown;
+ bool ssl_closed; // shutdown complete, or SSL error
+ ssize_t app_input_closed; // error code returned by upper layer process input
+ ssize_t app_output_closed; // error code returned by upper layer process output
+
+ // OpenSSL hides the protocol envelope bytes, SChannel has them in-line.
+ char *sc_outbuf; // SChannel output buffer
+ size_t sc_out_size;
+ size_t sc_out_count;
+ char *network_outp; // network ready bytes within sc_outbuf
+ size_t network_out_pending;
+
+ char *sc_inbuf; // SChannel input buffer
+ size_t sc_in_size;
+ size_t sc_in_count;
+ bool sc_in_incomplete;
+
+ char *inbuf_extra; // Still encrypted data from following Record(s)
+ size_t extra_count;
+
+ char *in_data; // Just the plaintext data part of sc_inbuf, decrypted in place
+ size_t in_data_size;
+ size_t in_data_count;
+ bool decrypting;
+ size_t max_data_size; // computed in the handshake
+
+ pn_bytes_t app_inbytes; // Virtual decrypted datastream, presented to app layer
+
+ pn_buffer_t *inbuf2; // Second input buf if longer contiguous bytes needed
+ bool double_buffered;
+
+ bool sc_input_shutdown;
+
+ CredHandle cred_handle;
+ CtxtHandle ctxt_handle;
+ SecPkgContext_StreamSizes sc_sizes;
+ pn_ssl_verify_mode_t verify_mode;
+ win_credential_t *cred;
+ char *subject;
+};
+
+static inline pn_transport_t *get_transport_internal(pn_ssl_t *ssl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return ((pn_transport_t *)ssl);
+}
+
+static inline pni_ssl_t *get_ssl_internal(pn_ssl_t *ssl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return ssl ? ((pn_transport_t *)ssl)->ssl : NULL;
+}
+
+struct pn_ssl_session_t {
+ const char *id;
+// TODO
+ pn_ssl_session_t *ssn_cache_next;
+ pn_ssl_session_t *ssn_cache_prev;
+};
+
+
+static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
+static void ssl_session_free( pn_ssl_session_t *);
+static size_t buffered_output( pn_transport_t *transport );
+static void start_ssl_shutdown(pn_transport_t *transport);
+static void rewind_sc_inbuf(pni_ssl_t *ssl);
+static bool grow_inbuf2(pn_transport_t *ssl, size_t minimum_size);
+static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing);
+
+// @todo: used to avoid littering the code with calls to printf...
+static void ssl_log_error(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fflush(stderr);
+}
+
+// @todo: used to avoid littering the code with calls to printf...
+static void ssl_log(pn_transport_t *transport, const char *fmt, ...)
+{
+ if (PN_TRACE_DRV & transport->trace) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fflush(stderr);
+ }
+}
+
+static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
+{
+ char buf[512];
+ va_list ap;
+
+ if (fmt) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+
+ if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, status, 0, buf, sizeof(buf), 0))
+ ssl_log_error(" : %s\n", buf);
+ else
+ fprintf(stderr, "pn internal Windows error: %x for %x\n", GetLastError(), status);
+
+ fflush(stderr);
+}
+
+static void ssl_log_clear_data(pn_transport_t *transport, const char *data, size_t len)
+{
+ if (PN_TRACE_RAW & transport->trace) {
+ fprintf(stderr, "SSL decrypted data: \"");
+ pn_fprint_data( stderr, data, len );
+ fprintf(stderr, "\"\n");
+ }
+}
+
+static size_t _pni_min(size_t a, size_t b)
+{
+ return (a < b) ? a : b;
+}
+
+// unrecoverable SSL failure occured, notify transport and generate error code.
+static int ssl_failed(pn_transport_t *transport, const char *reason)
+{
+ char buf[512] = "Unknown error.";
+ if (!reason) {
+ HRESULT status = GetLastError();
+
+ FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, status, 0, buf, sizeof(buf), 0);
+ reason = buf;
+ }
+ pni_ssl_t *ssl = transport->ssl;
+ ssl->ssl_closed = true;
+ ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
+ ssl->state = SSL_CLOSED;
+ pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
+ return PN_EOS;
+}
+
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *domain, const char *id )
+{
+// TODO:
+ return NULL;
+}
+
+static void ssl_session_free( pn_ssl_session_t *ssn)
+{
+ if (ssn) {
+ if (ssn->id) free( (void *)ssn->id );
+ free( ssn );
+ }
+}
+
+
+/** Public API - visible to application code */
+
+bool pn_ssl_present(void)
+{
+ return true;
+}
+
+pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
+{
+ pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
+ if (!domain) return NULL;
+
+ domain->ref_count = 1;
+ domain->mode = mode;
+ switch(mode) {
+ case PN_SSL_MODE_CLIENT:
+ case PN_SSL_MODE_SERVER:
+ break;
+
+ default:
+ ssl_log_error("Invalid mode for pn_ssl_mode_t: %d\n", mode);
+ free(domain);
+ return NULL;
+ }
+ domain->cred = win_credential(mode);
+ return domain;
+}
+
+void pn_ssl_domain_free( pn_ssl_domain_t *domain )
+{
+ if (!domain) return;
+
+ if (--domain->ref_count == 0) {
+ pn_decref(domain->cred);
+ free(domain);
+ }
+}
+
+
+int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
+ const char *certificate_file,
+ const char *private_key_file,
+ const char *password)
+{
+ if (!domain) return -1;
+
+ if (win_credential_has_certificate(domain->cred)) {
+ // Need a new win_credential_t to hold new certificate
+ pn_decref(domain->cred);
+ domain->cred = win_credential(domain->mode);
+ if (!domain->cred)
+ return -1;
+ }
+ return win_credential_load_cert(domain->cred, certificate_file, private_key_file, password);
+}
+
+
+int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
+ const char *certificate_db)
+{
+ if (!domain || !certificate_db) return -1;
+
+ int ec = 0;
+ HCERTSTORE store = open_cert_db(certificate_db, NULL, &ec);
+ if (!store)
+ return ec;
+
+ if (domain->has_ca_db) {
+ win_credential_t *new_cred = win_credential(domain->mode);
+ if (!new_cred)
+ return -1;
+ new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
+ pn_decref(domain->cred);
+ domain->cred = new_cred;
+ }
+
+ domain->cred->trust_store = store;
+ domain->cred->trust_store_name = pn_strdup(certificate_db);
+ domain->has_ca_db = true;
+ return 0;
+}
+
+
+int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
+ const pn_ssl_verify_mode_t mode,
+ const char *trusted_CAs)
+{
+ if (!domain) return -1;
+ if (!domain->has_ca_db && (mode == PN_SSL_VERIFY_PEER || mode == PN_SSL_VERIFY_PEER_NAME)) {
+ ssl_log_error("Error: cannot verify peer without a trusted CA configured.\n"
+ " Use pn_ssl_domain_set_trusted_ca_db()\n");
+ return -1;
+ }
+
+ HCERTSTORE store = 0;
+ bool changed = domain->verify_mode && mode != domain->verify_mode;
+
+ switch (mode) {
+ case PN_SSL_VERIFY_PEER:
+ case PN_SSL_VERIFY_PEER_NAME:
+ if (domain->mode == PN_SSL_MODE_SERVER) {
+ if (!trusted_CAs) {
+ ssl_log_error("Error: a list of trusted CAs must be provided.");
+ return -1;
+ }
+ if (!win_credential_has_certificate(domain->cred)) {
+ ssl_log_error("Error: Server cannot verify peer without configuring a certificate.\n"
+ " Use pn_ssl_domain_set_credentials()");
+ return -1;
+ }
+ int ec = 0;
+ if (!strcmp(trusted_CAs, domain->cred->trust_store_name)) {
+ store = open_cert_db(trusted_CAs, NULL, &ec);
+ if (!store)
+ return ec;
+ } else {
+ store = CertDuplicateStore(domain->cred->trust_store);
+ }
+
+ if (domain->cred->server_CA_certs) {
+ // Already have one
+ changed = true;
+ win_credential_t *new_cred = win_credential(domain->mode);
+ if (!new_cred) {
+ CertCloseStore(store, 0);
+ return -1;
+ }
+ new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
+ new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
+ new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
+ pn_decref(domain->cred);
+ domain->cred = new_cred;
+ }
+
+ domain->cred->server_CA_certs = store;
+ }
+ break;
+
+ case PN_SSL_ANONYMOUS_PEER: // hippie free love mode... :)
+ break;
+
+ default:
+ ssl_log_error("Invalid peer authentication mode given.\n");
+ return -1;
+ }
+
+ if (changed) {
+ win_credential_t *new_cred = win_credential(domain->mode);
+ if (!new_cred) {
+ CertCloseStore(store, 0);
+ return -1;
+ }
+ new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
+ new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
+ new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
+ pn_decref(domain->cred);
+ domain->cred = new_cred;
+ }
+
+ domain->verify_mode = mode;
+ domain->cred->server_CA_certs = store;
+
+ return 0;
+}
+
+const pn_io_layer_t ssl_layer = {
+ process_input_ssl,
+ process_output_ssl,
+ NULL,
+ NULL,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_input_closed_layer = {
+ process_input_done,
+ process_output_ssl,
+ NULL,
+ NULL,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_output_closed_layer = {
+ process_input_ssl,
+ process_output_done,
+ NULL,
+ NULL,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_closed_layer = {
+ process_input_done,
+ process_output_done,
+ NULL,
+ NULL,
+ buffered_output
+};
+
+int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
+{
+ pn_transport_t *transport = get_transport_internal(ssl0);
+ pni_ssl_t *ssl = transport->ssl;
+ if (!ssl || !domain || ssl->domain) return -1;
+ if (ssl->state != CREATED) return -1;
+
+ ssl->domain = domain;
+ domain->ref_count++;
+ if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
+ ssl->session_id = pn_strdup(session_id);
+
+ // If SSL doesn't specifically allow skipping encryption, require SSL
+ // TODO: This is a probably a stop-gap until allow_unsecured is removed
+ if (!domain->allow_unsecured) transport->encryption_required = true;
+
+ ssl->cred = domain->cred;
+ pn_incref(domain->cred);
+
+ SECURITY_STATUS status = SEC_E_OK;
+ ssl->cred_handle = win_credential_cred_handle(ssl->cred, ssl->verify_mode,
+ ssl->session_id, &status);
+ if (status != SEC_E_OK) {
+ ssl_log_error_status(status, "Credentials handle failure");
+ return -1;
+ }
+
+ ssl->state = (domain->mode == PN_SSL_MODE_CLIENT) ? CLIENT_HELLO : NEGOTIATING;
+ ssl->verify_mode = domain->verify_mode;
+ return 0;
+}
+
+
+int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
+{
+ if (!domain) return -1;
+ if (domain->mode != PN_SSL_MODE_SERVER) {
+ ssl_log_error("Cannot permit unsecured clients - not a server.\n");
+ return -1;
+ }
+ domain->allow_unsecured = true;
+ return 0;
+}
+
+
+// TODO: This is just an untested guess
+int pn_ssl_get_ssf(pn_ssl_t *ssl0)
+{
+ SecPkgContext_ConnectionInfo info;
+
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
+ if (ssl &&
+ ssl->state == RUNNING &&
+ SecIsValidHandle(&ssl->ctxt_handle) &&
+ QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
+ return info.dwCipherStrength;
+ }
+ return 0;
+}
+
+bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
+{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
+ if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
+ return false;
+ *buffer = '\0';
+ SecPkgContext_ConnectionInfo info;
+ if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
+ // TODO: come up with string for all permutations?
+ pni_snprintf( buffer, size, "%x_%x:%x_%x:%x_%x",
+ info.aiExch, info.dwExchStrength,
+ info.aiCipher, info.dwCipherStrength,
+ info.aiHash, info.dwHashStrength);
+ return true;
+ }
+ return false;
+}
+
+bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
+{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
+ if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
+ return false;
+ *buffer = '\0';
+ SecPkgContext_ConnectionInfo info;
+ if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
+ if (info.dwProtocol & (SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_SERVER))
+ pni_snprintf(buffer, size, "%s", "TLSv1");
+ // TLSV1.1 and TLSV1.2 are supported as of XP-SP3, but not defined until VS2010
+ else if ((info.dwProtocol & 0x300))
+ pni_snprintf(buffer, size, "%s", "TLSv1.1");
+ else if ((info.dwProtocol & 0xC00))
+ pni_snprintf(buffer, size, "%s", "TLSv1.2");
+ else {
+ ssl_log_error("unexpected protocol %x\n", info.dwProtocol);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+void pn_ssl_free( pn_transport_t *transport)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ if (!ssl) return;
+ ssl_log( transport, "SSL socket freed.\n" );
+ // clean up Windows per TLS session data before releasing the domain count
+ if (SecIsValidHandle(&ssl->ctxt_handle))
+ DeleteSecurityContext(&ssl->ctxt_handle);
+ if (ssl->cred) {
+ if (ssl->domain->mode == PN_SSL_MODE_CLIENT && ssl->session_id == NULL) {
+ // Responsible for unshared handle
+ if (SecIsValidHandle(&ssl->cred_handle))
+ FreeCredentialsHandle(&ssl->cred_handle);
+ }
+ pn_decref(ssl->cred);
+ }
+
+ if (ssl->domain) pn_ssl_domain_free(ssl->domain);
+ if (ssl->session_id) free((void *)ssl->session_id);
+ if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
+ if (ssl->sc_inbuf) free((void *)ssl->sc_inbuf);
+ if (ssl->sc_outbuf) free((void *)ssl->sc_outbuf);
+ if (ssl->inbuf2) pn_buffer_free(ssl->inbuf2);
+ if (ssl->subject) free(ssl->subject);
+
+ free(ssl);
+}
+
+pn_ssl_t *pn_ssl(pn_transport_t *transport)
+{
+ if (!transport) return NULL;
+ if (transport->ssl) return (pn_ssl_t *)transport;
+
+ pni_ssl_t *ssl = (pni_ssl_t *) calloc(1, sizeof(pni_ssl_t));
+ if (!ssl) return NULL;
+ ssl->sc_out_size = ssl->sc_in_size = SSL_BUF_SIZE;
+
+ ssl->sc_outbuf = (char *)malloc(ssl->sc_out_size);
+ if (!ssl->sc_outbuf) {
+ free(ssl);
+ return NULL;
+ }
+ ssl->sc_inbuf = (char *)malloc(ssl->sc_in_size);
+ if (!ssl->sc_inbuf) {
+ free(ssl->sc_outbuf);
+ free(ssl);
+ return NULL;
+ }
+
+ ssl->inbuf2 = pn_buffer(0);
+ if (!ssl->inbuf2) {
+ free(ssl->sc_inbuf);
+ free(ssl->sc_outbuf);
+ free(ssl);
+ return NULL;
+ }
+
+ transport->ssl = ssl;
+
+ // Set up hostname from any bound connection
+ if (transport->connection) {
+ if (pn_string_size(transport->connection->hostname)) {
+ pn_ssl_set_peer_hostname((pn_ssl_t *) transport, pn_string_get(transport->connection->hostname));
+ }
+ }
+
+ SecInvalidateHandle(&ssl->cred_handle);
+ SecInvalidateHandle(&ssl->ctxt_handle);
+ ssl->state = CREATED;
+ ssl->decrypting = true;
+
+ return (pn_ssl_t *)transport;
+}
+
+
+pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
+{
+ // TODO
+ return PN_SSL_RESUME_UNKNOWN;
+}
+
+
+int pn_ssl_set_peer_hostname( pn_ssl_t *ssl0, const char *hostname )
+{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
+ if (!ssl) return -1;
+
+ if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
+ ssl->peer_hostname = NULL;
+ if (hostname) {
+ ssl->peer_hostname = pn_strdup(hostname);
+ if (!ssl->peer_hostname) return -2;
+ }
+ return 0;
+}
+
+int pn_ssl_get_peer_hostname( pn_ssl_t *ssl0, char *hostname, size_t *bufsize )
+{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
+ if (!ssl) return -1;
+ if (!ssl->peer_hostname) {
+ *bufsize = 0;
+ if (hostname) *hostname = '\0';
+ return 0;
+ }
+ unsigned len = strlen(ssl->peer_hostname);
+ if (hostname) {
+ if (len >= *bufsize) return -1;
+ strcpy( hostname, ssl->peer_hostname );
+ }
+ *bufsize = len;
+ return 0;
+}
+
+const char* pn_ssl_get_remote_subject(pn_ssl_t *ssl0)
+{
+ // RFC 2253 compliant, but differs from openssl's subject string with space separators and
+ // ordering of multicomponent RDNs. Made to work as similarly as possible with choice of flags.
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
+ if (!ssl || !SecIsValidHandle(&ssl->ctxt_handle))
+ return NULL;
+ if (!ssl->subject) {
+ SECURITY_STATUS status;
+ PCCERT_CONTEXT peer_cc = 0;
+ status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
+ if (status != SEC_E_OK) {
+ ssl_log_error_status(status, "can't obtain remote certificate subject");
+ return NULL;
+ }
+ DWORD flags = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
+ DWORD strlen = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
+ flags, NULL, 0);
+ if (strlen > 0) {
+ ssl->subject = (char*) malloc(strlen);
+ if (ssl->subject) {
+ DWORD len = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
+ flags, ssl->subject, strlen);
+ if (len != strlen) {
+ free(ssl->subject);
+ ssl->subject = NULL;
+ ssl_log_error("pn_ssl_get_remote_subject failure in CertNameToStr");
+ }
+ }
+ }
+ CertFreeCertificateContext(peer_cc);
+ }
+ return ssl->subject;
+}
+
+
+/** SChannel specific: */
+
+const char *tls_version_check(pni_ssl_t *ssl)
+{
+ SecPkgContext_ConnectionInfo info;
+ QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info);
+ // Ascending bit patterns denote newer SSL/TLS protocol versions.
+ // SP_PROT_TLS1_0_SERVER is not defined until VS2010.
+ return (info.dwProtocol < SP_PROT_TLS1_SERVER) ?
+ "peer does not support TLS 1.0 security" : NULL;
+}
+
+static void ssl_encrypt(pn_transport_t *transport, char *app_data, size_t count)
+{
+ pni_ssl_t *ssl = transport->ssl;
+
+ // Get SChannel to encrypt exactly one Record.
+ SecBuffer buffs[4];
+ buffs[0].cbBuffer = ssl->sc_sizes.cbHeader;
+ buffs[0].BufferType = SECBUFFER_STREAM_HEADER;
+ buffs[0].pvBuffer = ssl->sc_outbuf;
+ buffs[1].cbBuffer = count;
+ buffs[1].BufferType = SECBUFFER_DATA;
+ buffs[1].pvBuffer = app_data;
+ buffs[2].cbBuffer = ssl->sc_sizes.cbTrailer;
+ buffs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+ buffs[2].pvBuffer = &app_data[count];
+ buffs[3].cbBuffer = 0;
+ buffs[3].BufferType = SECBUFFER_EMPTY;
+ buffs[3].pvBuffer = 0;
+ SecBufferDesc buff_desc;
+ buff_desc.ulVersion = SECBUFFER_VERSION;
+ buff_desc.cBuffers = 4;
+ buff_desc.pBuffers = buffs;
+ SECURITY_STATUS status = EncryptMessage(&ssl->ctxt_handle, 0, &buff_desc, 0);
+ assert(status == SEC_E_OK);
+
+ // EncryptMessage encrypts the data in place. The header and trailer
+ // areas were reserved previously and must now be included in the updated
+ // count of bytes to write to the peer.
+ ssl->sc_out_count = buffs[0].cbBuffer + buffs[1].cbBuffer + buffs[2].cbBuffer;
+ ssl->network_outp = ssl->sc_outbuf;
+ ssl->network_out_pending = ssl->sc_out_count;
+ ssl_log(transport, "ssl_encrypt %d network bytes\n", ssl->network_out_pending);
+}
+
+// Returns true if decryption succeeded (even for empty content)
+static bool ssl_decrypt(pn_transport_t *transport)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ // Get SChannel to decrypt input. May have an incomplete Record,
+ // exactly one, or more than one. Check also for session ending,
+ // session renegotiation.
+
+ SecBuffer recv_buffs[4];
+ recv_buffs[0].cbBuffer = ssl->sc_in_count;
+ recv_buffs[0].BufferType = SECBUFFER_DATA;
+ recv_buffs[0].pvBuffer = ssl->sc_inbuf;
+ recv_buffs[1].BufferType = SECBUFFER_EMPTY;
+ recv_buffs[2].BufferType = SECBUFFER_EMPTY;
+ recv_buffs[3].BufferType = SECBUFFER_EMPTY;
+ SecBufferDesc buff_desc;
+ buff_desc.ulVersion = SECBUFFER_VERSION;
+ buff_desc.cBuffers = 4;
+ buff_desc.pBuffers = recv_buffs;
+ SECURITY_STATUS status = DecryptMessage(&ssl->ctxt_handle, &buff_desc, 0, NULL);
+
+ if (status == SEC_E_INCOMPLETE_MESSAGE) {
+ // Less than a full Record, come back later with more network data
+ ssl->sc_in_incomplete = true;
+ return false;
+ }
+
+ ssl->decrypting = false;
+
+ if (status != SEC_E_OK) {
+ rewind_sc_inbuf(ssl);
+ switch (status) {
+ case SEC_I_CONTEXT_EXPIRED:
+ // TLS shutdown alert record. Ignore all subsequent input.
+ ssl->state = SHUTTING_DOWN;
+ ssl->sc_input_shutdown = true;
+ return false;
+
+ case SEC_I_RENEGOTIATE:
+ ssl_log_error("unexpected TLS renegotiation\n");
+ // TODO. Fall through for now.
+ default:
+ ssl_failed(transport, 0);
+ return false;
+ }
+ }
+
+ ssl->decrypting = false;
+ // have a decrypted Record and possible (still-encrypted) data of
+ // one (or more) later Recordss. Adjust pointers accordingly.
+ for (int i = 0; i < 4; i++) {
+ switch (recv_buffs[i].BufferType) {
+ case SECBUFFER_DATA:
+ ssl->in_data = (char *) recv_buffs[i].pvBuffer;
+ ssl->in_data_size = ssl->in_data_count = recv_buffs[i].cbBuffer;
+ break;
+ case SECBUFFER_EXTRA:
+ ssl->inbuf_extra = (char *)recv_buffs[i].pvBuffer;
+ ssl->extra_count = recv_buffs[i].cbBuffer;
+ break;
+ default:
+ // SECBUFFER_STREAM_HEADER:
+ // SECBUFFER_STREAM_TRAILER:
+ break;
+ }
+ }
+ return true;
+}
+
+static void client_handshake_init(pn_transport_t *transport)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ // Tell SChannel to create the first handshake token (ClientHello)
+ // and place it in sc_outbuf
+ SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
+ ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_EXTENDED_ERROR;
+ ULONG ctxt_attrs;
+
+ SecBuffer send_buffs[2];
+ send_buffs[0].cbBuffer = ssl->sc_out_size;
+ send_buffs[0].BufferType = SECBUFFER_TOKEN;
+ send_buffs[0].pvBuffer = ssl->sc_outbuf;
+ send_buffs[1].cbBuffer = 0;
+ send_buffs[1].BufferType = SECBUFFER_EMPTY;
+ send_buffs[1].pvBuffer = 0;
+ SecBufferDesc send_buff_desc;
+ send_buff_desc.ulVersion = SECBUFFER_VERSION;
+ send_buff_desc.cBuffers = 2;
+ send_buff_desc.pBuffers = send_buffs;
+ SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
+ NULL, host, ctxt_requested, 0, 0, NULL, 0,
+ &ssl->ctxt_handle, &send_buff_desc,
+ &ctxt_attrs, NULL);
+
+ if (status == SEC_I_CONTINUE_NEEDED) {
+ ssl->sc_out_count = send_buffs[0].cbBuffer;
+ ssl->network_out_pending = ssl->sc_out_count;
+ // the token is the whole quantity to send
+ ssl->network_outp = ssl->sc_outbuf;
+ ssl_log(transport, "Sending client hello %d bytes\n", ssl->network_out_pending);
+ } else {
+ ssl_log_error_status(status, "InitializeSecurityContext failed");
+ ssl_failed(transport, 0);
+ }
+}
+
+static void client_handshake( pn_transport_t* transport) {
+ pni_ssl_t *ssl = transport->ssl;
+ // Feed SChannel ongoing responses from the server until the handshake is complete.
+ SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
+ ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
+ ULONG ctxt_attrs;
+ size_t max = 0;
+
+ // token_buffs describe the buffer that's coming in. It should have
+ // a token from the SSL server, or empty if sending final shutdown alert.
+ bool shutdown = ssl->state == SHUTTING_DOWN;
+ SecBuffer token_buffs[2];
+ token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
+ token_buffs[0].BufferType = SECBUFFER_TOKEN;
+ token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
+ token_buffs[1].cbBuffer = 0;
+ token_buffs[1].BufferType = SECBUFFER_EMPTY;
+ token_buffs[1].pvBuffer = 0;
+ SecBufferDesc token_buff_desc;
+ token_buff_desc.ulVersion = SECBUFFER_VERSION;
+ token_buff_desc.cBuffers = 2;
+ token_buff_desc.pBuffers = token_buffs;
+
+ // send_buffs will hold information to forward to the peer.
+ SecBuffer send_buffs[2];
+ send_buffs[0].cbBuffer = ssl->sc_out_size;
+ send_buffs[0].BufferType = SECBUFFER_TOKEN;
+ send_buffs[0].pvBuffer = ssl->sc_outbuf;
+ send_buffs[1].cbBuffer = 0;
+ send_buffs[1].BufferType = SECBUFFER_EMPTY;
+ send_buffs[1].pvBuffer = 0;
+ SecBufferDesc send_buff_desc;
+ send_buff_desc.ulVersion = SECBUFFER_VERSION;
+ send_buff_desc.cBuffers = 2;
+ send_buff_desc.pBuffers = send_buffs;
+
+ SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
+ &ssl->ctxt_handle, host, ctxt_requested, 0, 0,
+ &token_buff_desc, 0, NULL, &send_buff_desc,
+ &ctxt_attrs, NULL);
+ switch (status) {
+ case SEC_E_INCOMPLETE_MESSAGE:
+ // Not enough - get more data from the server then try again.
+ // Leave input buffers untouched.
+ ssl_log(transport, "client handshake: incomplete record\n");
+ ssl->sc_in_incomplete = true;
+ return;
+
+ case SEC_I_CONTINUE_NEEDED:
+ // Successful handshake step, requiring data to be sent to peer.
+ ssl->sc_out_count = send_buffs[0].cbBuffer;
+ // the token is the whole quantity to send
+ ssl->network_out_pending = ssl->sc_out_count;
+ ssl->network_outp = ssl->sc_outbuf;
+ ssl_log(transport, "client handshake token %d bytes\n", ssl->network_out_pending);
+ break;
+
+ case SEC_E_OK:
+ // Handshake complete.
+ if (shutdown) {
+ if (send_buffs[0].cbBuffer > 0) {
+ ssl->sc_out_count = send_buffs[0].cbBuffer;
+ // the token is the whole quantity to send
+ ssl->network_out_pending = ssl->sc_out_count;
+ ssl->network_outp = ssl->sc_outbuf;
+ ssl_log(transport, "client shutdown token %d bytes\n", ssl->network_out_pending);
+ } else {
+ ssl->state = SSL_CLOSED;
+ }
+ // we didn't touch sc_inbuf, no need to reset
+ return;
+ }
+ if (send_buffs[0].cbBuffer != 0) {
+ ssl_failed(transport, "unexpected final server token");
+ break;
+ }
+ if (const char *err = tls_version_check(ssl)) {
+ ssl_failed(transport, err);
+ break;
+ }
+ if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
+ bool tracing = PN_TRACE_DRV & transport->trace;
+ HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, ssl->peer_hostname, tracing);
+ if (ec) {
+ if (ssl->peer_hostname)
+ ssl_log_error_status(ec, "certificate verification failed for host %s\n", ssl->peer_hostname);
+ else
+ ssl_log_error_status(ec, "certificate verification failed\n");
+ ssl_failed(transport, "TLS certificate verification error");
+ break;
+ }
+ }
+
+ if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0) {
+ // This seems to work but not documented, plus logic differs from decrypt message
+ // since the pvBuffer value is not set. Grrr.
+ ssl->extra_count = token_buffs[1].cbBuffer;
+ ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
+ }
+
+ QueryContextAttributes(&ssl->ctxt_handle,
+ SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
+ max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
+ if (max > ssl->sc_out_size) {
+ ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
+ ssl->state = SHUTTING_DOWN;
+ ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
+ start_ssl_shutdown(transport);
+ pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
+ break;
+ }
+
+ ssl->state = RUNNING;
+ ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
+ ssl_log(transport, "client handshake successful %d max record size\n", max);
+ break;
+
+ case SEC_I_CONTEXT_EXPIRED:
+ // ended before we got going
+ default:
+ ssl_log(transport, "client handshake failed %d\n", (int) status);
+ ssl_failed(transport, 0);
+ break;
+ }
+
+ if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
+ !ssl->ssl_closed) {
+ // remaining data after the consumed TLS record(s)
+ ssl->extra_count = token_buffs[1].cbBuffer;
+ ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
+ }
+
+ ssl->decrypting = false;
+ rewind_sc_inbuf(ssl);
+}
+
+
+static void server_handshake(pn_transport_t* transport)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ if (!ssl->protocol_detected) {
+ // SChannel fails less aggressively than openssl on client hello, causing hangs
+ // waiting for more bytes. Help out here.
+ pni_protocol_type_t type = pni_sniff_header(ssl->sc_inbuf, ssl->sc_in_count);
+ if (type == PNI_PROTOCOL_INSUFFICIENT) {
+ ssl_log(transport, "server handshake: incomplete record\n");
+ ssl->sc_in_incomplete = true;
+ return;
+ } else {
+ ssl->protocol_detected = true;
+ if (type != PNI_PROTOCOL_SSL) {
+ ssl_failed(transport, "bad client hello");
+ ssl->decrypting = false;
+ rewind_sc_inbuf(ssl);
+ return;
+ }
+ }
+ }
+
+ // Feed SChannel ongoing handshake records from the client until the handshake is complete.
+ ULONG ctxt_requested = ASC_REQ_STREAM | ASC_REQ_EXTENDED_ERROR;
+ if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME)
+ ctxt_requested |= ASC_REQ_MUTUAL_AUTH;
+ ULONG ctxt_attrs;
+ size_t max = 0;
+
+ // token_buffs describe the buffer that's coming in. It should have
+ // a token from the SSL client except if shutting down or renegotiating.
+ bool shutdown = ssl->state == SHUTTING_DOWN;
+ SecBuffer token_buffs[2];
+ token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
+ token_buffs[0].BufferType = SECBUFFER_TOKEN;
+ token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
+ token_buffs[1].cbBuffer = 0;
+ token_buffs[1].BufferType = SECBUFFER_EMPTY;
+ token_buffs[1].pvBuffer = 0;
+ SecBufferDesc token_buff_desc;
+ token_buff_desc.ulVersion = SECBUFFER_VERSION;
+ token_buff_desc.cBuffers = 2;
+ token_buff_desc.pBuffers = token_buffs;
+
+ // send_buffs will hold information to forward to the peer.
+ SecBuffer send_buffs[2];
+ send_buffs[0].cbBuffer = ssl->sc_out_size;
+ send_buffs[0].BufferType = SECBUFFER_TOKEN;
+ send_buffs[0].pvBuffer = ssl->sc_outbuf;
+ send_buffs[1].cbBuffer = 0;
+ send_buffs[1].BufferType = SECBUFFER_EMPTY;
+ send_buffs[1].pvBuffer = 0;
+ SecBufferDesc send_buff_desc;
+ send_buff_desc.ulVersion = SECBUFFER_VERSION;
+ send_buff_desc.cBuffers = 2;
+ send_buff_desc.pBuffers = send_buffs;
+ PCtxtHandle ctxt_handle_ptr = (SecIsValidHandle(&ssl->ctxt_handle)) ? &ssl->ctxt_handle : 0;
+
+ SECURITY_STATUS status = AcceptSecurityContext(&ssl->cred_handle, ctxt_handle_ptr,
+ &token_buff_desc, ctxt_requested, 0, &ssl->ctxt_handle,
+ &send_buff_desc, &ctxt_attrs, NULL);
+
+ bool outbound_token = false;
+ switch(status) {
+ case SEC_E_INCOMPLETE_MESSAGE:
+ // Not enough - get more data from the client then try again.
+ // Leave input buffers untouched.
+ ssl_log(transport, "server handshake: incomplete record\n");
+ ssl->sc_in_incomplete = true;
+ return;
+
+ case SEC_I_CONTINUE_NEEDED:
+ outbound_token = true;
+ break;
+
+ case SEC_E_OK:
+ // Handshake complete.
+ if (shutdown) {
+ if (send_buffs[0].cbBuffer > 0) {
+ ssl->sc_out_count = send_buffs[0].cbBuffer;
+ // the token is the whole quantity to send
+ ssl->network_out_pending = ssl->sc_out_count;
+ ssl->network_outp = ssl->sc_outbuf;
+ ssl_log(transport, "server shutdown token %d bytes\n", ssl->network_out_pending);
+ } else {
+ ssl->state = SSL_CLOSED;
+ }
+ // we didn't touch sc_inbuf, no need to reset
+ return;
+ }
+ if (const char *err = tls_version_check(ssl)) {
+ ssl_failed(transport, err);
+ break;
+ }
+ // Handshake complete.
+
+ if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
+ bool tracing = PN_TRACE_DRV & transport->trace;
+ HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, NULL, tracing);
+ if (ec) {
+ ssl_log_error_status(ec, "certificate verification failed\n");
+ ssl_failed(transport, "certificate verification error");
+ break;
+ }
+ }
+
+ QueryContextAttributes(&ssl->ctxt_handle,
+ SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
+ max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
+ if (max > ssl->sc_out_size) {
+ ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
+ ssl->state = SHUTTING_DOWN;
+ ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
+ start_ssl_shutdown(transport);
+ pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
+ break;
+ }
+
+ if (send_buffs[0].cbBuffer != 0)
+ outbound_token = true;
+
+ ssl->state = RUNNING;
+ ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
+ ssl_log(transport, "server handshake successful %d max record size\n", max);
+ break;
+
+ case SEC_I_CONTEXT_EXPIRED:
+ // ended before we got going
+ default:
+ ssl_log(transport, "server handshake failed %d\n", (int) status);
+ ssl_failed(transport, 0);
+ break;
+ }
+
+ if (outbound_token) {
+ // Successful handshake step, requiring data to be sent to peer.
+ assert(ssl->network_out_pending == 0);
+ ssl->sc_out_count = send_buffs[0].cbBuffer;
+ // the token is the whole quantity to send
+ ssl->network_out_pending = ssl->sc_out_count;
+ ssl->network_outp = ssl->sc_outbuf;
+ ssl_log(transport, "server handshake token %d bytes\n", ssl->network_out_pending);
+ }
+
+ if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
+ !ssl->ssl_closed) {
+ // remaining data after the consumed TLS record(s)
+ ssl->extra_count = token_buffs[1].cbBuffer;
+ ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
+ }
+
+ ssl->decrypting = false;
+ rewind_sc_inbuf(ssl);
+}
+
+static void ssl_handshake(pn_transport_t* transport) {
+ if (transport->ssl->domain->mode == PN_SSL_MODE_CLIENT)
+ client_handshake(transport);
+ else {
+ server_handshake(transport);
+ }
+}
+
+static bool grow_inbuf2(pn_transport_t *transport, size_t minimum_size) {
+ pni_ssl_t *ssl = transport->ssl;
+ size_t old_capacity = pn_buffer_capacity(ssl->inbuf2);
+ size_t new_capacity = old_capacity ? old_capacity * 2 : 1024;
+
+ while (new_capacity < minimum_size)
+ new_capacity *= 2;
+
+ uint32_t max_frame = pn_transport_get_max_frame(transport);
+ if (max_frame != 0) {
+ if (old_capacity >= max_frame) {
+ // already big enough
+ ssl_log(transport, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
+ ssl_failed(transport, "TLS: transport maximimum frame size error");
+ return false;
+ }
+ }
+
+ size_t extra_bytes = new_capacity - pn_buffer_size(ssl->inbuf2);
+ int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
+ if (err) {
+ ssl_log(transport, "TLS memory allocation failed for %d bytes\n", max_frame);
+ ssl_failed(transport, "TLS memory allocation failed");
+ return false;
+ }
+ return true;
+}
+
+
+// Peer initiated a session end by sending us a shutdown alert (and we should politely
+// reciprocate), or else we are initiating the session end (and will not bother to wait
+// for the peer shutdown alert). Stop processing input immediately, and stop processing
+// output once this is sent.
+
+static void start_ssl_shutdown(pn_transport_t *transport)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ assert(ssl->network_out_pending == 0);
+ if (ssl->queued_shutdown)
+ return;
+ ssl->queued_shutdown = true;
+ ssl_log(transport, "Shutting down SSL connection...\n");
+
+ DWORD shutdown = SCHANNEL_SHUTDOWN;
+ SecBuffer shutBuff;
+ shutBuff.cbBuffer = sizeof(DWORD);
+ shutBuff.BufferType = SECBUFFER_TOKEN;
+ shutBuff.pvBuffer = &shutdown;
+ SecBufferDesc desc;
+ desc.ulVersion = SECBUFFER_VERSION;
+ desc.cBuffers = 1;
+ desc.pBuffers = &shutBuff;
+ ApplyControlToken(&ssl->ctxt_handle, &desc);
+
+ // Next handshake will generate the shudown alert token
+ ssl_handshake(transport);
+}
+
+static void rewind_sc_inbuf(pni_ssl_t *ssl)
+{
+ // Decrypted bytes have been drained or double buffered. Prepare for the next SSL Record.
+ assert(ssl->in_data_count == 0);
+ if (ssl->decrypting)
+ return;
+ ssl->decrypting = true;
+ if (ssl->inbuf_extra) {
+ // A previous read picked up more than one Record. Move it to the beginning.
+ memmove(ssl->sc_inbuf, ssl->inbuf_extra, ssl->extra_count);
+ ssl->sc_in_count = ssl->extra_count;
+ ssl->inbuf_extra = 0;
+ ssl->extra_count = 0;
+ } else {
+ ssl->sc_in_count = 0;
+ }
+}
+
+static void app_inbytes_add(pn_transport_t *transport)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ if (!ssl->app_inbytes.start) {
+ ssl->app_inbytes.start = ssl->in_data;
+ ssl->app_inbytes.size = ssl->in_data_count;
+ return;
+ }
+
+ if (ssl->double_buffered) {
+ if (pn_buffer_available(ssl->inbuf2) == 0) {
+ if (!grow_inbuf2(transport, 1024))
+ // could not add room
+ return;
+ }
+ size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+ pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+ ssl->in_data += count;
+ ssl->in_data_count -= count;
+ ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+ } else {
+ assert(ssl->app_inbytes.size == 0);
+ ssl->app_inbytes.start = ssl->in_data;
+ ssl->app_inbytes.size = ssl->in_data_count;
+ }
+}
+
+
+static void app_inbytes_progress(pn_transport_t *transport, size_t minimum)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ // Make more decrypted data available, if possible. Otherwise, move
+ // unread bytes to front of inbuf2 to make room for next bulk decryption.
+ // SSL may have chopped up data that app layer expects to be
+ // contiguous. Start, continue or stop double buffering here.
+ if (ssl->double_buffered) {
+ if (ssl->app_inbytes.size == 0) {
+ // no straggler bytes, optimistically stop for now
+ ssl->double_buffered = false;
+ pn_buffer_clear(ssl->inbuf2);
+ ssl->app_inbytes.start = ssl->in_data;
+ ssl->app_inbytes.size = ssl->in_data_count;
+ } else {
+ pn_bytes_t ib2 = pn_buffer_bytes(ssl->inbuf2);
+ assert(ssl->app_inbytes.size <= ib2.size);
+ size_t consumed = ib2.size - ssl->app_inbytes.size;
+ if (consumed > 0) {
+ memmove((void *)ib2.start, ib2.start + consumed, ssl->app_inbytes.size);
+ pn_buffer_trim(ssl->inbuf2, 0, consumed);
+ }
+ if (!pn_buffer_available(ssl->inbuf2)) {
+ if (!grow_inbuf2(transport, minimum))
+ // could not add room
+ return;
+ }
+ size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+ pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+ ssl->in_data += count;
+ ssl->in_data_count -= count;
+ ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+ }
+ } else {
+ if (ssl->app_inbytes.size) {
+ // start double buffering the left over bytes
+ ssl->double_buffered = true;
+ pn_buffer_clear(ssl->inbuf2);
+ if (!pn_buffer_available(ssl->inbuf2)) {
+ if (!grow_inbuf2(transport, minimum))
+ // could not add room
+ return;
+ }
+ size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+ pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+ ssl->in_data += count;
+ ssl->in_data_count -= count;
+ ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+ } else {
+ // already pointing at all available bytes until next decrypt
+ }
+ }
+ if (ssl->in_data_count == 0)
+ rewind_sc_inbuf(ssl);
+}
+
+
+static void app_inbytes_advance(pn_transport_t *transport, size_t consumed)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ if (consumed == 0) {
+ // more contiguous bytes required
+ app_inbytes_progress(transport, ssl->app_inbytes.size + 1);
+ return;
+ }
+ assert(consumed <= ssl->app_inbytes.size);
+ ssl->app_inbytes.start += consumed;
+ ssl->app_inbytes.size -= consumed;
+ if (!ssl->double_buffered) {
+ ssl->in_data += consumed;
+ ssl->in_data_count -= consumed;
+ }
+ if (ssl->app_inbytes.size == 0)
+ app_inbytes_progress(transport, 0);
+}
+
+static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t error)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ if (ssl->app_input_closed)
+ return;
+ if (ssl->state == RUNNING && !error) {
+ // Signal end of stream
+ ssl->app_input_closed = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, 0);
+ }
+ if (!ssl->app_input_closed)
+ ssl->app_input_closed = error ? error : PN_ERR;
+
+ if (ssl->app_output_closed) {
+ // both sides of app closed, and no more app output pending:
+ ssl->state = SHUTTING_DOWN;
+ if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
+ start_ssl_shutdown(transport);
+ }
+ }
+}
+
+
+// Read up to "available" bytes from the network, decrypt it and pass plaintext to application.
+
+static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ ssl_log( transport, "process_input_ssl( data size=%d )\n",available );
+ ssize_t consumed = 0;
+ ssize_t forwarded = 0;
+ bool new_app_input;
+
+ if (available == 0) {
+ // No more inbound network data
+ read_closed(transport, layer, 0);
+ return 0;
+ }
+
+ do {
+ if (ssl->sc_input_shutdown) {
+ // TLS protocol shutdown detected on input, so we are done.
+ read_closed(transport, layer, 0);
+ return PN_EOS;
+ }
+
+ // sc_inbuf should be ready for new or additional network encrypted bytes.
+ // i.e. no straggling decrypted bytes pending.
+ assert(ssl->in_data_count == 0 && ssl->decrypting);
+ new_app_input = false;
+ size_t count;
+
+ if (ssl->state != RUNNING) {
+ count = _pni_min(ssl->sc_in_size - ssl->sc_in_count, available);
+ } else {
+ // look for TLS record boundaries
+ if (ssl->sc_in_count < 5) {
+ ssl->sc_in_incomplete = true;
+ size_t hc = _pni_min(available, 5 - ssl->sc_in_count);
+ memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, hc);
+ ssl->sc_in_count += hc;
+ input_data += hc;
+ available -= hc;
+ consumed += hc;
+ if (ssl->sc_in_count < 5 || available == 0)
+ break;
+ }
+
+ // Top up sc_inbuf from network input_data hoping for a complete TLS Record
+ // We try to guess the length as an optimization, but let SChannel
+ // ultimately decide if there is spoofing going on.
+ unsigned char low = (unsigned char) ssl->sc_inbuf[4];
+ unsigned char high = (unsigned char) ssl->sc_inbuf[3];
+ size_t rec_len = high * 256 + low + 5;
+ if (rec_len < 5 || rec_len == ssl->sc_in_count || rec_len > ssl->sc_in_size)
+ rec_len = ssl->sc_in_size;
+
+ count = _pni_min(rec_len - ssl->sc_in_count, available);
+ }
+
+ if (count > 0) {
+ memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, count);
+ ssl->sc_in_count += count;
+ input_data += count;
+ available -= count;
+ consumed += count;
+ ssl->sc_in_incomplete = false;
+ }
+
+ // Try to decrypt another TLS Record.
+
+ if (ssl->sc_in_count > 0 && ssl->state <= SHUTTING_DOWN) {
+ if (ssl->state == NEGOTIATING) {
+ ssl_handshake(transport);
+ } else {
+ if (ssl_decrypt(transport)) {
+ // Ignore TLS Record with 0 length data (does not mean EOS)
+ if (ssl->in_data_size > 0) {
+ new_app_input = true;
+ app_inbytes_add(transport);
+ } else {
+ assert(ssl->decrypting == false);
+ rewind_sc_inbuf(ssl);
+ }
+ }
+ ssl_log(transport, "Next decryption, %d left over\n", available);
+ }
+ }
+
+ if (ssl->state == SHUTTING_DOWN) {
+ if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
+ start_ssl_shutdown(transport);
+ }
+ } else if (ssl->state == SSL_CLOSED) {
+ return PN_EOS;
+ }
+
+ // Consume or discard the decrypted bytes
+ if (new_app_input && (ssl->state == RUNNING || ssl->state == SHUTTING_DOWN)) {
+ // present app_inbytes to io_next only if it has new content
+ while (ssl->app_inbytes.size > 0) {
+ if (!ssl->app_input_closed) {
+ ssize_t count = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, ssl->app_inbytes.size);
+ if (count > 0) {
+ forwarded += count;
+ // advance() can increase app_inbytes.size if double buffered
+ app_inbytes_advance(transport, count);
+ ssl_log(transport, "Application consumed %d bytes from peer\n", (int) count);
+ } else if (count == 0) {
+ size_t old_size = ssl->app_inbytes.size;
+ app_inbytes_advance(transport, 0);
+ if (ssl->app_inbytes.size == old_size) {
+ break; // no additional contiguous decrypted data available, get more network data
+ }
+ } else {
+ // count < 0
+ ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)\n",
+ (int) count, (int)ssl->app_inbytes.size);
+ app_inbytes_advance(transport, ssl->app_inbytes.size); // discard
+ read_closed(transport, layer, count);
+ }
+ } else {
+ ssl_log(transport, "Input closed discard %d bytes\n",
+ (int)ssl->app_inbytes.size);
+ app_inbytes_advance(transport, ssl->app_inbytes.size); // discard
+ }
+ }
+ }
+ } while (available || (ssl->sc_in_count && !ssl->sc_in_incomplete));
+
+ if (ssl->state >= SHUTTING_DOWN) {
+ if (ssl->app_input_closed || ssl->sc_input_shutdown) {
+ // Next layer doesn't want more bytes, or it can't process without more data than it has seen so far
+ // but the ssl stream has ended
+ consumed = ssl->app_input_closed ? ssl->app_input_closed : PN_EOS;
+ if (transport->io_layers[layer]==&ssl_output_closed_layer) {
+ transport->io_layers[layer] = &ssl_closed_layer;
+ } else {
+ transport->io_layers[layer] = &ssl_input_closed_layer;
+ }
+ }
+ }
+ ssl_log(transport, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
+ return consumed;
+}
+
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
+{
+ pni_ssl_t *ssl = transport->ssl;
+ if (!ssl) return PN_EOS;
+ ssl_log( transport, "process_output_ssl( max_len=%d )\n",max_len );
+
+ ssize_t written = 0;
+ ssize_t total_app_bytes = 0;
+ bool work_pending;
+
+ if (ssl->state == CLIENT_HELLO) {
+ // output buffers eclusively for internal handshake use until negotiation complete
+ client_handshake_init(transport);
+ if (ssl->state == SSL_CLOSED)
+ return PN_EOS;
+ ssl->state = NEGOTIATING;
+ }
+
+ do {
+ work_pending = false;
+
+ if (ssl->network_out_pending > 0) {
+ size_t wcount = _pni_min(ssl->network_out_pending, max_len);
+ memmove(buffer, ssl->network_outp, wcount);
+ ssl->network_outp += wcount;
+ ssl->network_out_pending -= wcount;
+ buffer += wcount;
+ max_len -= wcount;
+ written += wcount;
+ }
+
+ if (ssl->network_out_pending == 0 && ssl->state == RUNNING && !ssl->app_output_closed) {
+ // refill the buffer with app data and encrypt it
+
+ char *app_data = ssl->sc_outbuf + ssl->sc_sizes.cbHeader;
+ char *app_outp = app_data;
+ size_t remaining = ssl->max_data_size;
+ ssize_t app_bytes;
+ do {
+ app_bytes = transport->io_layers[layer+1]->process_output(transport, layer+1, app_outp, remaining);
+ if (app_bytes > 0) {
+ app_outp += app_bytes;
+ remaining -= app_bytes;
+ ssl_log( transport, "Gathered %d bytes from app to send to peer\n", app_bytes );
+ } else {
+ if (app_bytes < 0) {
+ ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)\n",
+ (int) app_bytes, (int) ssl->network_out_pending);
+ ssl->app_output_closed = app_bytes;
+ if (ssl->app_input_closed)
+ ssl->state = SHUTTING_DOWN;
+ } else if (total_app_bytes == 0 && ssl->app_input_closed) {
+ // We've drained all the App layer can provide
+ ssl_log(transport, "Application layer blocked on input, closing\n");
+ ssl->state = SHUTTING_DOWN;
+ ssl->app_output_closed = PN_ERR;
+ }
+ }
+ } while (app_bytes > 0);
+ if (app_outp > app_data) {
+ work_pending = (max_len > 0);
+ ssl_encrypt(transport, app_data, app_outp - app_data);
+ }
+ }
+
+ if (ssl->network_out_pending == 0) {
+ if (ssl->state == SHUTTING_DOWN) {
+ if (!ssl->queued_shutdown) {
+ start_ssl_shutdown(transport);
+ work_pending = true;
+ } else {
+ ssl->state = SSL_CLOSED;
+ }
+ }
+ else if (ssl->state == NEGOTIATING && ssl->app_input_closed) {
+ ssl->app_output_closed = PN_EOS;
+ ssl->state = SSL_CLOSED;
+ }
+ }
+ } while (work_pending);
+
+ if (written == 0 && ssl->state == SSL_CLOSED) {
+ written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
+ if (transport->io_layers[layer]==&ssl_input_closed_layer) {
+ transport->io_layers[layer] = &ssl_closed_layer;
+ } else {
+ transport->io_layers[layer] = &ssl_output_closed_layer;
+ }
+ }
+ ssl_log(transport, "process_output_ssl() returning %d\n", (int) written);
+ return written;
+}
+
+
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
+{
+ return PN_EOS;
+}
+
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
+{
+ return PN_EOS;
+}
+
+// return # output bytes sitting in this layer
+static size_t buffered_output(pn_transport_t *transport)
+{
+ size_t count = 0;
+ pni_ssl_t *ssl = transport->ssl;
+ if (ssl) {
+ count += ssl->network_out_pending;
+ if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
+ count++;
+ }
+ return count;
+}
+
+static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error) {
+ *error = 0;
+ DWORD sys_store_type = 0;
+ HCERTSTORE cert_store = 0;
+
+ if (store_name) {
+ if (strncmp(store_name, "ss:", 3) == 0) {
+ store_name += 3;
+ sys_store_type = CERT_SYSTEM_STORE_CURRENT_USER;
+ }
+ else if (strncmp(store_name, "lmss:", 5) == 0) {
+ store_name += 5;
+ sys_store_type = CERT_SYSTEM_STORE_LOCAL_MACHINE;
+ }
+ }
+
+ if (sys_store_type) {
+ // Opening a system store, names are not case sensitive.
+ // Map confusing GUI name to actual registry store name.
+ if (!pn_strcasecmp(store_name, "personal")) store_name= "my";
+ cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, NULL,
+ CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG |
+ sys_store_type, store_name);
+ if (!cert_store) {
+ ssl_log_error_status(GetLastError(), "Failed to open system certificate store %s", store_name);
+ *error = -3;
+ return NULL;
+ }
+ } else {
+ // PKCS#12 file
+ HANDLE cert_file = CreateFile(store_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (INVALID_HANDLE_VALUE == cert_file) {
+ HRESULT status = GetLastError();
+ ssl_log_error_status(status, "Failed to open the file holding the private key: %s", store_name);
+ *error = -4;
+ return NULL;
+ }
+ DWORD nread = 0L;
+ const DWORD file_size = GetFileSize(cert_file, NULL);
+ char *buf = NULL;
+ if (INVALID_FILE_SIZE != file_size)
+ buf = (char *) malloc(file_size);
+ if (!buf || !ReadFile(cert_file, buf, file_size, &nread, NULL)
+ || file_size != nread) {
+ HRESULT status = GetLastError();
+ CloseHandle(cert_file);
+ free(buf);
+ ssl_log_error_status(status, "Reading the private key from file failed %s", store_name);
+ *error = -5;
+ return NULL;
+ }
+ CloseHandle(cert_file);
+
+ CRYPT_DATA_BLOB blob;
+ blob.cbData = nread;
+ blob.pbData = (BYTE *) buf;
+
+ wchar_t *pwUCS2 = NULL;
+ int pwlen = 0;
+ if (passwd) {
+ // convert passwd to null terminated wchar_t (Windows UCS2)
+ pwlen = strlen(passwd);
+ pwUCS2 = (wchar_t *) calloc(pwlen + 1, sizeof(wchar_t));
+ int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, passwd, pwlen, &pwUCS2[0], pwlen);
+ if (!nwc) {
+ ssl_log_error_status(GetLastError(), "Error converting password from UTF8");
+ free(buf);
+ free(pwUCS2);
+ *error = -6;
+ return NULL;
+ }
+ }
+
+ cert_store = PFXImportCertStore(&blob, pwUCS2, 0);
+ if (pwUCS2) {
+ SecureZeroMemory(pwUCS2, pwlen * sizeof(wchar_t));
+ free(pwUCS2);
+ }
+ if (cert_store == NULL) {
+ ssl_log_error_status(GetLastError(), "Failed to import the file based certificate store");
+ free(buf);
+ *error = -7;
+ return NULL;
+ }
+
+ free(buf);
+ }
+
+ return cert_store;
+}
+
+static bool store_contains(HCERTSTORE store, PCCERT_CONTEXT cert)
+{
+ DWORD find_type = CERT_FIND_EXISTING; // Require exact match
+ PCCERT_CONTEXT tcert = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0, find_type, cert, 0);
+ if (tcert) {
+ CertFreeCertificateContext(tcert);
+ return true;
+ }
+ return false;
+}
+
+/* Match the DNS name pattern from the peer certificate against our configured peer
+ hostname */
+static bool match_dns_pattern(const char *hostname, const char *pattern, int plen)
+{
+ int slen = (int) strlen(hostname);
+ if (memchr( pattern, '*', plen ) == NULL)
+ return (plen == slen &&
+ pn_strncasecmp( pattern, hostname, plen ) == 0);
+
+ /* dns wildcarded pattern - RFC2818 */
+ char plabel[64]; /* max label length < 63 - RFC1034 */
+ char slabel[64];
+
+ while (plen > 0 && slen > 0) {
+ const char *cptr;
+ int len;
+
+ cptr = (const char *) memchr( pattern, '.', plen );
+ len = (cptr) ? cptr - pattern : plen;
+ if (len > (int) sizeof(plabel) - 1) return false;
+ memcpy( plabel, pattern, len );
+ plabel[len] = 0;
+ if (cptr) ++len; // skip matching '.'
+ pattern += len;
+ plen -= len;
+
+ cptr = (const char *) memchr( hostname, '.', slen );
+ len = (cptr) ? cptr - hostname : slen;
+ if (len > (int) sizeof(slabel) - 1) return false;
+ memcpy( slabel, hostname, len );
+ slabel[len] = 0;
+ if (cptr) ++len; // skip matching '.'
+ hostname += len;
+ slen -= len;
+
+ char *star = strchr( plabel, '*' );
+ if (!star) {
+ if (pn_strcasecmp( plabel, slabel )) return false;
+ } else {
+ *star = '\0';
+ char *prefix = plabel;
+ int prefix_len = strlen(prefix);
+ char *suffix = star + 1;
+ int suffix_len = strlen(suffix);
+ if (prefix_len && pn_strncasecmp( prefix, slabel, prefix_len )) return false;
+ if (suffix_len && pn_strncasecmp( suffix,
+ slabel + (strlen(slabel) - suffix_len),
+ suffix_len )) return false;
+ }
+ }
+
+ return plen == slen;
+}
+
+// Caller must free the returned buffer
+static char* wide_to_utf8(LPWSTR wstring)
+{
+ int len = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, 0, 0, 0, 0);
+ if (!len) {
+ ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
+ return NULL;
+ }
+ char *p = (char *) malloc(len);
+ if (!p) return NULL;
+ if (WideCharToMultiByte(CP_UTF8, 0, wstring, -1, p, len, 0, 0))
+ return p;
+ ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
+ free (p);
+ return NULL;
+}
+
+static bool server_name_matches(const char *server_name, CERT_EXTENSION *alt_name_ext, PCCERT_CONTEXT cert)
+{
+ // As for openssl.c: alt names first, then CN
+ bool matched = false;
+
+ if (alt_name_ext) {
+ CERT_ALT_NAME_INFO* alt_name_info = NULL;
+ DWORD size = 0;
+ if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME2,
+ alt_name_ext->Value.pbData, alt_name_ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
+ 0, &alt_name_info, &size)) {
+ ssl_log_error_status(GetLastError(), "Alternative name match internal error");
+ return false;
+ }
+
+ int name_ct = alt_name_info->cAltEntry;
+ for (int i = 0; !matched && i < name_ct; ++i) {
+ if (alt_name_info->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) {
+ char *alt_name = wide_to_utf8(alt_name_info->rgAltEntry[i].pwszDNSName);
+ if (alt_name) {
+ matched = match_dns_pattern(server_name, (const char *) alt_name, strlen(alt_name));
+ free(alt_name);
+ }
+ }
+ }
+ LocalFree(&alt_name_info);
+ }
+
+ if (!matched) {
+ PCERT_INFO info = cert->pCertInfo;
+ DWORD len = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, 0, 0);
+ char *name = (char *) malloc(len);
+ if (name) {
+ int count = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, name, len);
+ if (count)
+ matched = match_dns_pattern(server_name, (const char *) name, strlen(name));
+ free(name);
+ }
+ }
+ return matched;
+}
+
+const char* pn_ssl_get_remote_subject_subfield(pn_ssl_t *ssl0, pn_ssl_cert_subject_subfield field)
+{
+ return NULL;
+}
+
+int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0,
+ char *fingerprint,
+ size_t fingerprint_length,
+ pn_ssl_hash_alg hash_alg)
+{
+ return -1;
+}
+
+static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing)
+{
+ // Free/release the following before return:
+ PCCERT_CONTEXT peer_cc = 0;
+ PCCERT_CONTEXT trust_anchor = 0;
+ PCCERT_CHAIN_CONTEXT chain_context = 0;
+ wchar_t *nameUCS2 = 0;
+
+ if (server_name && strlen(server_name) > 255) {
+ ssl_log_error("invalid server name: %s\n", server_name);
+ return WSAENAMETOOLONG;
+ }
+
+ // Get peer's certificate.
+ SECURITY_STATUS status;
+ status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
+ if (status != SEC_E_OK) {
+ ssl_log_error_status(status, "can't obtain remote peer certificate information");
+ return status;
+ }
+
+ // Build the peer's certificate chain. Multiple chains may be built but we
+ // care about rgpChain[0], which is the best. Custom root stores are not
+ // allowed until W8/server 2012: see CERT_CHAIN_ENGINE_CONFIG. For now, we
+ // manually override to taste.
+
+ // Chain verification functions give false reports for CRL if the trust anchor
+ // is not in the official root store. We ignore CRL completely if it doesn't
+ // apply to any untrusted certs in the chain, and defer to SChannel's veto
+ // otherwise. To rely on CRL, the CA must be in both the official system
+ // trusted root store and the Proton cred->trust_store. To defeat CRL, the
+ // most distal cert with CRL must be placed in the Proton cred->trust_store.
+ // Similarly, certificate usage checking is overly strict at times.
+
+ CERT_CHAIN_PARA desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.cbSize = sizeof(desc);
+
+ LPSTR usages[] = { szOID_PKIX_KP_SERVER_AUTH };
+ DWORD n_usages = sizeof(usages) / sizeof(LPSTR);
+ desc.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+ desc.RequestedUsage.Usage.cUsageIdentifier = n_usages;
+ desc.RequestedUsage.Usage.rgpszUsageIdentifier = usages;
+
+ if(!CertGetCertificateChain(0, peer_cc, 0, peer_cc->hCertStore, &desc,
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT |
+ CERT_CHAIN_CACHE_END_CERT,
+ 0, &chain_context)){
+ HRESULT st = GetLastError();
+ ssl_log_error_status(st, "Basic certificate chain check failed");
+ CertFreeCertificateContext(peer_cc);
+ return st;
+ }
+ if (chain_context->cChain < 1 || chain_context->rgpChain[0]->cElement < 1) {
+ ssl_log_error("empty chain with status %x %x\n", chain_context->TrustStatus.dwErrorStatus,
+ chain_context->TrustStatus.dwInfoStatus);
+ return SEC_E_CERT_UNKNOWN;
+ }
+
+ int chain_len = chain_context->rgpChain[0]->cElement;
+ PCCERT_CONTEXT leaf_cert = chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
+ PCCERT_CONTEXT trunk_cert = chain_context->rgpChain[0]->rgpElement[chain_len - 1]->pCertContext;
+ if (tracing)
+ // See doc for CERT_CHAIN_POLICY_STATUS for bit field error and info status values
+ ssl_log_error("status for complete chain: error bits %x info bits %x\n",
+ chain_context->TrustStatus.dwErrorStatus, chain_context->TrustStatus.dwInfoStatus);
+
+ // Supplement with checks against Proton's trusted_ca_db, custom revocation and usage.
+ HRESULT error = 0;
+ do {
+ // Do not return from this do loop. Set error = SEC_E_XXX and break.
+ bool revocable = false; // unless we see any untrusted certs that could be
+ for (int i = 0; i < chain_len; i++) {
+ CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[i];
+ PCCERT_CONTEXT cc = ce->pCertContext;
+ if (cc->pCertInfo->dwVersion != CERT_V3) {
+ if (tracing)
+ ssl_log_error("certificate chain element %d is not version 3\n", i);
+ error = SEC_E_CERT_WRONG_USAGE; // A fossil
+ break;
+ }
+
+ if (!trust_anchor && store_contains(root_store, cc))
+ trust_anchor = CertDuplicateCertificateContext(cc);
+
+ int n_ext = cc->pCertInfo->cExtension;
+ for (int ii = 0; ii < n_ext && !revocable && !trust_anchor; ii++) {
+ CERT_EXTENSION *p = &cc->pCertInfo->rgExtension[ii];
+ // rfc 5280 extensions for revocation
+ if (!strcmp(p->pszObjId, szOID_AUTHORITY_INFO_ACCESS) ||
+ !strcmp(p->pszObjId, szOID_CRL_DIST_POINTS) ||
+ !strcmp(p->pszObjId, szOID_FRESHEST_CRL)) {
+ revocable = true;
+ }
+ }
+
+ if (tracing) {
+ char name[512];
+ const char *is_anchor = (cc == trust_anchor) ? " trust anchor" : "";
+ if (!CertNameToStr(cc->dwCertEncodingType, &cc->pCertInfo->Subject,
+ CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG, name, sizeof(name)))
+ strcpy(name, "[too long]");
+ ssl_log_error("element %d (name: %s)%s error bits %x info bits %x\n", i, name, is_anchor,
+ ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
+ }
+ }
+ if (error)
+ break;
+
+ if (!trust_anchor) {
+ // We don't trust any of the certs in the chain, see if the last cert
+ // is issued by a Proton trusted CA.
+ DWORD flags = CERT_STORE_NO_ISSUER_FLAG || CERT_STORE_SIGNATURE_FLAG ||
+ CERT_STORE_TIME_VALIDITY_FLAG;
+ trust_anchor = CertGetIssuerCertificateFromStore(root_store, trunk_cert, 0, &flags);
+ if (trust_anchor) {
+ if (tracing) {
+ if (flags & CERT_STORE_SIGNATURE_FLAG)
+ ssl_log_error("root certificate signature failure\n");
+ if (flags & CERT_STORE_TIME_VALIDITY_FLAG)
+ ssl_log_error("root certificate time validity failure\n");
+ }
+ if (flags) {
+ CertFreeCertificateContext(trust_anchor);
+ trust_anchor = 0;
+ }
+ }
+ }
+ if (!trust_anchor) {
+ error = SEC_E_UNTRUSTED_ROOT;
+ break;
+ }
+
+ bool strict_usage = false;
+ CERT_EXTENSION *leaf_alt_names = 0;
+ if (leaf_cert != trust_anchor) {
+ int n_ext = leaf_cert->pCertInfo->cExtension;
+ for (int ii = 0; ii < n_ext; ii++) {
+ CERT_EXTENSION *p = &leaf_cert->pCertInfo->rgExtension[ii];
+ if (!strcmp(p->pszObjId, szOID_ENHANCED_KEY_USAGE))
+ strict_usage = true;
+ if (!strcmp(p->pszObjId, szOID_SUBJECT_ALT_NAME2))
+ if (p->Value.pbData)
+ leaf_alt_names = p;
+ }
+ }
+
+ if (server_name) {
+ int len = strlen(server_name);
+ nameUCS2 = (wchar_t *) calloc(len + 1, sizeof(wchar_t));
+ int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, server_name, len, &nameUCS2[0], len);
+ if (!nwc) {
+ error = GetLastError();
+ ssl_log_error_status(error, "Error converting server name from UTF8");
+ break;
+ }
+ }
+
+ // SSL-specific parameters (ExtraPolicy below)
+ SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_desc;
+ memset(&ssl_desc, 0, sizeof(ssl_desc));
+ ssl_desc.cbSize = sizeof(ssl_desc);
+ ssl_desc.pwszServerName = nameUCS2;
+ ssl_desc.dwAuthType = nameUCS2 ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT;
+ ssl_desc.fdwChecks = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
+ if (server_name)
+ ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
+ if (!revocable)
+ ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_REVOCATION;
+ if (!strict_usage)
+ ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_WRONG_USAGE;
+
+ // General certificate chain parameters
+ CERT_CHAIN_POLICY_PARA chain_desc;
+ memset(&chain_desc, 0, sizeof(chain_desc));
+ chain_desc.cbSize = sizeof(chain_desc);
+ chain_desc.dwFlags = CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG;
+ if (!revocable)
+ chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
+ if (!strict_usage)
+ chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
+ chain_desc.pvExtraPolicyPara = &ssl_desc;
+
+ CERT_CHAIN_POLICY_STATUS chain_status;
+ memset(&chain_status, 0, sizeof(chain_status));
+ chain_status.cbSize = sizeof(chain_status);
+
+ if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context,
+ &chain_desc, &chain_status)) {
+ error = GetLastError();
+ // Failure to complete the check, does not (in)validate the cert.
+ ssl_log_error_status(error, "Supplemental certificate chain check failed");
+ break;
+ }
+
+ if (chain_status.dwError) {
+ error = chain_status.dwError;
+ if (tracing) {
+ ssl_log_error_status(chain_status.dwError, "Certificate chain verification error");
+ if (chain_status.lChainIndex == 0 && chain_status.lElementIndex != -1) {
+ int idx = chain_status.lElementIndex;
+ CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[idx];
+ ssl_log_error(" chain failure at %d error/info: %x %x\n", idx,
+ ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
+ }
+ }
+ break;
+ }
+
+ if (server_name && ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME &&
+ !server_name_matches(server_name, leaf_alt_names, leaf_cert)) {
+ error = SEC_E_WRONG_PRINCIPAL;
+ break;
+ }
+ else if (ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME && !server_name) {
+ ssl_log_error("Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
+ error = SEC_E_WRONG_PRINCIPAL;
+ break;
+ }
+ } while (0);
+
+ if (tracing && !error)
+ ssl_log_error("peer certificate authenticated\n");
+
+ // Lots to clean up.
+ if (peer_cc)
+ CertFreeCertificateContext(peer_cc);
+ if (trust_anchor)
+ CertFreeCertificateContext(trust_anchor);
+ if (chain_context)
+ CertFreeCertificateChain(chain_context);
+ free(nameUCS2);
+ return error;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ssl/ssl_stub.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl_stub.c b/proton-c/src/ssl/ssl_stub.c
index c836b59..db2d983 100644
--- a/proton-c/src/ssl/ssl_stub.c
+++ b/proton-c/src/ssl/ssl_stub.c
@@ -22,7 +22,7 @@
#include <proton/ssl.h>
#include <proton/error.h>
#include <proton/transport.h>
-#include "engine/engine-internal.h"
+#include "core/engine-internal.h"
/** @file
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/tests/data.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/data.c b/proton-c/src/tests/data.c
index 8fb8217..10e7039 100644
--- a/proton-c/src/tests/data.c
+++ b/proton-c/src/tests/data.c
@@ -22,7 +22,7 @@
#undef NDEBUG /* Make sure that assert() is enabled even in a release build. */
#include <proton/codec.h>
-#include "../codec/data.h"
+#include "core/data.h"
#include <assert.h>
#include <stdio.h>
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/autodetect.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/autodetect.c b/proton-c/src/transport/autodetect.c
deleted file mode 100644
index 00f6d98..0000000
--- a/proton-c/src/transport/autodetect.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "autodetect.h"
-
-#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
-#define SSL_HEADER ("AMQP\x02\x01\x00\x00")
-#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
-
-#define SASL_HEADER_LEN 8
-
-/*
- * SSLv2 Client Hello format
- * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
- *
- * Bytes 0-1: RECORD-LENGTH
- * Byte 2: MSG-CLIENT-HELLO (1)
- * Byte 3: CLIENT-VERSION-MSB
- * Byte 4: CLIENT-VERSION-LSB
- *
- * Allowed versions:
- * 2.0 - SSLv2
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- *
- * The version sent in the Client-Hello is the latest version supported by
- * the client. NSS may send version 3.x in an SSLv2 header for
- * maximum compatibility.
- */
-/*
- * SSLv3/TLS Client Hello format
- * RFC 2246
- *
- * Byte 0: ContentType (handshake - 22)
- * Bytes 1-2: ProtocolVersion {major, minor}
- *
- * Allowed versions:
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- */
-/*
- * AMQP 1.0 Header
- *
- * Bytes 0-3: "AMQP"
- * Byte 4: 0==AMQP, 2==SSL, 3==SASL
- * Byte 5: 1
- * Bytes 6-7: 0
- */
-/*
- * AMQP Pre 1.0 Header
- *
- * Bytes 0-3: 'AMQP'
- * Byte 4: 1
- * Byte 5: 1
- * Byte 6: 0 (major version)
- * Byte 7: Minor version
- */
-pni_protocol_type_t pni_sniff_header(const char *buf, size_t len)
-{
- if (len < 3) return PNI_PROTOCOL_INSUFFICIENT;
- bool isSSL3Handshake = buf[0]==22 && // handshake
- buf[1]==3 && buf[2]<=3; // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
- if (isSSL3Handshake) return PNI_PROTOCOL_SSL;
-
- bool isFirst3AMQP = buf[0]=='A' && buf[1]=='M' && buf[2]=='Q';
- bool isFirst3SSL2CLientHello = buf[2]==1; // Client Hello
- if (!isFirst3AMQP && !isFirst3SSL2CLientHello) return PNI_PROTOCOL_UNKNOWN;
-
-
- if (len < 4) return PNI_PROTOCOL_INSUFFICIENT;
- bool isAMQP = isFirst3AMQP && buf[3]=='P';
- bool isFirst4SSL2ClientHello = isFirst3SSL2CLientHello && (buf[3]==2 || buf[3]==3);
- if (!isAMQP && !isFirst4SSL2ClientHello) return PNI_PROTOCOL_UNKNOWN;
-
- if (len < 5) return PNI_PROTOCOL_INSUFFICIENT;
- bool isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO
- ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
- (buf[3] == 2 && buf[4] == 0)); // SSL 2
- if (isSSL2Handshake) return PNI_PROTOCOL_SSL;
-
- bool isFirst5OldAMQP = isAMQP && buf[4]==1;
- bool isFirst5AMQP = isAMQP && (buf[4]==0 || buf[4]==2 || buf[4]==3);
- if (!isFirst5AMQP && !isFirst5OldAMQP) return PNI_PROTOCOL_UNKNOWN;
-
- if (len < 6) return PNI_PROTOCOL_INSUFFICIENT;
-
- // Both old and new versions of AMQP have 1 in byte 5
- if (buf[5]!=1) return PNI_PROTOCOL_UNKNOWN;
-
- // From here on it must be some sort of AMQP
- if (len < 8) return PNI_PROTOCOL_INSUFFICIENT;
- if (buf[6]==0 && buf[7]==0) {
- // AM<QP 1.0
- if (buf[4]==0) return PNI_PROTOCOL_AMQP1;
- if (buf[4]==2) return PNI_PROTOCOL_AMQP_SSL;
- if (buf[4]==3) return PNI_PROTOCOL_AMQP_SASL;
- }
- return PNI_PROTOCOL_AMQP_OTHER;
-}
-
-const char* pni_protocol_name(pni_protocol_type_t p)
-{
- static const char* names[] = {
- "Insufficient data to determine protocol",
- "Unknown protocol",
- "SSL/TLS connection",
- "AMQP TLS layer",
- "AMQP SASL layer",
- "AMQP 1.0 layer",
- "Pre standard AMQP connection"
- };
- return names[p];
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/autodetect.h
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/autodetect.h b/proton-c/src/transport/autodetect.h
deleted file mode 100644
index 12cb7d8..0000000
--- a/proton-c/src/transport/autodetect.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef PROTON_AUTODETECT_H
-#define PROTON_AUTODETECT_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/types.h"
-
-typedef enum {
- PNI_PROTOCOL_INSUFFICIENT,
- PNI_PROTOCOL_UNKNOWN,
- PNI_PROTOCOL_SSL,
- PNI_PROTOCOL_AMQP_SSL,
- PNI_PROTOCOL_AMQP_SASL,
- PNI_PROTOCOL_AMQP1,
- PNI_PROTOCOL_AMQP_OTHER
-} pni_protocol_type_t;
-
-pni_protocol_type_t pni_sniff_header(const char *data, size_t len);
-const char* pni_protocol_name(pni_protocol_type_t p);
-
-#endif
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[18/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/buffer.c
----------------------------------------------------------------------
diff --git a/proton-c/src/buffer.c b/proton-c/src/buffer.c
deleted file mode 100644
index c3015f4..0000000
--- a/proton-c/src/buffer.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/error.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "buffer.h"
-#include "util.h"
-
-struct pn_buffer_t {
- size_t capacity;
- size_t start;
- size_t size;
- char *bytes;
-};
-
-pn_buffer_t *pn_buffer(size_t capacity)
-{
- pn_buffer_t *buf = (pn_buffer_t *) malloc(sizeof(pn_buffer_t));
- if (buf != NULL) {
- buf->capacity = capacity;
- buf->start = 0;
- buf->size = 0;
- if (capacity > 0) {
- buf->bytes = (char *)malloc(capacity);
- if (buf->bytes == NULL) {
- free(buf);
- buf = NULL;
- }
- }
- else {
- buf->bytes = NULL;
- }
- }
- return buf;
-}
-
-void pn_buffer_free(pn_buffer_t *buf)
-{
- if (buf) {
- free(buf->bytes);
- free(buf);
- }
-}
-
-size_t pn_buffer_size(pn_buffer_t *buf)
-{
- return buf->size;
-}
-
-size_t pn_buffer_capacity(pn_buffer_t *buf)
-{
- return buf->capacity;
-}
-
-size_t pn_buffer_available(pn_buffer_t *buf)
-{
- return buf->capacity - buf->size;
-}
-
-static size_t pni_buffer_head(pn_buffer_t *buf)
-{
- return buf->start;
-}
-
-static size_t pni_buffer_tail(pn_buffer_t *buf)
-{
- size_t tail = buf->start + buf->size;
- if (tail >= buf->capacity)
- tail -= buf->capacity;
- return tail;
-}
-
-static bool pni_buffer_wrapped(pn_buffer_t *buf)
-{
- return buf->size && pni_buffer_head(buf) >= pni_buffer_tail(buf);
-}
-
-static size_t pni_buffer_tail_space(pn_buffer_t *buf)
-{
- if (pni_buffer_wrapped(buf)) {
- return pn_buffer_available(buf);
- } else {
- return buf->capacity - pni_buffer_tail(buf);
- }
-}
-
-static size_t pni_buffer_head_space(pn_buffer_t *buf)
-{
- if (pni_buffer_wrapped(buf)) {
- return pn_buffer_available(buf);
- } else {
- return pni_buffer_head(buf);
- }
-}
-
-static size_t pni_buffer_head_size(pn_buffer_t *buf)
-{
- if (pni_buffer_wrapped(buf)) {
- return buf->capacity - pni_buffer_head(buf);
- } else {
- return pni_buffer_tail(buf) - pni_buffer_head(buf);
- }
-}
-
-static size_t pni_buffer_tail_size(pn_buffer_t *buf)
-{
- if (pni_buffer_wrapped(buf)) {
- return pni_buffer_tail(buf);
- } else {
- return 0;
- }
-}
-
-int pn_buffer_ensure(pn_buffer_t *buf, size_t size)
-{
- size_t old_capacity = buf->capacity;
- size_t old_head = pni_buffer_head(buf);
- bool wrapped = pni_buffer_wrapped(buf);
-
- while (pn_buffer_available(buf) < size) {
- buf->capacity = 2*(buf->capacity ? buf->capacity : 16);
- }
-
- if (buf->capacity != old_capacity) {
- char* new_bytes = (char *)realloc(buf->bytes, buf->capacity);
- if (new_bytes) {
- buf->bytes = new_bytes;
-
- if (wrapped) {
- size_t n = old_capacity - old_head;
- memmove(buf->bytes + buf->capacity - n, buf->bytes + old_head, n);
- buf->start = buf->capacity - n;
- }
- }
- }
-
- return 0;
-}
-
-int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size)
-{
- int err = pn_buffer_ensure(buf, size);
- if (err) return err;
-
- size_t tail = pni_buffer_tail(buf);
- size_t tail_space = pni_buffer_tail_space(buf);
- size_t n = pn_min(tail_space, size);
-
- memmove(buf->bytes + tail, bytes, n);
- memmove(buf->bytes, bytes + n, size - n);
-
- buf->size += size;
-
- return 0;
-}
-
-int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size)
-{
- int err = pn_buffer_ensure(buf, size);
- if (err) return err;
-
- size_t head = pni_buffer_head(buf);
- size_t head_space = pni_buffer_head_space(buf);
- size_t n = pn_min(head_space, size);
-
- memmove(buf->bytes + head - n, bytes + size - n, n);
- memmove(buf->bytes + buf->capacity - (size - n), bytes, size - n);
-
- if (buf->start >= size) {
- buf->start -= size;
- } else {
- buf->start = buf->capacity - (size - buf->start);
- }
-
- buf->size += size;
-
- return 0;
-}
-
-static size_t pni_buffer_index(pn_buffer_t *buf, size_t index)
-{
- size_t result = buf->start + index;
- if (result >= buf->capacity) result -= buf->capacity;
- return result;
-}
-
-size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst)
-{
- size = pn_min(size, buf->size);
- size_t start = pni_buffer_index(buf, offset);
- size_t stop = pni_buffer_index(buf, offset + size);
-
- if (size == 0) return 0;
-
- size_t sz1;
- size_t sz2;
-
- if (start >= stop) {
- sz1 = buf->capacity - start;
- sz2 = stop;
- } else {
- sz1 = stop - start;
- sz2 = 0;
- }
-
- memmove(dst, buf->bytes + start, sz1);
- memmove(dst + sz1, buf->bytes, sz2);
-
- return sz1 + sz2;
-}
-
-int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right)
-{
- if (left + right > buf->size) return PN_ARG_ERR;
-
- buf->start += left;
- if (buf->start >= buf->capacity)
- buf->start -= buf->capacity;
-
- buf->size -= left + right;
-
- return 0;
-}
-
-void pn_buffer_clear(pn_buffer_t *buf)
-{
- buf->start = 0;
- buf->size = 0;
-}
-
-static void pn_buffer_rotate (pn_buffer_t *buf, size_t sz) {
- if (sz == 0) return;
-
- unsigned c = 0, v = 0;
- for (; c < buf->capacity; v++) {
- unsigned t = v, tp = v + sz;
- char tmp = buf->bytes[v];
- c++;
- while (tp != v) {
- buf->bytes[t] = buf->bytes[tp];
- t = tp;
- tp += sz;
- if (tp >= buf->capacity) tp -= buf->capacity;
- c++;
- }
- buf->bytes[t] = tmp;
- }
-}
-
-int pn_buffer_defrag(pn_buffer_t *buf)
-{
- pn_buffer_rotate(buf, buf->start);
- buf->start = 0;
- return 0;
-}
-
-pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf)
-{
- if (buf) {
- pn_buffer_defrag(buf);
- return pn_bytes(buf->size, buf->bytes);
- } else {
- return pn_bytes(0, NULL);
- }
-}
-
-pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf)
-{
- if (buf) {
- pn_buffer_defrag(buf);
- pn_rwbytes_t r = {buf->size, buf->bytes};
- return r;
- } else {
- pn_rwbytes_t r = {0, NULL};
- return r;
- }
-}
-
-int pn_buffer_print(pn_buffer_t *buf)
-{
- printf("pn_buffer(\"");
- pn_print_data(buf->bytes + pni_buffer_head(buf), pni_buffer_head_size(buf));
- pn_print_data(buf->bytes, pni_buffer_tail_size(buf));
- printf("\")");
- return 0;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/buffer.h
----------------------------------------------------------------------
diff --git a/proton-c/src/buffer.h b/proton-c/src/buffer.h
deleted file mode 100644
index da557ef..0000000
--- a/proton-c/src/buffer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef PROTON_BUFFER_H
-#define PROTON_BUFFER_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <proton/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct pn_buffer_t pn_buffer_t;
-
-pn_buffer_t *pn_buffer(size_t capacity);
-void pn_buffer_free(pn_buffer_t *buf);
-size_t pn_buffer_size(pn_buffer_t *buf);
-size_t pn_buffer_capacity(pn_buffer_t *buf);
-size_t pn_buffer_available(pn_buffer_t *buf);
-int pn_buffer_ensure(pn_buffer_t *buf, size_t size);
-int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size);
-int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size);
-size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst);
-int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right);
-void pn_buffer_clear(pn_buffer_t *buf);
-int pn_buffer_defrag(pn_buffer_t *buf);
-pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf);
-pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf);
-int pn_buffer_print(pn_buffer_t *buf);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* buffer.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/codec.c b/proton-c/src/codec/codec.c
deleted file mode 100644
index 2a4532c..0000000
--- a/proton-c/src/codec/codec.c
+++ /dev/null
@@ -1,2142 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/object.h>
-#include <proton/codec.h>
-#include <proton/error.h>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include "encodings.h"
-#define DEFINE_FIELDS
-#include "protocol.h"
-#include "platform.h"
-#include "platform_fmt.h"
-#include "util.h"
-#include "decoder.h"
-#include "encoder.h"
-#include "data.h"
-#include "log_private.h"
-
-const char *pn_type_name(pn_type_t type)
-{
- switch (type)
- {
- case PN_NULL: return "PN_NULL";
- case PN_BOOL: return "PN_BOOL";
- case PN_UBYTE: return "PN_UBYTE";
- case PN_BYTE: return "PN_BYTE";
- case PN_USHORT: return "PN_USHORT";
- case PN_SHORT: return "PN_SHORT";
- case PN_UINT: return "PN_UINT";
- case PN_INT: return "PN_INT";
- case PN_CHAR: return "PN_CHAR";
- case PN_ULONG: return "PN_ULONG";
- case PN_LONG: return "PN_LONG";
- case PN_TIMESTAMP: return "PN_TIMESTAMP";
- case PN_FLOAT: return "PN_FLOAT";
- case PN_DOUBLE: return "PN_DOUBLE";
- case PN_DECIMAL32: return "PN_DECIMAL32";
- case PN_DECIMAL64: return "PN_DECIMAL64";
- case PN_DECIMAL128: return "PN_DECIMAL128";
- case PN_UUID: return "PN_UUID";
- case PN_BINARY: return "PN_BINARY";
- case PN_STRING: return "PN_STRING";
- case PN_SYMBOL: return "PN_SYMBOL";
- case PN_DESCRIBED: return "PN_DESCRIBED";
- case PN_ARRAY: return "PN_ARRAY";
- case PN_LIST: return "PN_LIST";
- case PN_MAP: return "PN_MAP";
- default: break;
- }
-
- return "<UNKNOWN>";
-}
-
-static inline void pni_atom_init(pn_atom_t *atom, pn_type_t type)
-{
- memset(atom, 0, sizeof(pn_atom_t));
- atom->type = type;
-}
-
-// data
-
-static void pn_data_finalize(void *object)
-{
- pn_data_t *data = (pn_data_t *) object;
- free(data->nodes);
- pn_buffer_free(data->buf);
- pn_free(data->str);
- pn_error_free(data->error);
- pn_free(data->decoder);
- pn_free(data->encoder);
-}
-
-static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
-{
- if (!node) return NULL;
- if (node->atom.type != PN_DESCRIBED) return NULL;
-
- pni_node_t *descriptor = pn_data_node(data, node->down);
-
- if (!descriptor || descriptor->atom.type != PN_ULONG) {
- return NULL;
- }
-
- if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong <= FIELD_MAX) {
- const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN];
- return (f->name_index!=0) ? f : NULL;
- } else {
- return NULL;
- }
-}
-
-static int pni_node_index(pn_data_t *data, pni_node_t *node)
-{
- int count = 0;
- while (node) {
- node = pn_data_node(data, node->prev);
- count++;
- }
- return count - 1;
-}
-
-int pni_inspect_atom(pn_atom_t *atom, pn_string_t *str)
-{
- switch (atom->type) {
- case PN_NULL:
- return pn_string_addf(str, "null");
- case PN_BOOL:
- return pn_string_addf(str, atom->u.as_bool ? "true" : "false");
- case PN_UBYTE:
- return pn_string_addf(str, "%" PRIu8, atom->u.as_ubyte);
- case PN_BYTE:
- return pn_string_addf(str, "%" PRIi8, atom->u.as_byte);
- case PN_USHORT:
- return pn_string_addf(str, "%" PRIu16, atom->u.as_ushort);
- case PN_SHORT:
- return pn_string_addf(str, "%" PRIi16, atom->u.as_short);
- case PN_UINT:
- return pn_string_addf(str, "%" PRIu32, atom->u.as_uint);
- case PN_INT:
- return pn_string_addf(str, "%" PRIi32, atom->u.as_int);
- case PN_CHAR:
- return pn_string_addf(str, "%c", atom->u.as_char);
- case PN_ULONG:
- return pn_string_addf(str, "%" PRIu64, atom->u.as_ulong);
- case PN_LONG:
- return pn_string_addf(str, "%" PRIi64, atom->u.as_long);
- case PN_TIMESTAMP:
- return pn_string_addf(str, "%" PRIi64, atom->u.as_timestamp);
- case PN_FLOAT:
- return pn_string_addf(str, "%g", atom->u.as_float);
- case PN_DOUBLE:
- return pn_string_addf(str, "%g", atom->u.as_double);
- case PN_DECIMAL32:
- return pn_string_addf(str, "D32(%" PRIu32 ")", atom->u.as_decimal32);
- case PN_DECIMAL64:
- return pn_string_addf(str, "D64(%" PRIu64 ")", atom->u.as_decimal64);
- case PN_DECIMAL128:
- return pn_string_addf(str, "D128(%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
- "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
- "%02hhx%02hhx)",
- atom->u.as_decimal128.bytes[0],
- atom->u.as_decimal128.bytes[1],
- atom->u.as_decimal128.bytes[2],
- atom->u.as_decimal128.bytes[3],
- atom->u.as_decimal128.bytes[4],
- atom->u.as_decimal128.bytes[5],
- atom->u.as_decimal128.bytes[6],
- atom->u.as_decimal128.bytes[7],
- atom->u.as_decimal128.bytes[8],
- atom->u.as_decimal128.bytes[9],
- atom->u.as_decimal128.bytes[10],
- atom->u.as_decimal128.bytes[11],
- atom->u.as_decimal128.bytes[12],
- atom->u.as_decimal128.bytes[13],
- atom->u.as_decimal128.bytes[14],
- atom->u.as_decimal128.bytes[15]);
- case PN_UUID:
- return pn_string_addf(str, "UUID(%02hhx%02hhx%02hhx%02hhx-"
- "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
- "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx)",
- atom->u.as_uuid.bytes[0],
- atom->u.as_uuid.bytes[1],
- atom->u.as_uuid.bytes[2],
- atom->u.as_uuid.bytes[3],
- atom->u.as_uuid.bytes[4],
- atom->u.as_uuid.bytes[5],
- atom->u.as_uuid.bytes[6],
- atom->u.as_uuid.bytes[7],
- atom->u.as_uuid.bytes[8],
- atom->u.as_uuid.bytes[9],
- atom->u.as_uuid.bytes[10],
- atom->u.as_uuid.bytes[11],
- atom->u.as_uuid.bytes[12],
- atom->u.as_uuid.bytes[13],
- atom->u.as_uuid.bytes[14],
- atom->u.as_uuid.bytes[15]);
- case PN_BINARY:
- case PN_STRING:
- case PN_SYMBOL:
- {
- int err;
- const char *pfx;
- pn_bytes_t bin = atom->u.as_bytes;
- bool quote;
- switch (atom->type) {
- case PN_BINARY:
- pfx = "b";
- quote = true;
- break;
- case PN_STRING:
- pfx = "";
- quote = true;
- break;
- case PN_SYMBOL:
- pfx = ":";
- quote = false;
- for (unsigned i = 0; i < bin.size; i++) {
- if (!isalpha(bin.start[i])) {
- quote = true;
- break;
- }
- }
- break;
- default:
- assert(false);
- return PN_ERR;
- }
-
- if ((err = pn_string_addf(str, "%s", pfx))) return err;
- if (quote) if ((err = pn_string_addf(str, "\""))) return err;
- if ((err = pn_quote(str, bin.start, bin.size))) return err;
- if (quote) if ((err = pn_string_addf(str, "\""))) return err;
- return 0;
- }
- case PN_LIST:
- return pn_string_addf(str, "<list>");
- case PN_MAP:
- return pn_string_addf(str, "<map>");
- case PN_ARRAY:
- return pn_string_addf(str, "<array>");
- case PN_DESCRIBED:
- return pn_string_addf(str, "<described>");
- default:
- return pn_string_addf(str, "<undefined: %i>", atom->type);
- }
-}
-
-int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
-{
- pn_string_t *str = (pn_string_t *) ctx;
- pn_atom_t *atom = (pn_atom_t *) &node->atom;
-
- pni_node_t *parent = pn_data_node(data, node->parent);
- const pn_fields_t *fields = pni_node_fields(data, parent);
- pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
- const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
- int index = pni_node_index(data, node);
-
- int err;
-
- if (grandfields) {
- if (atom->type == PN_NULL) {
- return 0;
- }
- const char *name = (index < grandfields->field_count)
- ? FIELD_STRINGPOOL.STRING0+FIELD_FIELDS[grandfields->first_field_index+index]
- : NULL;
- if (name) {
- err = pn_string_addf(str, "%s=", name);
- if (err) return err;
- }
- }
-
- switch (atom->type) {
- case PN_DESCRIBED:
- return pn_string_addf(str, "@");
- case PN_ARRAY:
- // XXX: need to fix for described arrays
- return pn_string_addf(str, "@%s[", pn_type_name(node->type));
- case PN_LIST:
- return pn_string_addf(str, "[");
- case PN_MAP:
- return pn_string_addf(str, "{");
- default:
- if (fields && index == 0) {
- err = pn_string_addf(str, "%s", FIELD_STRINGPOOL.STRING0+FIELD_NAME[fields->name_index]);
- if (err) return err;
- err = pn_string_addf(str, "(");
- if (err) return err;
- err = pni_inspect_atom(atom, str);
- if (err) return err;
- return pn_string_addf(str, ")");
- } else {
- return pni_inspect_atom(atom, str);
- }
- }
-}
-
-pni_node_t *pni_next_nonnull(pn_data_t *data, pni_node_t *node)
-{
- while (node) {
- node = pn_data_node(data, node->next);
- if (node && node->atom.type != PN_NULL) {
- return node;
- }
- }
-
- return NULL;
-}
-
-int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node)
-{
- pn_string_t *str = (pn_string_t *) ctx;
- pni_node_t *parent = pn_data_node(data, node->parent);
- pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
- const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
- pni_node_t *next = pn_data_node(data, node->next);
- int err;
-
- switch (node->atom.type) {
- case PN_ARRAY:
- case PN_LIST:
- err = pn_string_addf(str, "]");
- if (err) return err;
- break;
- case PN_MAP:
- err = pn_string_addf(str, "}");
- if (err) return err;
- break;
- default:
- break;
- }
-
- if (!grandfields || node->atom.type != PN_NULL) {
- if (next) {
- int index = pni_node_index(data, node);
- if (parent && parent->atom.type == PN_MAP && (index % 2) == 0) {
- err = pn_string_addf(str, "=");
- } else if (parent && parent->atom.type == PN_DESCRIBED && index == 0) {
- err = pn_string_addf(str, " ");
- if (err) return err;
- } else {
- if (!grandfields || pni_next_nonnull(data, node)) {
- err = pn_string_addf(str, ", ");
- if (err) return err;
- }
- }
- }
- }
-
- return 0;
-}
-
-static int pn_data_inspect(void *obj, pn_string_t *dst)
-{
- pn_data_t *data = (pn_data_t *) obj;
-
- return pni_data_traverse(data, pni_inspect_enter, pni_inspect_exit, dst);
-}
-
-#define pn_data_initialize NULL
-#define pn_data_hashcode NULL
-#define pn_data_compare NULL
-
-pn_data_t *pn_data(size_t capacity)
-{
- static const pn_class_t clazz = PN_CLASS(pn_data);
- pn_data_t *data = (pn_data_t *) pn_class_new(&clazz, sizeof(pn_data_t));
- data->capacity = capacity;
- data->size = 0;
- data->nodes = capacity ? (pni_node_t *) malloc(capacity * sizeof(pni_node_t)) : NULL;
- data->buf = pn_buffer(64);
- data->parent = 0;
- data->current = 0;
- data->base_parent = 0;
- data->base_current = 0;
- data->decoder = pn_decoder();
- data->encoder = pn_encoder();
- data->error = pn_error();
- data->str = pn_string(NULL);
- return data;
-}
-
-void pn_data_free(pn_data_t *data)
-{
- pn_free(data);
-}
-
-int pn_data_errno(pn_data_t *data)
-{
- return pn_error_code(data->error);
-}
-
-pn_error_t *pn_data_error(pn_data_t *data)
-{
- return data->error;
-}
-
-size_t pn_data_size(pn_data_t *data)
-{
- return data ? data->size : 0;
-}
-
-void pn_data_clear(pn_data_t *data)
-{
- if (data) {
- data->size = 0;
- data->parent = 0;
- data->current = 0;
- data->base_parent = 0;
- data->base_current = 0;
- pn_buffer_clear(data->buf);
- }
-}
-
-static int pni_data_grow(pn_data_t *data)
-{
- size_t capacity = data->capacity ? data->capacity : 2;
- if (capacity >= PNI_NID_MAX) return PN_OUT_OF_MEMORY;
- else if (capacity < PNI_NID_MAX/2) capacity *= 2;
- else capacity = PNI_NID_MAX;
-
- pni_node_t *new_nodes = (pni_node_t *)realloc(data->nodes, capacity * sizeof(pni_node_t));
- if (new_nodes == NULL) return PN_OUT_OF_MEMORY;
- data->capacity = capacity;
- data->nodes = new_nodes;
- return 0;
-}
-
-static ssize_t pni_data_intern(pn_data_t *data, const char *start, size_t size)
-{
- size_t offset = pn_buffer_size(data->buf);
- int err = pn_buffer_append(data->buf, start, size);
- if (err) return err;
- err = pn_buffer_append(data->buf, "\0", 1);
- if (err) return err;
- return offset;
-}
-
-static pn_bytes_t *pni_data_bytes(pn_data_t *data, pni_node_t *node)
-{
- switch (node->atom.type) {
- case PN_BINARY:
- case PN_STRING:
- case PN_SYMBOL:
- return &node->atom.u.as_bytes;
- default: return NULL;
- }
-}
-
-static void pni_data_rebase(pn_data_t *data, char *base)
-{
- for (unsigned i = 0; i < data->size; i++) {
- pni_node_t *node = &data->nodes[i];
- if (node->data) {
- pn_bytes_t *bytes = pni_data_bytes(data, node);
- bytes->start = base + node->data_offset;
- }
- }
-}
-
-static int pni_data_intern_node(pn_data_t *data, pni_node_t *node)
-{
- pn_bytes_t *bytes = pni_data_bytes(data, node);
- if (!bytes) return 0;
- size_t oldcap = pn_buffer_capacity(data->buf);
- ssize_t offset = pni_data_intern(data, bytes->start, bytes->size);
- if (offset < 0) return offset;
- node->data = true;
- node->data_offset = offset;
- node->data_size = bytes->size;
- pn_rwbytes_t buf = pn_buffer_memory(data->buf);
- bytes->start = buf.start + offset;
-
- if (pn_buffer_capacity(data->buf) != oldcap) {
- pni_data_rebase(data, buf.start);
- }
-
- return 0;
-}
-
-int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap)
-{
- int err = 0;
- const char *begin = fmt;
- while (*fmt) {
- char code = *(fmt++);
- if (!code) return 0;
-
- switch (code) {
- case 'n':
- err = pn_data_put_null(data);
- break;
- case 'o':
- err = pn_data_put_bool(data, va_arg(ap, int));
- break;
- case 'B':
- err = pn_data_put_ubyte(data, va_arg(ap, unsigned int));
- break;
- case 'b':
- err = pn_data_put_byte(data, va_arg(ap, int));
- break;
- case 'H':
- err = pn_data_put_ushort(data, va_arg(ap, unsigned int));
- break;
- case 'h':
- err = pn_data_put_short(data, va_arg(ap, int));
- break;
- case 'I':
- err = pn_data_put_uint(data, va_arg(ap, uint32_t));
- break;
- case 'i':
- err = pn_data_put_int(data, va_arg(ap, uint32_t));
- break;
- case 'L':
- err = pn_data_put_ulong(data, va_arg(ap, uint64_t));
- break;
- case 'l':
- err = pn_data_put_long(data, va_arg(ap, int64_t));
- break;
- case 't':
- err = pn_data_put_timestamp(data, va_arg(ap, pn_timestamp_t));
- break;
- case 'f':
- err = pn_data_put_float(data, va_arg(ap, double));
- break;
- case 'd':
- err = pn_data_put_double(data, va_arg(ap, double));
- break;
- case 'z':
- {
- // For maximum portability, caller must pass these as two separate args, not a single struct
- size_t size = va_arg(ap, size_t);
- char *start = va_arg(ap, char *);
- if (start) {
- err = pn_data_put_binary(data, pn_bytes(size, start));
- } else {
- err = pn_data_put_null(data);
- }
- }
- break;
- case 'S':
- case 's':
- {
- char *start = va_arg(ap, char *);
- size_t size;
- if (start) {
- size = strlen(start);
- if (code == 'S') {
- err = pn_data_put_string(data, pn_bytes(size, start));
- } else {
- err = pn_data_put_symbol(data, pn_bytes(size, start));
- }
- } else {
- err = pn_data_put_null(data);
- }
- }
- break;
- case 'D':
- err = pn_data_put_described(data);
- pn_data_enter(data);
- break;
- case 'T':
- {
- pni_node_t *parent = pn_data_node(data, data->parent);
- if (parent->atom.type == PN_ARRAY) {
- parent->type = (pn_type_t) va_arg(ap, int);
- } else {
- return pn_error_format(data->error, PN_ERR, "naked type");
- }
- }
- break;
- case '@':
- {
- bool described;
- if (*(fmt + 1) == 'D') {
- fmt++;
- described = true;
- } else {
- described = false;
- }
- err = pn_data_put_array(data, described, (pn_type_t) 0);
- pn_data_enter(data);
- }
- break;
- case '[':
- if (fmt < (begin + 2) || *(fmt - 2) != 'T') {
- err = pn_data_put_list(data);
- if (err) return err;
- pn_data_enter(data);
- }
- break;
- case '{':
- err = pn_data_put_map(data);
- if (err) return err;
- pn_data_enter(data);
- break;
- case '}':
- case ']':
- if (!pn_data_exit(data))
- return pn_error_format(data->error, PN_ERR, "exit failed");
- break;
- case '?':
- if (!va_arg(ap, int)) {
- err = pn_data_put_null(data);
- if (err) return err;
- pn_data_enter(data);
- }
- break;
- case '*':
- {
- int count = va_arg(ap, int);
- void *ptr = va_arg(ap, void *);
-
- char c = *(fmt++);
-
- switch (c)
- {
- case 's':
- {
- char **sptr = (char **) ptr;
- for (int i = 0; i < count; i++)
- {
- char *sym = *(sptr++);
- err = pn_data_fill(data, "s", sym);
- if (err) return err;
- }
- }
- break;
- default:
- pn_logf("unrecognized * code: 0x%.2X '%c'", code, code);
- return PN_ARG_ERR;
- }
- }
- break;
- case 'C':
- {
- pn_data_t *src = va_arg(ap, pn_data_t *);
- if (src && pn_data_size(src) > 0) {
- err = pn_data_appendn(data, src, 1);
- if (err) return err;
- } else {
- err = pn_data_put_null(data);
- if (err) return err;
- }
- }
- break;
- default:
- pn_logf("unrecognized fill code: 0x%.2X '%c'", code, code);
- return PN_ARG_ERR;
- }
-
- if (err) return err;
-
- pni_node_t *parent = pn_data_node(data, data->parent);
- while (parent) {
- if (parent->atom.type == PN_DESCRIBED && parent->children == 2) {
- pn_data_exit(data);
- parent = pn_data_node(data, data->parent);
- } else if (parent->atom.type == PN_NULL && parent->children == 1) {
- pn_data_exit(data);
- pni_node_t *current = pn_data_node(data, data->current);
- current->down = 0;
- current->children = 0;
- parent = pn_data_node(data, data->parent);
- } else {
- break;
- }
- }
- }
-
- return 0;
-}
-
-
-int pn_data_fill(pn_data_t *data, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- int err = pn_data_vfill(data, fmt, ap);
- va_end(ap);
- return err;
-}
-
-static bool pn_scan_next(pn_data_t *data, pn_type_t *type, bool suspend)
-{
- if (suspend) return false;
- bool found = pn_data_next(data);
- if (found) {
- *type = pn_data_type(data);
- return true;
- } else {
- pni_node_t *parent = pn_data_node(data, data->parent);
- if (parent && parent->atom.type == PN_DESCRIBED) {
- pn_data_exit(data);
- return pn_scan_next(data, type, suspend);
- } else {
- *type = PN_INVALID;
- return false;
- }
- }
-}
-
-static pni_node_t *pni_data_peek(pn_data_t *data);
-
-int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap)
-{
- pn_data_rewind(data);
- bool *scanarg = NULL;
- bool at = false;
- int level = 0;
- int count_level = -1;
- int resume_count = 0;
-
- while (*fmt) {
- char code = *(fmt++);
-
- bool found = false;
- pn_type_t type;
-
- bool scanned = false;
- bool suspend = resume_count > 0;
-
- switch (code) {
- case 'n':
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_NULL) {
- scanned = true;
- } else {
- scanned = false;
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'o':
- {
- bool *value = va_arg(ap, bool *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_BOOL) {
- *value = pn_data_get_bool(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'B':
- {
- uint8_t *value = va_arg(ap, uint8_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_UBYTE) {
- *value = pn_data_get_ubyte(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'b':
- {
- int8_t *value = va_arg(ap, int8_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_BYTE) {
- *value = pn_data_get_byte(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'H':
- {
- uint16_t *value = va_arg(ap, uint16_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_USHORT) {
- *value = pn_data_get_ushort(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'h':
- {
- int16_t *value = va_arg(ap, int16_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_SHORT) {
- *value = pn_data_get_short(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'I':
- {
- uint32_t *value = va_arg(ap, uint32_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_UINT) {
- *value = pn_data_get_uint(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'i':
- {
- int32_t *value = va_arg(ap, int32_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_INT) {
- *value = pn_data_get_int(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'c':
- {
- pn_char_t *value = va_arg(ap, pn_char_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_CHAR) {
- *value = pn_data_get_char(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'L':
- {
- uint64_t *value = va_arg(ap, uint64_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_ULONG) {
- *value = pn_data_get_ulong(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'l':
- {
- int64_t *value = va_arg(ap, int64_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_LONG) {
- *value = pn_data_get_long(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 't':
- {
- pn_timestamp_t *value = va_arg(ap, pn_timestamp_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_TIMESTAMP) {
- *value = pn_data_get_timestamp(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'f':
- {
- float *value = va_arg(ap, float *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_FLOAT) {
- *value = pn_data_get_float(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'd':
- {
- double *value = va_arg(ap, double *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_DOUBLE) {
- *value = pn_data_get_double(data);
- scanned = true;
- } else {
- *value = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'z':
- {
- pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_BINARY) {
- *bytes = pn_data_get_binary(data);
- scanned = true;
- } else {
- bytes->start = 0;
- bytes->size = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'S':
- {
- pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_STRING) {
- *bytes = pn_data_get_string(data);
- scanned = true;
- } else {
- bytes->start = 0;
- bytes->size = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 's':
- {
- pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_SYMBOL) {
- *bytes = pn_data_get_symbol(data);
- scanned = true;
- } else {
- bytes->start = 0;
- bytes->size = 0;
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case 'D':
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_DESCRIBED) {
- pn_data_enter(data);
- scanned = true;
- } else {
- if (!suspend) {
- resume_count = 3;
- count_level = level;
- }
- scanned = false;
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case '@':
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_ARRAY) {
- pn_data_enter(data);
- scanned = true;
- at = true;
- } else {
- if (!suspend) {
- resume_count = 3;
- count_level = level;
- }
- scanned = false;
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- case '[':
- if (at) {
- scanned = true;
- at = false;
- } else {
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_LIST) {
- pn_data_enter(data);
- scanned = true;
- } else {
- if (!suspend) {
- resume_count = 1;
- count_level = level;
- }
- scanned = false;
- }
- }
- level++;
- break;
- case '{':
- found = pn_scan_next(data, &type, suspend);
- if (found && type == PN_MAP) {
- pn_data_enter(data);
- scanned = true;
- } else {
- if (resume_count) {
- resume_count = 1;
- count_level = level;
- }
- scanned = false;
- }
- level++;
- break;
- case ']':
- case '}':
- level--;
- if (!suspend && !pn_data_exit(data))
- return pn_error_format(data->error, PN_ERR, "exit failed");
- if (resume_count && level == count_level) resume_count--;
- break;
- case '.':
- found = pn_scan_next(data, &type, suspend);
- scanned = found;
- if (resume_count && level == count_level) resume_count--;
- break;
- case '?':
- if (!*fmt || *fmt == '?')
- return pn_error_format(data->error, PN_ARG_ERR, "codes must follow a ?");
- scanarg = va_arg(ap, bool *);
- break;
- case 'C':
- {
- pn_data_t *dst = va_arg(ap, pn_data_t *);
- if (!suspend) {
- size_t old = pn_data_size(dst);
- pni_node_t *next = pni_data_peek(data);
- if (next && next->atom.type != PN_NULL) {
- pn_data_narrow(data);
- int err = pn_data_appendn(dst, data, 1);
- pn_data_widen(data);
- if (err) return err;
- scanned = pn_data_size(dst) > old;
- } else {
- scanned = false;
- }
- pn_data_next(data);
- } else {
- scanned = false;
- }
- }
- if (resume_count && level == count_level) resume_count--;
- break;
- default:
- return pn_error_format(data->error, PN_ARG_ERR, "unrecognized scan code: 0x%.2X '%c'", code, code);
- }
-
- if (scanarg && code != '?') {
- *scanarg = scanned;
- scanarg = NULL;
- }
- }
-
- return 0;
-}
-
-int pn_data_scan(pn_data_t *data, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- int err = pn_data_vscan(data, fmt, ap);
- va_end(ap);
- return err;
-}
-
-static int pni_data_inspectify(pn_data_t *data)
-{
- int err = pn_string_set(data->str, "");
- if (err) return err;
- return pn_data_inspect(data, data->str);
-}
-
-int pn_data_print(pn_data_t *data)
-{
- int err = pni_data_inspectify(data);
- if (err) return err;
- printf("%s", pn_string_get(data->str));
- return 0;
-}
-
-int pn_data_format(pn_data_t *data, char *bytes, size_t *size)
-{
- int err = pni_data_inspectify(data);
- if (err) return err;
- if (pn_string_size(data->str) >= *size) {
- return PN_OVERFLOW;
- } else {
- pn_string_put(data->str, bytes);
- *size = pn_string_size(data->str);
- return 0;
- }
-}
-
-static size_t pni_data_id(pn_data_t *data, pni_node_t *node)
-{
- return node - data->nodes + 1;
-}
-
-static pni_node_t *pni_data_new(pn_data_t *data)
-{
- if ((data->capacity <= data->size) && (pni_data_grow(data) != 0)) return NULL;
- pni_node_t *node = pn_data_node(data, ++(data->size));
- node->next = 0;
- node->down = 0;
- node->children = 0;
- return node;
-}
-
-void pn_data_rewind(pn_data_t *data)
-{
- data->parent = data->base_parent;
- data->current = data->base_current;
-}
-
-static pni_node_t *pni_data_current(pn_data_t *data)
-{
- return pn_data_node(data, data->current);
-}
-
-void pn_data_narrow(pn_data_t *data)
-{
- data->base_parent = data->parent;
- data->base_current = data->current;
-}
-
-void pn_data_widen(pn_data_t *data)
-{
- data->base_parent = 0;
- data->base_current = 0;
-}
-
-pn_handle_t pn_data_point(pn_data_t *data)
-{
- if (data->current) {
- return (pn_handle_t)(uintptr_t)data->current;
- } else {
- return (pn_handle_t)(uintptr_t)-data->parent;
- }
-}
-
-bool pn_data_restore(pn_data_t *data, pn_handle_t point)
-{
- pn_shandle_t spoint = (pn_shandle_t) point;
- if (spoint <= 0 && ((size_t) (-spoint)) <= data->size) {
- data->parent = -((pn_shandle_t) point);
- data->current = 0;
- return true;
- } else if (spoint && spoint <= data->size) {
- data->current = spoint;
- pni_node_t *current = pni_data_current(data);
- data->parent = current->parent;
- return true;
- } else {
- return false;
- }
-}
-
-static pni_node_t *pni_data_peek(pn_data_t *data)
-{
- pni_node_t *current = pni_data_current(data);
- if (current) {
- return pn_data_node(data, current->next);
- }
-
- pni_node_t *parent = pn_data_node(data, data->parent);
- if (parent) {
- return pn_data_node(data, parent->down);
- }
-
- return NULL;
-}
-
-bool pn_data_next(pn_data_t *data)
-{
- pni_node_t *current = pni_data_current(data);
- pni_node_t *parent = pn_data_node(data, data->parent);
- size_t next;
-
- if (current) {
- next = current->next;
- } else if (parent && parent->down) {
- next = parent->down;
- } else if (!parent && data->size) {
- next = 1;
- } else {
- return false;
- }
-
- if (next) {
- data->current = next;
- return true;
- } else {
- return false;
- }
-}
-
-bool pn_data_prev(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->prev) {
- data->current = node->prev;
- return true;
- } else {
- return false;
- }
-}
-
-int pni_data_traverse(pn_data_t *data,
- int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
- int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
- void *ctx)
-{
- pni_node_t *node = data->size ? pn_data_node(data, 1) : NULL;
- while (node) {
- pni_node_t *parent = pn_data_node(data, node->parent);
-
- int err = enter(ctx, data, node);
- if (err) return err;
-
- size_t next = 0;
- if (node->down) {
- next = node->down;
- } else if (node->next) {
- err = exit(ctx, data, node);
- if (err) return err;
- next = node->next;
- } else {
- err = exit(ctx, data, node);
- if (err) return err;
- while (parent) {
- err = exit(ctx, data, parent);
- if (err) return err;
- if (parent->next) {
- next = parent->next;
- break;
- } else {
- parent = pn_data_node(data, parent->parent);
- }
- }
- }
-
- node = pn_data_node(data, next);
- }
-
- return 0;
-}
-
-pn_type_t pn_data_type(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node) {
- return node->atom.type;
- } else {
- return PN_INVALID;
- }
-}
-
-pn_type_t pni_data_parent_type(pn_data_t *data)
-{
- pni_node_t *node = pn_data_node(data, data->parent);
- if (node) {
- return node->atom.type;
- } else {
- return PN_INVALID;
- }
-}
-
-size_t pn_data_siblings(pn_data_t *data)
-{
- pni_node_t *node = pn_data_node(data, data->parent);
- if (node) {
- return node->children;
- } else {
- return 0;
- }
-}
-
-bool pn_data_enter(pn_data_t *data)
-{
- if (data->current) {
- data->parent = data->current;
- data->current = 0;
- return true;
- } else {
- return false;
- }
-}
-
-bool pn_data_exit(pn_data_t *data)
-{
- if (data->parent) {
- pni_node_t *parent = pn_data_node(data, data->parent);
- data->current = data->parent;
- data->parent = parent->parent;
- return true;
- } else {
- return false;
- }
-}
-
-bool pn_data_lookup(pn_data_t *data, const char *name)
-{
- while (pn_data_next(data)) {
- pn_type_t type = pn_data_type(data);
-
- switch (type) {
- case PN_STRING:
- case PN_SYMBOL:
- {
- pn_bytes_t bytes = pn_data_get_bytes(data);
- if (strlen(name) == bytes.size && !strncmp(name, bytes.start, bytes.size)) {
- return pn_data_next(data);
- }
- }
- break;
- default:
- break;
- }
-
- // skip the value
- pn_data_next(data);
- }
-
- return false;
-}
-
-void pn_data_dump(pn_data_t *data)
-{
- printf("{current=%" PN_ZI ", parent=%" PN_ZI "}\n", (size_t) data->current, (size_t) data->parent);
- for (unsigned i = 0; i < data->size; i++)
- {
- pni_node_t *node = &data->nodes[i];
- pn_string_set(data->str, "");
- pni_inspect_atom((pn_atom_t *) &node->atom, data->str);
- printf("Node %i: prev=%" PN_ZI ", next=%" PN_ZI ", parent=%" PN_ZI ", down=%" PN_ZI
- ", children=%" PN_ZI ", type=%s (%s)\n",
- i + 1, (size_t) node->prev,
- (size_t) node->next,
- (size_t) node->parent,
- (size_t) node->down,
- (size_t) node->children,
- pn_type_name(node->atom.type), pn_string_get(data->str));
- }
-}
-
-static pni_node_t *pni_data_add(pn_data_t *data)
-{
- pni_node_t *current = pni_data_current(data);
- pni_node_t *parent = pn_data_node(data, data->parent);
- pni_node_t *node;
-
- if (current) {
- if (current->next) {
- node = pn_data_node(data, current->next);
- } else {
- node = pni_data_new(data);
- if (!node) return NULL;
-
- // refresh the pointers in case we grew
- current = pni_data_current(data);
- parent = pn_data_node(data, data->parent);
- node->prev = data->current;
- current->next = pni_data_id(data, node);
- node->parent = data->parent;
- if (parent) {
- if (!parent->down) {
- parent->down = pni_data_id(data, node);
- }
- parent->children++;
- }
- }
- } else if (parent) {
- if (parent->down) {
- node = pn_data_node(data, parent->down);
- } else {
- node = pni_data_new(data);
- if (!node) return NULL;
-
- // refresh the pointers in case we grew
- parent = pn_data_node(data, data->parent);
- node->prev = 0;
- node->parent = data->parent;
- parent->down = pni_data_id(data, node);
- parent->children++;
- }
- } else if (data->size) {
- node = pn_data_node(data, 1);
- } else {
- node = pni_data_new(data);
- if (!node) return NULL;
-
- node->prev = 0;
- node->parent = 0;
- }
-
- node->down = 0;
- node->children = 0;
- node->data = false;
- node->data_offset = 0;
- node->data_size = 0;
- data->current = pni_data_id(data, node);
- return node;
-}
-
-ssize_t pn_data_encode(pn_data_t *data, char *bytes, size_t size)
-{
- return pn_encoder_encode(data->encoder, data, bytes, size);
-}
-
-ssize_t pn_data_encoded_size(pn_data_t *data)
-{
- return pn_encoder_size(data->encoder, data);
-}
-
-ssize_t pn_data_decode(pn_data_t *data, const char *bytes, size_t size)
-{
- return pn_decoder_decode(data->decoder, bytes, size, data);
-}
-
-int pn_data_put_list(pn_data_t *data)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_LIST;
- return 0;
-}
-
-int pn_data_put_map(pn_data_t *data)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_MAP;
- return 0;
-}
-
-int pn_data_put_array(pn_data_t *data, bool described, pn_type_t type)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_ARRAY;
- node->described = described;
- node->type = type;
- return 0;
-}
-
-void pni_data_set_array_type(pn_data_t *data, pn_type_t type)
-{
- pni_node_t *array = pni_data_current(data);
- if (array) array->type = type;
-}
-
-int pn_data_put_described(pn_data_t *data)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_DESCRIBED;
- return 0;
-}
-
-int pn_data_put_null(pn_data_t *data)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- pni_atom_init(&node->atom, PN_NULL);
- return 0;
-}
-
-int pn_data_put_bool(pn_data_t *data, bool b)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_BOOL;
- node->atom.u.as_bool = b;
- return 0;
-}
-
-int pn_data_put_ubyte(pn_data_t *data, uint8_t ub)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_UBYTE;
- node->atom.u.as_ubyte = ub;
- return 0;
-}
-
-int pn_data_put_byte(pn_data_t *data, int8_t b)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_BYTE;
- node->atom.u.as_byte = b;
- return 0;
-}
-
-int pn_data_put_ushort(pn_data_t *data, uint16_t us)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_USHORT;
- node->atom.u.as_ushort = us;
- return 0;
-}
-
-int pn_data_put_short(pn_data_t *data, int16_t s)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_SHORT;
- node->atom.u.as_short = s;
- return 0;
-}
-
-int pn_data_put_uint(pn_data_t *data, uint32_t ui)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_UINT;
- node->atom.u.as_uint = ui;
- return 0;
-}
-
-int pn_data_put_int(pn_data_t *data, int32_t i)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_INT;
- node->atom.u.as_int = i;
- return 0;
-}
-
-int pn_data_put_char(pn_data_t *data, pn_char_t c)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_CHAR;
- node->atom.u.as_char = c;
- return 0;
-}
-
-int pn_data_put_ulong(pn_data_t *data, uint64_t ul)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_ULONG;
- node->atom.u.as_ulong = ul;
- return 0;
-}
-
-int pn_data_put_long(pn_data_t *data, int64_t l)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_LONG;
- node->atom.u.as_long = l;
- return 0;
-}
-
-int pn_data_put_timestamp(pn_data_t *data, pn_timestamp_t t)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_TIMESTAMP;
- node->atom.u.as_timestamp = t;
- return 0;
-}
-
-int pn_data_put_float(pn_data_t *data, float f)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_FLOAT;
- node->atom.u.as_float = f;
- return 0;
-}
-
-int pn_data_put_double(pn_data_t *data, double d)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_DOUBLE;
- node->atom.u.as_double = d;
- return 0;
-}
-
-int pn_data_put_decimal32(pn_data_t *data, pn_decimal32_t d)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_DECIMAL32;
- node->atom.u.as_decimal32 = d;
- return 0;
-}
-
-int pn_data_put_decimal64(pn_data_t *data, pn_decimal64_t d)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_DECIMAL64;
- node->atom.u.as_decimal64 = d;
- return 0;
-}
-
-int pn_data_put_decimal128(pn_data_t *data, pn_decimal128_t d)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_DECIMAL128;
- memmove(node->atom.u.as_decimal128.bytes, d.bytes, 16);
- return 0;
-}
-
-int pn_data_put_uuid(pn_data_t *data, pn_uuid_t u)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_UUID;
- memmove(node->atom.u.as_uuid.bytes, u.bytes, 16);
- return 0;
-}
-
-int pn_data_put_binary(pn_data_t *data, pn_bytes_t bytes)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_BINARY;
- node->atom.u.as_bytes = bytes;
- return pni_data_intern_node(data, node);
-}
-
-int pn_data_put_string(pn_data_t *data, pn_bytes_t string)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_STRING;
- node->atom.u.as_bytes = string;
- return pni_data_intern_node(data, node);
-}
-
-int pn_data_put_symbol(pn_data_t *data, pn_bytes_t symbol)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom.type = PN_SYMBOL;
- node->atom.u.as_bytes = symbol;
- return pni_data_intern_node(data, node);
-}
-
-int pn_data_put_atom(pn_data_t *data, pn_atom_t atom)
-{
- pni_node_t *node = pni_data_add(data);
- if (node == NULL) return PN_OUT_OF_MEMORY;
- node->atom = atom;
- return pni_data_intern_node(data, node);
-}
-
-size_t pn_data_get_list(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_LIST) {
- return node->children;
- } else {
- return 0;
- }
-}
-
-size_t pn_data_get_map(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_MAP) {
- return node->children;
- } else {
- return 0;
- }
-}
-
-size_t pn_data_get_array(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_ARRAY) {
- if (node->described) {
- return node->children - 1;
- } else {
- return node->children;
- }
- } else {
- return 0;
- }
-}
-
-bool pn_data_is_array_described(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_ARRAY) {
- return node->described;
- } else {
- return false;
- }
-}
-
-pn_type_t pn_data_get_array_type(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_ARRAY) {
- return node->type;
- } else {
- return PN_INVALID;
- }
-}
-
-bool pn_data_is_described(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- return node && node->atom.type == PN_DESCRIBED;
-}
-
-bool pn_data_is_null(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- return node && node->atom.type == PN_NULL;
-}
-
-bool pn_data_get_bool(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_BOOL) {
- return node->atom.u.as_bool;
- } else {
- return false;
- }
-}
-
-uint8_t pn_data_get_ubyte(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_UBYTE) {
- return node->atom.u.as_ubyte;
- } else {
- return 0;
- }
-}
-
-int8_t pn_data_get_byte(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_BYTE) {
- return node->atom.u.as_byte;
- } else {
- return 0;
- }
-}
-
-uint16_t pn_data_get_ushort(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_USHORT) {
- return node->atom.u.as_ushort;
- } else {
- return 0;
- }
-}
-
-int16_t pn_data_get_short(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_SHORT) {
- return node->atom.u.as_short;
- } else {
- return 0;
- }
-}
-
-uint32_t pn_data_get_uint(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_UINT) {
- return node->atom.u.as_uint;
- } else {
- return 0;
- }
-}
-
-int32_t pn_data_get_int(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_INT) {
- return node->atom.u.as_int;
- } else {
- return 0;
- }
-}
-
-pn_char_t pn_data_get_char(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_CHAR) {
- return node->atom.u.as_char;
- } else {
- return 0;
- }
-}
-
-uint64_t pn_data_get_ulong(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_ULONG) {
- return node->atom.u.as_ulong;
- } else {
- return 0;
- }
-}
-
-int64_t pn_data_get_long(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_LONG) {
- return node->atom.u.as_long;
- } else {
- return 0;
- }
-}
-
-pn_timestamp_t pn_data_get_timestamp(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_TIMESTAMP) {
- return node->atom.u.as_timestamp;
- } else {
- return 0;
- }
-}
-
-float pn_data_get_float(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_FLOAT) {
- return node->atom.u.as_float;
- } else {
- return 0;
- }
-}
-
-double pn_data_get_double(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_DOUBLE) {
- return node->atom.u.as_double;
- } else {
- return 0;
- }
-}
-
-pn_decimal32_t pn_data_get_decimal32(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_DECIMAL32) {
- return node->atom.u.as_decimal32;
- } else {
- return 0;
- }
-}
-
-pn_decimal64_t pn_data_get_decimal64(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_DECIMAL64) {
- return node->atom.u.as_decimal64;
- } else {
- return 0;
- }
-}
-
-pn_decimal128_t pn_data_get_decimal128(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_DECIMAL128) {
- return node->atom.u.as_decimal128;
- } else {
- pn_decimal128_t t = {{0}};
- return t;
- }
-}
-
-pn_uuid_t pn_data_get_uuid(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_UUID) {
- return node->atom.u.as_uuid;
- } else {
- pn_uuid_t t = {{0}};
- return t;
- }
-}
-
-pn_bytes_t pn_data_get_binary(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_BINARY) {
- return node->atom.u.as_bytes;
- } else {
- pn_bytes_t t = {0};
- return t;
- }
-}
-
-pn_bytes_t pn_data_get_string(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_STRING) {
- return node->atom.u.as_bytes;
- } else {
- pn_bytes_t t = {0};
- return t;
- }
-}
-
-pn_bytes_t pn_data_get_symbol(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && node->atom.type == PN_SYMBOL) {
- return node->atom.u.as_bytes;
- } else {
- pn_bytes_t t = {0};
- return t;
- }
-}
-
-pn_bytes_t pn_data_get_bytes(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node && (node->atom.type == PN_BINARY ||
- node->atom.type == PN_STRING ||
- node->atom.type == PN_SYMBOL)) {
- return node->atom.u.as_bytes;
- } else {
- pn_bytes_t t = {0};
- return t;
- }
-}
-
-pn_atom_t pn_data_get_atom(pn_data_t *data)
-{
- pni_node_t *node = pni_data_current(data);
- if (node) {
- return *((pn_atom_t *) &node->atom);
- } else {
- pn_atom_t t = {PN_NULL, {0,}};
- return t;
- }
-}
-
-int pn_data_copy(pn_data_t *data, pn_data_t *src)
-{
- pn_data_clear(data);
- int err = pn_data_append(data, src);
- pn_data_rewind(data);
- return err;
-}
-
-int pn_data_append(pn_data_t *data, pn_data_t *src)
-{
- return pn_data_appendn(data, src, -1);
-}
-
-int pn_data_appendn(pn_data_t *data, pn_data_t *src, int limit)
-{
- int err = 0;
- int level = 0, count = 0;
- bool stop = false;
- pn_handle_t point = pn_data_point(src);
- pn_data_rewind(src);
-
- while (true) {
- while (!pn_data_next(src)) {
- if (level > 0) {
- pn_data_exit(data);
- pn_data_exit(src);
- level--;
- continue;
- }
-
- if (!pn_data_next(src)) {
- stop = true;
- }
- break;
- }
-
- if (stop) break;
-
- if (level == 0 && count == limit)
- break;
-
- pn_type_t type = pn_data_type(src);
- switch (type) {
- case PN_NULL:
- err = pn_data_put_null(data);
- if (level == 0) count++;
- break;
- case PN_BOOL:
- err = pn_data_put_bool(data, pn_data_get_bool(src));
- if (level == 0) count++;
- break;
- case PN_UBYTE:
- err = pn_data_put_ubyte(data, pn_data_get_ubyte(src));
- if (level == 0) count++;
- break;
- case PN_BYTE:
- err = pn_data_put_byte(data, pn_data_get_byte(src));
- if (level == 0) count++;
- break;
- case PN_USHORT:
- err = pn_data_put_ushort(data, pn_data_get_ushort(src));
- if (level == 0) count++;
- break;
- case PN_SHORT:
- err = pn_data_put_short(data, pn_data_get_short(src));
- if (level == 0) count++;
- break;
- case PN_UINT:
- err = pn_data_put_uint(data, pn_data_get_uint(src));
- if (level == 0) count++;
- break;
- case PN_INT:
- err = pn_data_put_int(data, pn_data_get_int(src));
- if (level == 0) count++;
- break;
- case PN_CHAR:
- err = pn_data_put_char(data, pn_data_get_char(src));
- if (level == 0) count++;
- break;
- case PN_ULONG:
- err = pn_data_put_ulong(data, pn_data_get_ulong(src));
- if (level == 0) count++;
- break;
- case PN_LONG:
- err = pn_data_put_long(data, pn_data_get_long(src));
- if (level == 0) count++;
- break;
- case PN_TIMESTAMP:
- err = pn_data_put_timestamp(data, pn_data_get_timestamp(src));
- if (level == 0) count++;
- break;
- case PN_FLOAT:
- err = pn_data_put_float(data, pn_data_get_float(src));
- if (level == 0) count++;
- break;
- case PN_DOUBLE:
- err = pn_data_put_double(data, pn_data_get_double(src));
- if (level == 0) count++;
- break;
- case PN_DECIMAL32:
- err = pn_data_put_decimal32(data, pn_data_get_decimal32(src));
- if (level == 0) count++;
- break;
- case PN_DECIMAL64:
- err = pn_data_put_decimal64(data, pn_data_get_decimal64(src));
- if (level == 0) count++;
- break;
- case PN_DECIMAL128:
- err = pn_data_put_decimal128(data, pn_data_get_decimal128(src));
- if (level == 0) count++;
- break;
- case PN_UUID:
- err = pn_data_put_uuid(data, pn_data_get_uuid(src));
- if (level == 0) count++;
- break;
- case PN_BINARY:
- err = pn_data_put_binary(data, pn_data_get_binary(src));
- if (level == 0) count++;
- break;
- case PN_STRING:
- err = pn_data_put_string(data, pn_data_get_string(src));
- if (level == 0) count++;
- break;
- case PN_SYMBOL:
- err = pn_data_put_symbol(data, pn_data_get_symbol(src));
- if (level == 0) count++;
- break;
- case PN_DESCRIBED:
- err = pn_data_put_described(data);
- if (level == 0) count++;
- if (err) { pn_data_restore(src, point); return err; }
- pn_data_enter(data);
- pn_data_enter(src);
- level++;
- break;
- case PN_ARRAY:
- err = pn_data_put_array(data, pn_data_is_array_described(src),
- pn_data_get_array_type(src));
- if (level == 0) count++;
- if (err) { pn_data_restore(src, point); return err; }
- pn_data_enter(data);
- pn_data_enter(src);
- level++;
- break;
- case PN_LIST:
- err = pn_data_put_list(data);
- if (level == 0) count++;
- if (err) { pn_data_restore(src, point); return err; }
- pn_data_enter(data);
- pn_data_enter(src);
- level++;
- break;
- case PN_MAP:
- err = pn_data_put_map(data);
- if (level == 0) count++;
- if (err) { pn_data_restore(src, point); return err; }
- pn_data_enter(data);
- pn_data_enter(src);
- level++;
- break;
- default:
- break;
- }
-
- if (err) { pn_data_restore(src, point); return err; }
- }
-
- pn_data_restore(src, point);
-
- return 0;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/data.h b/proton-c/src/codec/data.h
deleted file mode 100644
index 94dc7d6..0000000
--- a/proton-c/src/codec/data.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef _PROTON_DATA_H
-#define _PROTON_DATA_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/codec.h>
-#include "buffer.h"
-#include "decoder.h"
-#include "encoder.h"
-
-typedef uint16_t pni_nid_t;
-#define PNI_NID_MAX ((pni_nid_t)-1)
-
-typedef struct {
- char *start;
- size_t data_offset;
- size_t data_size;
- pn_atom_t atom;
- pn_type_t type;
- pni_nid_t next;
- pni_nid_t prev;
- pni_nid_t down;
- pni_nid_t parent;
- pni_nid_t children;
- // for arrays
- bool described;
- bool data;
- bool small;
-} pni_node_t;
-
-struct pn_data_t {
- pni_node_t *nodes;
- pn_buffer_t *buf;
- pn_decoder_t *decoder;
- pn_encoder_t *encoder;
- pn_error_t *error;
- pn_string_t *str;
- pni_nid_t capacity;
- pni_nid_t size;
- pni_nid_t parent;
- pni_nid_t current;
- pni_nid_t base_parent;
- pni_nid_t base_current;
-};
-
-static inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd)
-{
- return nd ? (data->nodes + nd - 1) : NULL;
-}
-
-int pni_data_traverse(pn_data_t *data,
- int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
- int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
- void *ctx);
-
-#endif /* data.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/decoder.c b/proton-c/src/codec/decoder.c
deleted file mode 100644
index b0c8d79..0000000
--- a/proton-c/src/codec/decoder.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/error.h>
-#include <proton/object.h>
-#include <proton/codec.h>
-#include "encodings.h"
-#include "decoder.h"
-
-#include <string.h>
-
-struct pn_decoder_t {
- const char *input;
- size_t size;
- const char *position;
- pn_error_t *error;
-};
-
-static void pn_decoder_initialize(void *obj)
-{
- pn_decoder_t *decoder = (pn_decoder_t *) obj;
- decoder->input = NULL;
- decoder->size = 0;
- decoder->position = NULL;
- decoder->error = pn_error();
-}
-
-static void pn_decoder_finalize(void *obj) {
- pn_decoder_t *decoder = (pn_decoder_t *) obj;
- pn_error_free(decoder->error);
-}
-
-#define pn_decoder_hashcode NULL
-#define pn_decoder_compare NULL
-#define pn_decoder_inspect NULL
-
-pn_decoder_t *pn_decoder()
-{
- static const pn_class_t clazz = PN_CLASS(pn_decoder);
- return (pn_decoder_t *) pn_class_new(&clazz, sizeof(pn_decoder_t));
-}
-
-static inline uint8_t pn_decoder_readf8(pn_decoder_t *decoder)
-{
- uint8_t r = decoder->position[0];
- decoder->position++;
- return r;
-}
-
-static inline uint16_t pn_decoder_readf16(pn_decoder_t *decoder)
-{
- uint16_t a = (uint8_t) decoder->position[0];
- uint16_t b = (uint8_t) decoder->position[1];
- uint16_t r = a << 8
- | b;
- decoder->position += 2;
- return r;
-}
-
-static inline uint32_t pn_decoder_readf32(pn_decoder_t *decoder)
-{
- uint32_t a = (uint8_t) decoder->position[0];
- uint32_t b = (uint8_t) decoder->position[1];
- uint32_t c = (uint8_t) decoder->position[2];
- uint32_t d = (uint8_t) decoder->position[3];
- uint32_t r = a << 24
- | b << 16
- | c << 8
- | d;
- decoder->position += 4;
- return r;
-}
-
-static inline uint64_t pn_decoder_readf64(pn_decoder_t *decoder)
-{
- uint64_t a = pn_decoder_readf32(decoder);
- uint64_t b = pn_decoder_readf32(decoder);
- return a << 32 | b;
-}
-
-static inline void pn_decoder_readf128(pn_decoder_t *decoder, void *dst)
-{
- memmove(dst, decoder->position, 16);
- decoder->position += 16;
-}
-
-static inline size_t pn_decoder_remaining(pn_decoder_t *decoder)
-{
- return decoder->input + decoder->size - decoder->position;
-}
-
-typedef union {
- uint32_t i;
- uint32_t a[2];
- uint64_t l;
- float f;
- double d;
-} conv_t;
-
-static inline pn_type_t pn_code2type(uint8_t code)
-{
- switch (code)
- {
- case PNE_DESCRIPTOR:
- return (pn_type_t) PN_ARG_ERR;
- case PNE_NULL:
- return PN_NULL;
- case PNE_TRUE:
- case PNE_FALSE:
- case PNE_BOOLEAN:
- return PN_BOOL;
- case PNE_UBYTE:
- return PN_UBYTE;
- case PNE_BYTE:
- return PN_BYTE;
- case PNE_USHORT:
- return PN_USHORT;
- case PNE_SHORT:
- return PN_SHORT;
- case PNE_UINT0:
- case PNE_SMALLUINT:
- case PNE_UINT:
- return PN_UINT;
- case PNE_SMALLINT:
- case PNE_INT:
- return PN_INT;
- case PNE_UTF32:
- return PN_CHAR;
- case PNE_FLOAT:
- return PN_FLOAT;
- case PNE_LONG:
- case PNE_SMALLLONG:
- return PN_LONG;
- case PNE_MS64:
- return PN_TIMESTAMP;
- case PNE_DOUBLE:
- return PN_DOUBLE;
- case PNE_DECIMAL32:
- return PN_DECIMAL32;
- case PNE_DECIMAL64:
- return PN_DECIMAL64;
- case PNE_DECIMAL128:
- return PN_DECIMAL128;
- case PNE_UUID:
- return PN_UUID;
- case PNE_ULONG0:
- case PNE_SMALLULONG:
- case PNE_ULONG:
- return PN_ULONG;
- case PNE_VBIN8:
- case PNE_VBIN32:
- return PN_BINARY;
- case PNE_STR8_UTF8:
- case PNE_STR32_UTF8:
- return PN_STRING;
- case PNE_SYM8:
- case PNE_SYM32:
- return PN_SYMBOL;
- case PNE_LIST0:
- case PNE_LIST8:
- case PNE_LIST32:
- return PN_LIST;
- case PNE_ARRAY8:
- case PNE_ARRAY32:
- return PN_ARRAY;
- case PNE_MAP8:
- case PNE_MAP32:
- return PN_MAP;
- default:
- return (pn_type_t) PN_ARG_ERR;
- }
-}
-
-static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code);
-static int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data);
-void pni_data_set_array_type(pn_data_t *data, pn_type_t type);
-
-static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code)
-{
- int err;
- conv_t conv;
- pn_decimal128_t dec128;
- pn_uuid_t uuid;
- size_t size;
- size_t count;
-
- switch (code)
- {
- case PNE_NULL:
- err = pn_data_put_null(data);
- break;
- case PNE_TRUE:
- err = pn_data_put_bool(data, true);
- break;
- case PNE_FALSE:
- err = pn_data_put_bool(data, false);
- break;
- case PNE_BOOLEAN:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- err = pn_data_put_bool(data, pn_decoder_readf8(decoder) != 0);
- break;
- case PNE_UBYTE:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- err = pn_data_put_ubyte(data, pn_decoder_readf8(decoder));
- break;
- case PNE_BYTE:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- err = pn_data_put_byte(data, pn_decoder_readf8(decoder));
- break;
- case PNE_USHORT:
- if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
- err = pn_data_put_ushort(data, pn_decoder_readf16(decoder));
- break;
- case PNE_SHORT:
- if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
- err = pn_data_put_short(data, pn_decoder_readf16(decoder));
- break;
- case PNE_UINT:
- if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
- err = pn_data_put_uint(data, pn_decoder_readf32(decoder));
- break;
- case PNE_UINT0:
- err = pn_data_put_uint(data, 0);
- break;
- case PNE_SMALLUINT:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- err = pn_data_put_uint(data, pn_decoder_readf8(decoder));
- break;
- case PNE_SMALLINT:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- err = pn_data_put_int(data, (int8_t)pn_decoder_readf8(decoder));
- break;
- case PNE_INT:
- if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
- err = pn_data_put_int(data, pn_decoder_readf32(decoder));
- break;
- case PNE_UTF32:
- if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
- err = pn_data_put_char(data, pn_decoder_readf32(decoder));
- break;
- case PNE_FLOAT:
- if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
- // XXX: this assumes the platform uses IEEE floats
- conv.i = pn_decoder_readf32(decoder);
- err = pn_data_put_float(data, conv.f);
- break;
- case PNE_DECIMAL32:
- if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
- err = pn_data_put_decimal32(data, pn_decoder_readf32(decoder));
- break;
- case PNE_ULONG:
- if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
- err = pn_data_put_ulong(data, pn_decoder_readf64(decoder));
- break;
- case PNE_LONG:
- if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
- err = pn_data_put_long(data, pn_decoder_readf64(decoder));
- break;
- case PNE_MS64:
- if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
- err = pn_data_put_timestamp(data, pn_decoder_readf64(decoder));
- break;
- case PNE_DOUBLE:
- // XXX: this assumes the platform uses IEEE floats
- if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
- conv.l = pn_decoder_readf64(decoder);
- err = pn_data_put_double(data, conv.d);
- break;
- case PNE_DECIMAL64:
- if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
- err = pn_data_put_decimal64(data, pn_decoder_readf64(decoder));
- break;
- case PNE_ULONG0:
- err = pn_data_put_ulong(data, 0);
- break;
- case PNE_SMALLULONG:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- err = pn_data_put_ulong(data, pn_decoder_readf8(decoder));
- break;
- case PNE_SMALLLONG:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- err = pn_data_put_long(data, (int8_t)pn_decoder_readf8(decoder));
- break;
- case PNE_DECIMAL128:
- if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
- pn_decoder_readf128(decoder, &dec128);
- err = pn_data_put_decimal128(data, dec128);
- break;
- case PNE_UUID:
- if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
- pn_decoder_readf128(decoder, &uuid);
- err = pn_data_put_uuid(data, uuid);
- break;
- case PNE_VBIN8:
- case PNE_STR8_UTF8:
- case PNE_SYM8:
- case PNE_VBIN32:
- case PNE_STR32_UTF8:
- case PNE_SYM32:
- switch (code & 0xF0)
- {
- case 0xA0:
- if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
- size = pn_decoder_readf8(decoder);
- break;
- case 0xB0:
- if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
- size = pn_decoder_readf32(decoder);
- break;
- default:
- return PN_ARG_ERR;
- }
-
- if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
-
- {
- char *start = (char *) decoder->position;
- pn_bytes_t bytes = {size, start};
- switch (code & 0x0F)
- {
- case 0x0:
- err = pn_data_put_binary(data, bytes);
- break;
- case 0x1:
- err = pn_data_put_string(data, bytes);
- break;
- case 0x3:
- err = pn_data_put_symbol(data, bytes);
- break;
- default:
- return PN_ARG_ERR;
- }
- }
-
- decoder->position += size;
- break;
- case PNE_LIST0:
- err = pn_data_put_list(data);
- break;
- case PNE_ARRAY8:
- case PNE_ARRAY32:
- case PNE_LIST8:
- case PNE_LIST32:
- case PNE_MAP8:
- case PNE_MAP32:
- switch (code)
- {
- case PNE_ARRAY8:
- case PNE_LIST8:
- case PNE_MAP8:
- if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
- size = pn_decoder_readf8(decoder);
- count = pn_decoder_readf8(decoder);
- break;
- case PNE_ARRAY32:
- case PNE_LIST32:
- case PNE_MAP32:
- size = pn_decoder_readf32(decoder);
- count = pn_decoder_readf32(decoder);
- break;
- default:
- return PN_ARG_ERR;
- }
-
- switch (code)
- {
- case PNE_ARRAY8:
- case PNE_ARRAY32:
- {
- uint8_t next = *decoder->position;
- bool described = (next == PNE_DESCRIPTOR);
- err = pn_data_put_array(data, described, (pn_type_t) 0);
- if (err) return err;
-
- pn_data_enter(data);
- uint8_t acode;
- int e = pni_decoder_decode_type(decoder, data, &acode);
- if (e) return e;
- pn_type_t type = pn_code2type(acode);
- if ((int)type < 0) return (int)type;
- for (size_t i = 0; i < count; i++)
- {
- e = pni_decoder_decode_value(decoder, data, acode);
- if (e) return e;
- }
- pn_data_exit(data);
-
- pni_data_set_array_type(data, type);
- }
- return 0;
- case PNE_LIST8:
- case PNE_LIST32:
- err = pn_data_put_list(data);
- if (err) return err;
- break;
- case PNE_MAP8:
- case PNE_MAP32:
- err = pn_data_put_map(data);
- if (err) return err;
- break;
- default:
- return PN_ARG_ERR;
- }
-
- pn_data_enter(data);
- for (size_t i = 0; i < count; i++)
- {
- int e = pni_decoder_single(decoder, data);
- if (e) return e;
- }
- pn_data_exit(data);
-
- return 0;
- default:
- return pn_error_format(decoder->error, PN_ARG_ERR, "unrecognized typecode: %u", code);
- }
-
- return err;
-}
-
-pn_type_t pni_data_parent_type(pn_data_t *data);
-
-static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code)
-{
- int err;
-
- if (!pn_decoder_remaining(decoder)) {
- return PN_UNDERFLOW;
- }
-
- uint8_t next = *decoder->position++;
-
- if (next == PNE_DESCRIPTOR) {
- if (pni_data_parent_type(data) != PN_ARRAY) {
- err = pn_data_put_described(data);
- if (err) return err;
- // pni_decoder_single has the corresponding exit
- pn_data_enter(data);
- }
- err = pni_decoder_single(decoder, data);
- if (err) return err;
- err = pni_decoder_decode_type(decoder, data, code);
- if (err) return err;
- } else {
- *code = next;
- }
-
- return 0;
-}
-
-size_t pn_data_siblings(pn_data_t *data);
-
-int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data)
-{
- uint8_t code;
- int err = pni_decoder_decode_type(decoder, data, &code);
- if (err) return err;
- err = pni_decoder_decode_value(decoder, data, code);
- if (err) return err;
- if (pni_data_parent_type(data) == PN_DESCRIBED && pn_data_siblings(data) > 1) {
- pn_data_exit(data);
- }
- return 0;
-}
-
-ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst)
-{
- decoder->input = src;
- decoder->size = size;
- decoder->position = src;
-
- int err = pni_decoder_single(decoder, dst);
-
- if (err == PN_UNDERFLOW)
- return pn_error_format(pn_data_error(dst), PN_UNDERFLOW, "not enough data to decode");
- if (err) return err;
-
- return decoder->position - decoder->input;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/decoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/decoder.h b/proton-c/src/codec/decoder.h
deleted file mode 100644
index b7de898..0000000
--- a/proton-c/src/codec/decoder.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _PROTON_DECODER_H
-#define _PROTON_DECODER_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-typedef struct pn_decoder_t pn_decoder_t;
-
-pn_decoder_t *pn_decoder(void);
-ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst);
-
-#endif /* decoder.h */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[20/20] qpid-proton git commit: PROTON-1351: Make go binding only
depend on qpid-proton-core
Posted by as...@apache.org.
PROTON-1351: Make go binding only depend on qpid-proton-core
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/eac0bb66
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/eac0bb66
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/eac0bb66
Branch: refs/heads/master
Commit: eac0bb663dd16bd9f43126038e22a0b4d0247c78
Parents: a585071
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Nov 14 12:55:28 2016 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 14 12:55:28 2016 -0500
----------------------------------------------------------------------
proton-c/bindings/go/CMakeLists.txt | 2 +-
proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go | 2 +-
proton-c/bindings/go/src/qpid.apache.org/electron/doc.go | 2 +-
proton-c/bindings/go/src/qpid.apache.org/proton/doc.go | 2 +-
proton-c/bindings/go/src/qpid.apache.org/proton/error.go | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eac0bb66/proton-c/bindings/go/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/CMakeLists.txt b/proton-c/bindings/go/CMakeLists.txt
index 269f9bf..16c633b 100644
--- a/proton-c/bindings/go/CMakeLists.txt
+++ b/proton-c/bindings/go/CMakeLists.txt
@@ -58,7 +58,7 @@ set(GO_TEST ${GO} test ${GO_BUILD_FLAGS} ${GO_RPATH_FLAGS} ${GO_TEST_FLAGS} CACH
# done.
add_custom_target(go-build ALL
COMMAND ${GO_INSTALL} qpid.apache.org/...
- DEPENDS qpid-proton
+ DEPENDS qpid-proton-core
WORKING_DIRECTORY $ENV{PWD})
add_test(
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eac0bb66/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
index 97051a5..d270704 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
@@ -30,7 +30,7 @@ AMQP 1.0 is an open standard for inter-operable message exchange, see <http://ww
*/
package amqp
-// #cgo LDFLAGS: -lqpid-proton
+// #cgo LDFLAGS: -lqpid-proton-core
import "C"
// This file is just for the package comment.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eac0bb66/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go b/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
index bc2c589..79a566e 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
@@ -48,7 +48,7 @@ More realistic examples: https://github.com/apache/qpid-proton/blob/master/examp
*/
package electron
-//#cgo LDFLAGS: -lqpid-proton
+//#cgo LDFLAGS: -lqpid-proton-core
import "C"
// Just for package comment
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eac0bb66/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
index 083f701..27bc5ec 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
@@ -58,7 +58,7 @@ applications.
*/
package proton
-// #cgo LDFLAGS: -lqpid-proton
+// #cgo LDFLAGS: -lqpid-proton-core
import "C"
// This file is just for the package comment.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eac0bb66/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/error.go b/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
index 80d9680..5232fec 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
@@ -20,7 +20,7 @@ under the License.
// Internal implementation details - ignore.
package proton
-// #cgo LDFLAGS: -lqpid-proton
+// #cgo LDFLAGS: -lqpid-proton-core
// #include <proton/error.h>
// #include <proton/codec.h>
import "C"
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[02/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
deleted file mode 100644
index 0201034..0000000
--- a/proton-c/src/windows/schannel.c
+++ /dev/null
@@ -1,2239 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/*
- * SChannel is designed to encrypt and decrypt data in place. So a
- * given buffer is expected to sometimes contain encrypted data,
- * sometimes decrypted data, and occasionally both. Outgoing buffers
- * need to reserve space for the TLS header and trailer. Read
- * operations need to ignore the same headers and trailers from
- * incoming buffers. Outgoing is simple because we choose record
- * boundaries. Incoming is complicated by handling incomplete TLS
- * records, and buffering contiguous data for the app layer that may
- * span many records. A lazy double buffering system is used for
- * the latter.
- */
-
-#include <proton/ssl.h>
-#include <proton/engine.h>
-#include "engine/engine-internal.h"
-#include "platform.h"
-#include "util.h"
-#include "transport/autodetect.h"
-
-#include <assert.h>
-
-// security.h needs to see this to distinguish from kernel use.
-#include <windows.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <Schnlsp.h>
-#include <WinInet.h>
-#undef SECURITY_WIN32
-
-
-/** @file
- * SSL/TLS support API.
- *
- * This file contains an SChannel-based implemention of the SSL/TLS API for Windows platforms.
- */
-
-static void ssl_log_error(const char *fmt, ...);
-static void ssl_log(pn_transport_t *transport, const char *fmt, ...);
-static void ssl_log_error_status(HRESULT status, const char *fmt, ...);
-static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error);
-
-/*
- * win_credential_t: SChannel context that must accompany TLS connections.
- *
- * SChannel attempts session resumption for shared CredHandle objects.
- * To mimic openssl behavior, server CredHandle handles must be shared
- * by derived connections, client CredHandle handles must be unique
- * when app's session_id is null and tracked for reuse otherwise
- * (TODO).
- *
- * Ref counted by parent ssl_domain_t and each derived connection.
- */
-struct win_credential_t {
- pn_ssl_mode_t mode;
- PCCERT_CONTEXT cert_context; // Particulars of the certificate (if any)
- CredHandle cred_handle; // Bound session parameters, certificate, CAs, verification_mode
- HCERTSTORE trust_store; // Store of root CAs for validating
- HCERTSTORE server_CA_certs; // CAs advertised by server (may be a duplicate of the trust_store)
- char *trust_store_name;
-};
-
-#define win_credential_compare NULL
-#define win_credential_inspect NULL
-#define win_credential_hashcode NULL
-
-static void win_credential_initialize(void *object)
-{
- win_credential_t *c = (win_credential_t *) object;
- SecInvalidateHandle(&c->cred_handle);
- c->cert_context = 0;
- c->trust_store = 0;
- c->server_CA_certs = 0;
- c->trust_store_name = 0;
-}
-
-static void win_credential_finalize(void *object)
-{
- win_credential_t *c = (win_credential_t *) object;
- if (SecIsValidHandle(&c->cred_handle))
- FreeCredentialsHandle(&c->cred_handle);
- if (c->cert_context)
- CertFreeCertificateContext(c->cert_context);
- if (c->trust_store)
- CertCloseStore(c->trust_store, 0);
- if (c->server_CA_certs)
- CertCloseStore(c->server_CA_certs, 0);
- free(c->trust_store_name);
-}
-
-static win_credential_t *win_credential(pn_ssl_mode_t m)
-{
- static const pn_cid_t CID_win_credential = CID_pn_void;
- static const pn_class_t clazz = PN_CLASS(win_credential);
- win_credential_t *c = (win_credential_t *) pn_class_new(&clazz, sizeof(win_credential_t));
- c->mode = m;
- return c;
-}
-
-static int win_credential_load_cert(win_credential_t *cred, const char *store_name, const char *cert_name, const char *passwd)
-{
- if (!store_name)
- return -2;
-
- int ec = 0;
- HCERTSTORE cert_store = open_cert_db(store_name, passwd, &ec);
- if (!cert_store)
- return ec;
-
- // find friendly name that matches cert_name, or sole certificate
- PCCERT_CONTEXT tmpctx = NULL;
- PCCERT_CONTEXT found_ctx = NULL;
- int cert_count = 0;
- int name_len = cert_name ? strlen(cert_name) : 0;
- char *fn = name_len ? (char *) malloc(name_len + 1) : 0;
- while (tmpctx = CertEnumCertificatesInStore(cert_store, tmpctx)) {
- cert_count++;
- if (cert_name) {
- DWORD len = CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
- 0, NULL, NULL, 0);
- if (len != name_len + 1)
- continue;
- CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
- 0, NULL, fn, len);
- if (!strcmp(cert_name, fn)) {
- found_ctx = tmpctx;
- tmpctx= NULL;
- break;
- }
- } else {
- // Test for single certificate
- if (cert_count == 1) {
- found_ctx = CertDuplicateCertificateContext(tmpctx);
- } else {
- ssl_log_error("Multiple certificates to choose from certificate store %s\n", store_name);
- found_ctx = NULL;
- break;
- }
- }
- }
-
- if (tmpctx) {
- CertFreeCertificateContext(tmpctx);
- tmpctx = false;
- }
- if (!found_ctx && cert_name && cert_count == 1)
- ssl_log_error("Could not find certificate %s in store %s\n", cert_name, store_name);
- cred->cert_context = found_ctx;
-
- free(fn);
- CertCloseStore(cert_store, 0);
- return found_ctx ? 0 : -8;
-}
-
-
-static CredHandle win_credential_cred_handle(win_credential_t *cred, pn_ssl_verify_mode_t verify_mode,
- const char *session_id, SECURITY_STATUS *status)
-{
- if (cred->mode == PN_SSL_MODE_SERVER && SecIsValidHandle(&cred->cred_handle)) {
- *status = SEC_E_OK;
- return cred->cred_handle; // Server always reuses cached value
- }
- // TODO: if (is_client && session_id != NULL) create or use cached value based on
- // session_id+server_host_name (per domain? reclaimed after X hours?)
-
- CredHandle tmp_handle;
- SecInvalidateHandle(&tmp_handle);
- TimeStamp expiry; // Not used
- SCHANNEL_CRED descriptor;
- memset(&descriptor, 0, sizeof(descriptor));
-
- descriptor.dwVersion = SCHANNEL_CRED_VERSION;
- descriptor.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
- if (cred->cert_context != NULL) {
- // assign the certificate into the credentials
- descriptor.paCred = &cred->cert_context;
- descriptor.cCreds = 1;
- }
-
- if (cred->mode == PN_SSL_MODE_SERVER) {
- descriptor.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
- if (cred->server_CA_certs) {
- descriptor.hRootStore = cred->server_CA_certs;
- }
- }
-
- ULONG direction = (cred->mode == PN_SSL_MODE_SERVER) ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND;
- *status = AcquireCredentialsHandle(NULL, UNISP_NAME, direction, NULL,
- &descriptor, NULL, NULL, &tmp_handle, &expiry);
- if (cred->mode == PN_SSL_MODE_SERVER && *status == SEC_E_OK)
- cred->cred_handle = tmp_handle;
-
- return tmp_handle;
-}
-
-static bool win_credential_has_certificate(win_credential_t *cred)
-{
- if (!cred) return false;
- return (cred->cert_context != NULL);
-}
-
-#define SSL_DATA_SIZE 16384
-#define SSL_BUF_SIZE (SSL_DATA_SIZE + 5 + 2048 + 32)
-
-typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
-typedef struct pn_ssl_session_t pn_ssl_session_t;
-
-struct pn_ssl_domain_t {
- int ref_count;
- pn_ssl_mode_t mode;
- bool has_ca_db; // true when CA database configured
- pn_ssl_verify_mode_t verify_mode;
- bool allow_unsecured;
- win_credential_t *cred;
-};
-
-typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
- RUNNING, SHUTTING_DOWN, SSL_CLOSED } ssl_state_t;
-
-struct pni_ssl_t {
- pn_ssl_domain_t *domain;
- const char *session_id;
- const char *peer_hostname;
- ssl_state_t state;
-
- bool protocol_detected;
- bool queued_shutdown;
- bool ssl_closed; // shutdown complete, or SSL error
- ssize_t app_input_closed; // error code returned by upper layer process input
- ssize_t app_output_closed; // error code returned by upper layer process output
-
- // OpenSSL hides the protocol envelope bytes, SChannel has them in-line.
- char *sc_outbuf; // SChannel output buffer
- size_t sc_out_size;
- size_t sc_out_count;
- char *network_outp; // network ready bytes within sc_outbuf
- size_t network_out_pending;
-
- char *sc_inbuf; // SChannel input buffer
- size_t sc_in_size;
- size_t sc_in_count;
- bool sc_in_incomplete;
-
- char *inbuf_extra; // Still encrypted data from following Record(s)
- size_t extra_count;
-
- char *in_data; // Just the plaintext data part of sc_inbuf, decrypted in place
- size_t in_data_size;
- size_t in_data_count;
- bool decrypting;
- size_t max_data_size; // computed in the handshake
-
- pn_bytes_t app_inbytes; // Virtual decrypted datastream, presented to app layer
-
- pn_buffer_t *inbuf2; // Second input buf if longer contiguous bytes needed
- bool double_buffered;
-
- bool sc_input_shutdown;
-
- CredHandle cred_handle;
- CtxtHandle ctxt_handle;
- SecPkgContext_StreamSizes sc_sizes;
- pn_ssl_verify_mode_t verify_mode;
- win_credential_t *cred;
- char *subject;
-};
-
-static inline pn_transport_t *get_transport_internal(pn_ssl_t *ssl)
-{
- // The external pn_sasl_t is really a pointer to the internal pni_transport_t
- return ((pn_transport_t *)ssl);
-}
-
-static inline pni_ssl_t *get_ssl_internal(pn_ssl_t *ssl)
-{
- // The external pn_sasl_t is really a pointer to the internal pni_transport_t
- return ssl ? ((pn_transport_t *)ssl)->ssl : NULL;
-}
-
-struct pn_ssl_session_t {
- const char *id;
-// TODO
- pn_ssl_session_t *ssn_cache_next;
- pn_ssl_session_t *ssn_cache_prev;
-};
-
-
-static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
-static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
-static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
-static void ssl_session_free( pn_ssl_session_t *);
-static size_t buffered_output( pn_transport_t *transport );
-static void start_ssl_shutdown(pn_transport_t *transport);
-static void rewind_sc_inbuf(pni_ssl_t *ssl);
-static bool grow_inbuf2(pn_transport_t *ssl, size_t minimum_size);
-static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing);
-
-// @todo: used to avoid littering the code with calls to printf...
-static void ssl_log_error(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fflush(stderr);
-}
-
-// @todo: used to avoid littering the code with calls to printf...
-static void ssl_log(pn_transport_t *transport, const char *fmt, ...)
-{
- if (PN_TRACE_DRV & transport->trace) {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fflush(stderr);
- }
-}
-
-static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
-{
- char buf[512];
- va_list ap;
-
- if (fmt) {
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
-
- if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
- 0, status, 0, buf, sizeof(buf), 0))
- ssl_log_error(" : %s\n", buf);
- else
- fprintf(stderr, "pn internal Windows error: %x for %x\n", GetLastError(), status);
-
- fflush(stderr);
-}
-
-static void ssl_log_clear_data(pn_transport_t *transport, const char *data, size_t len)
-{
- if (PN_TRACE_RAW & transport->trace) {
- fprintf(stderr, "SSL decrypted data: \"");
- pn_fprint_data( stderr, data, len );
- fprintf(stderr, "\"\n");
- }
-}
-
-static size_t _pni_min(size_t a, size_t b)
-{
- return (a < b) ? a : b;
-}
-
-// unrecoverable SSL failure occured, notify transport and generate error code.
-static int ssl_failed(pn_transport_t *transport, const char *reason)
-{
- char buf[512] = "Unknown error.";
- if (!reason) {
- HRESULT status = GetLastError();
-
- FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
- 0, status, 0, buf, sizeof(buf), 0);
- reason = buf;
- }
- pni_ssl_t *ssl = transport->ssl;
- ssl->ssl_closed = true;
- ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
- ssl->state = SSL_CLOSED;
- pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
- return PN_EOS;
-}
-
-static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *domain, const char *id )
-{
-// TODO:
- return NULL;
-}
-
-static void ssl_session_free( pn_ssl_session_t *ssn)
-{
- if (ssn) {
- if (ssn->id) free( (void *)ssn->id );
- free( ssn );
- }
-}
-
-
-/** Public API - visible to application code */
-
-bool pn_ssl_present(void)
-{
- return true;
-}
-
-pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
-{
- pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
- if (!domain) return NULL;
-
- domain->ref_count = 1;
- domain->mode = mode;
- switch(mode) {
- case PN_SSL_MODE_CLIENT:
- case PN_SSL_MODE_SERVER:
- break;
-
- default:
- ssl_log_error("Invalid mode for pn_ssl_mode_t: %d\n", mode);
- free(domain);
- return NULL;
- }
- domain->cred = win_credential(mode);
- return domain;
-}
-
-void pn_ssl_domain_free( pn_ssl_domain_t *domain )
-{
- if (!domain) return;
-
- if (--domain->ref_count == 0) {
- pn_decref(domain->cred);
- free(domain);
- }
-}
-
-
-int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
- const char *certificate_file,
- const char *private_key_file,
- const char *password)
-{
- if (!domain) return -1;
-
- if (win_credential_has_certificate(domain->cred)) {
- // Need a new win_credential_t to hold new certificate
- pn_decref(domain->cred);
- domain->cred = win_credential(domain->mode);
- if (!domain->cred)
- return -1;
- }
- return win_credential_load_cert(domain->cred, certificate_file, private_key_file, password);
-}
-
-
-int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
- const char *certificate_db)
-{
- if (!domain || !certificate_db) return -1;
-
- int ec = 0;
- HCERTSTORE store = open_cert_db(certificate_db, NULL, &ec);
- if (!store)
- return ec;
-
- if (domain->has_ca_db) {
- win_credential_t *new_cred = win_credential(domain->mode);
- if (!new_cred)
- return -1;
- new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
- pn_decref(domain->cred);
- domain->cred = new_cred;
- }
-
- domain->cred->trust_store = store;
- domain->cred->trust_store_name = pn_strdup(certificate_db);
- domain->has_ca_db = true;
- return 0;
-}
-
-
-int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
- const pn_ssl_verify_mode_t mode,
- const char *trusted_CAs)
-{
- if (!domain) return -1;
- if (!domain->has_ca_db && (mode == PN_SSL_VERIFY_PEER || mode == PN_SSL_VERIFY_PEER_NAME)) {
- ssl_log_error("Error: cannot verify peer without a trusted CA configured.\n"
- " Use pn_ssl_domain_set_trusted_ca_db()\n");
- return -1;
- }
-
- HCERTSTORE store = 0;
- bool changed = domain->verify_mode && mode != domain->verify_mode;
-
- switch (mode) {
- case PN_SSL_VERIFY_PEER:
- case PN_SSL_VERIFY_PEER_NAME:
- if (domain->mode == PN_SSL_MODE_SERVER) {
- if (!trusted_CAs) {
- ssl_log_error("Error: a list of trusted CAs must be provided.");
- return -1;
- }
- if (!win_credential_has_certificate(domain->cred)) {
- ssl_log_error("Error: Server cannot verify peer without configuring a certificate.\n"
- " Use pn_ssl_domain_set_credentials()");
- return -1;
- }
- int ec = 0;
- if (!strcmp(trusted_CAs, domain->cred->trust_store_name)) {
- store = open_cert_db(trusted_CAs, NULL, &ec);
- if (!store)
- return ec;
- } else {
- store = CertDuplicateStore(domain->cred->trust_store);
- }
-
- if (domain->cred->server_CA_certs) {
- // Already have one
- changed = true;
- win_credential_t *new_cred = win_credential(domain->mode);
- if (!new_cred) {
- CertCloseStore(store, 0);
- return -1;
- }
- new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
- new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
- new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
- pn_decref(domain->cred);
- domain->cred = new_cred;
- }
-
- domain->cred->server_CA_certs = store;
- }
- break;
-
- case PN_SSL_ANONYMOUS_PEER: // hippie free love mode... :)
- break;
-
- default:
- ssl_log_error("Invalid peer authentication mode given.\n");
- return -1;
- }
-
- if (changed) {
- win_credential_t *new_cred = win_credential(domain->mode);
- if (!new_cred) {
- CertCloseStore(store, 0);
- return -1;
- }
- new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
- new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
- new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
- pn_decref(domain->cred);
- domain->cred = new_cred;
- }
-
- domain->verify_mode = mode;
- domain->cred->server_CA_certs = store;
-
- return 0;
-}
-
-const pn_io_layer_t ssl_layer = {
- process_input_ssl,
- process_output_ssl,
- NULL,
- NULL,
- buffered_output
-};
-
-const pn_io_layer_t ssl_input_closed_layer = {
- process_input_done,
- process_output_ssl,
- NULL,
- NULL,
- buffered_output
-};
-
-const pn_io_layer_t ssl_output_closed_layer = {
- process_input_ssl,
- process_output_done,
- NULL,
- NULL,
- buffered_output
-};
-
-const pn_io_layer_t ssl_closed_layer = {
- process_input_done,
- process_output_done,
- NULL,
- NULL,
- buffered_output
-};
-
-int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
-{
- pn_transport_t *transport = get_transport_internal(ssl0);
- pni_ssl_t *ssl = transport->ssl;
- if (!ssl || !domain || ssl->domain) return -1;
- if (ssl->state != CREATED) return -1;
-
- ssl->domain = domain;
- domain->ref_count++;
- if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
- ssl->session_id = pn_strdup(session_id);
-
- // If SSL doesn't specifically allow skipping encryption, require SSL
- // TODO: This is a probably a stop-gap until allow_unsecured is removed
- if (!domain->allow_unsecured) transport->encryption_required = true;
-
- ssl->cred = domain->cred;
- pn_incref(domain->cred);
-
- SECURITY_STATUS status = SEC_E_OK;
- ssl->cred_handle = win_credential_cred_handle(ssl->cred, ssl->verify_mode,
- ssl->session_id, &status);
- if (status != SEC_E_OK) {
- ssl_log_error_status(status, "Credentials handle failure");
- return -1;
- }
-
- ssl->state = (domain->mode == PN_SSL_MODE_CLIENT) ? CLIENT_HELLO : NEGOTIATING;
- ssl->verify_mode = domain->verify_mode;
- return 0;
-}
-
-
-int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
-{
- if (!domain) return -1;
- if (domain->mode != PN_SSL_MODE_SERVER) {
- ssl_log_error("Cannot permit unsecured clients - not a server.\n");
- return -1;
- }
- domain->allow_unsecured = true;
- return 0;
-}
-
-
-// TODO: This is just an untested guess
-int pn_ssl_get_ssf(pn_ssl_t *ssl0)
-{
- SecPkgContext_ConnectionInfo info;
-
- pni_ssl_t *ssl = get_ssl_internal(ssl0);
- if (ssl &&
- ssl->state == RUNNING &&
- SecIsValidHandle(&ssl->ctxt_handle) &&
- QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
- return info.dwCipherStrength;
- }
- return 0;
-}
-
-bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
-{
- pni_ssl_t *ssl = get_ssl_internal(ssl0);
- if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
- return false;
- *buffer = '\0';
- SecPkgContext_ConnectionInfo info;
- if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
- // TODO: come up with string for all permutations?
- snprintf( buffer, size, "%x_%x:%x_%x:%x_%x",
- info.aiExch, info.dwExchStrength,
- info.aiCipher, info.dwCipherStrength,
- info.aiHash, info.dwHashStrength);
- return true;
- }
- return false;
-}
-
-bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
-{
- pni_ssl_t *ssl = get_ssl_internal(ssl0);
- if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
- return false;
- *buffer = '\0';
- SecPkgContext_ConnectionInfo info;
- if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
- if (info.dwProtocol & (SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_SERVER))
- snprintf(buffer, size, "%s", "TLSv1");
- // TLSV1.1 and TLSV1.2 are supported as of XP-SP3, but not defined until VS2010
- else if ((info.dwProtocol & 0x300))
- snprintf(buffer, size, "%s", "TLSv1.1");
- else if ((info.dwProtocol & 0xC00))
- snprintf(buffer, size, "%s", "TLSv1.2");
- else {
- ssl_log_error("unexpected protocol %x\n", info.dwProtocol);
- return false;
- }
- return true;
- }
- return false;
-}
-
-
-void pn_ssl_free( pn_transport_t *transport)
-{
- pni_ssl_t *ssl = transport->ssl;
- if (!ssl) return;
- ssl_log( transport, "SSL socket freed.\n" );
- // clean up Windows per TLS session data before releasing the domain count
- if (SecIsValidHandle(&ssl->ctxt_handle))
- DeleteSecurityContext(&ssl->ctxt_handle);
- if (ssl->cred) {
- if (ssl->domain->mode == PN_SSL_MODE_CLIENT && ssl->session_id == NULL) {
- // Responsible for unshared handle
- if (SecIsValidHandle(&ssl->cred_handle))
- FreeCredentialsHandle(&ssl->cred_handle);
- }
- pn_decref(ssl->cred);
- }
-
- if (ssl->domain) pn_ssl_domain_free(ssl->domain);
- if (ssl->session_id) free((void *)ssl->session_id);
- if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
- if (ssl->sc_inbuf) free((void *)ssl->sc_inbuf);
- if (ssl->sc_outbuf) free((void *)ssl->sc_outbuf);
- if (ssl->inbuf2) pn_buffer_free(ssl->inbuf2);
- if (ssl->subject) free(ssl->subject);
-
- free(ssl);
-}
-
-pn_ssl_t *pn_ssl(pn_transport_t *transport)
-{
- if (!transport) return NULL;
- if (transport->ssl) return (pn_ssl_t *)transport;
-
- pni_ssl_t *ssl = (pni_ssl_t *) calloc(1, sizeof(pni_ssl_t));
- if (!ssl) return NULL;
- ssl->sc_out_size = ssl->sc_in_size = SSL_BUF_SIZE;
-
- ssl->sc_outbuf = (char *)malloc(ssl->sc_out_size);
- if (!ssl->sc_outbuf) {
- free(ssl);
- return NULL;
- }
- ssl->sc_inbuf = (char *)malloc(ssl->sc_in_size);
- if (!ssl->sc_inbuf) {
- free(ssl->sc_outbuf);
- free(ssl);
- return NULL;
- }
-
- ssl->inbuf2 = pn_buffer(0);
- if (!ssl->inbuf2) {
- free(ssl->sc_inbuf);
- free(ssl->sc_outbuf);
- free(ssl);
- return NULL;
- }
-
- transport->ssl = ssl;
-
- // Set up hostname from any bound connection
- if (transport->connection) {
- if (pn_string_size(transport->connection->hostname)) {
- pn_ssl_set_peer_hostname((pn_ssl_t *) transport, pn_string_get(transport->connection->hostname));
- }
- }
-
- SecInvalidateHandle(&ssl->cred_handle);
- SecInvalidateHandle(&ssl->ctxt_handle);
- ssl->state = CREATED;
- ssl->decrypting = true;
-
- return (pn_ssl_t *)transport;
-}
-
-
-pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
-{
- // TODO
- return PN_SSL_RESUME_UNKNOWN;
-}
-
-
-int pn_ssl_set_peer_hostname( pn_ssl_t *ssl0, const char *hostname )
-{
- pni_ssl_t *ssl = get_ssl_internal(ssl0);
- if (!ssl) return -1;
-
- if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
- ssl->peer_hostname = NULL;
- if (hostname) {
- ssl->peer_hostname = pn_strdup(hostname);
- if (!ssl->peer_hostname) return -2;
- }
- return 0;
-}
-
-int pn_ssl_get_peer_hostname( pn_ssl_t *ssl0, char *hostname, size_t *bufsize )
-{
- pni_ssl_t *ssl = get_ssl_internal(ssl0);
- if (!ssl) return -1;
- if (!ssl->peer_hostname) {
- *bufsize = 0;
- if (hostname) *hostname = '\0';
- return 0;
- }
- unsigned len = strlen(ssl->peer_hostname);
- if (hostname) {
- if (len >= *bufsize) return -1;
- strcpy( hostname, ssl->peer_hostname );
- }
- *bufsize = len;
- return 0;
-}
-
-const char* pn_ssl_get_remote_subject(pn_ssl_t *ssl0)
-{
- // RFC 2253 compliant, but differs from openssl's subject string with space separators and
- // ordering of multicomponent RDNs. Made to work as similarly as possible with choice of flags.
- pni_ssl_t *ssl = get_ssl_internal(ssl0);
- if (!ssl || !SecIsValidHandle(&ssl->ctxt_handle))
- return NULL;
- if (!ssl->subject) {
- SECURITY_STATUS status;
- PCCERT_CONTEXT peer_cc = 0;
- status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
- if (status != SEC_E_OK) {
- ssl_log_error_status(status, "can't obtain remote certificate subject");
- return NULL;
- }
- DWORD flags = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
- DWORD strlen = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
- flags, NULL, 0);
- if (strlen > 0) {
- ssl->subject = (char*) malloc(strlen);
- if (ssl->subject) {
- DWORD len = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
- flags, ssl->subject, strlen);
- if (len != strlen) {
- free(ssl->subject);
- ssl->subject = NULL;
- ssl_log_error("pn_ssl_get_remote_subject failure in CertNameToStr");
- }
- }
- }
- CertFreeCertificateContext(peer_cc);
- }
- return ssl->subject;
-}
-
-
-/** SChannel specific: */
-
-const char *tls_version_check(pni_ssl_t *ssl)
-{
- SecPkgContext_ConnectionInfo info;
- QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info);
- // Ascending bit patterns denote newer SSL/TLS protocol versions.
- // SP_PROT_TLS1_0_SERVER is not defined until VS2010.
- return (info.dwProtocol < SP_PROT_TLS1_SERVER) ?
- "peer does not support TLS 1.0 security" : NULL;
-}
-
-static void ssl_encrypt(pn_transport_t *transport, char *app_data, size_t count)
-{
- pni_ssl_t *ssl = transport->ssl;
-
- // Get SChannel to encrypt exactly one Record.
- SecBuffer buffs[4];
- buffs[0].cbBuffer = ssl->sc_sizes.cbHeader;
- buffs[0].BufferType = SECBUFFER_STREAM_HEADER;
- buffs[0].pvBuffer = ssl->sc_outbuf;
- buffs[1].cbBuffer = count;
- buffs[1].BufferType = SECBUFFER_DATA;
- buffs[1].pvBuffer = app_data;
- buffs[2].cbBuffer = ssl->sc_sizes.cbTrailer;
- buffs[2].BufferType = SECBUFFER_STREAM_TRAILER;
- buffs[2].pvBuffer = &app_data[count];
- buffs[3].cbBuffer = 0;
- buffs[3].BufferType = SECBUFFER_EMPTY;
- buffs[3].pvBuffer = 0;
- SecBufferDesc buff_desc;
- buff_desc.ulVersion = SECBUFFER_VERSION;
- buff_desc.cBuffers = 4;
- buff_desc.pBuffers = buffs;
- SECURITY_STATUS status = EncryptMessage(&ssl->ctxt_handle, 0, &buff_desc, 0);
- assert(status == SEC_E_OK);
-
- // EncryptMessage encrypts the data in place. The header and trailer
- // areas were reserved previously and must now be included in the updated
- // count of bytes to write to the peer.
- ssl->sc_out_count = buffs[0].cbBuffer + buffs[1].cbBuffer + buffs[2].cbBuffer;
- ssl->network_outp = ssl->sc_outbuf;
- ssl->network_out_pending = ssl->sc_out_count;
- ssl_log(transport, "ssl_encrypt %d network bytes\n", ssl->network_out_pending);
-}
-
-// Returns true if decryption succeeded (even for empty content)
-static bool ssl_decrypt(pn_transport_t *transport)
-{
- pni_ssl_t *ssl = transport->ssl;
- // Get SChannel to decrypt input. May have an incomplete Record,
- // exactly one, or more than one. Check also for session ending,
- // session renegotiation.
-
- SecBuffer recv_buffs[4];
- recv_buffs[0].cbBuffer = ssl->sc_in_count;
- recv_buffs[0].BufferType = SECBUFFER_DATA;
- recv_buffs[0].pvBuffer = ssl->sc_inbuf;
- recv_buffs[1].BufferType = SECBUFFER_EMPTY;
- recv_buffs[2].BufferType = SECBUFFER_EMPTY;
- recv_buffs[3].BufferType = SECBUFFER_EMPTY;
- SecBufferDesc buff_desc;
- buff_desc.ulVersion = SECBUFFER_VERSION;
- buff_desc.cBuffers = 4;
- buff_desc.pBuffers = recv_buffs;
- SECURITY_STATUS status = DecryptMessage(&ssl->ctxt_handle, &buff_desc, 0, NULL);
-
- if (status == SEC_E_INCOMPLETE_MESSAGE) {
- // Less than a full Record, come back later with more network data
- ssl->sc_in_incomplete = true;
- return false;
- }
-
- ssl->decrypting = false;
-
- if (status != SEC_E_OK) {
- rewind_sc_inbuf(ssl);
- switch (status) {
- case SEC_I_CONTEXT_EXPIRED:
- // TLS shutdown alert record. Ignore all subsequent input.
- ssl->state = SHUTTING_DOWN;
- ssl->sc_input_shutdown = true;
- return false;
-
- case SEC_I_RENEGOTIATE:
- ssl_log_error("unexpected TLS renegotiation\n");
- // TODO. Fall through for now.
- default:
- ssl_failed(transport, 0);
- return false;
- }
- }
-
- ssl->decrypting = false;
- // have a decrypted Record and possible (still-encrypted) data of
- // one (or more) later Recordss. Adjust pointers accordingly.
- for (int i = 0; i < 4; i++) {
- switch (recv_buffs[i].BufferType) {
- case SECBUFFER_DATA:
- ssl->in_data = (char *) recv_buffs[i].pvBuffer;
- ssl->in_data_size = ssl->in_data_count = recv_buffs[i].cbBuffer;
- break;
- case SECBUFFER_EXTRA:
- ssl->inbuf_extra = (char *)recv_buffs[i].pvBuffer;
- ssl->extra_count = recv_buffs[i].cbBuffer;
- break;
- default:
- // SECBUFFER_STREAM_HEADER:
- // SECBUFFER_STREAM_TRAILER:
- break;
- }
- }
- return true;
-}
-
-static void client_handshake_init(pn_transport_t *transport)
-{
- pni_ssl_t *ssl = transport->ssl;
- // Tell SChannel to create the first handshake token (ClientHello)
- // and place it in sc_outbuf
- SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
- ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_EXTENDED_ERROR;
- ULONG ctxt_attrs;
-
- SecBuffer send_buffs[2];
- send_buffs[0].cbBuffer = ssl->sc_out_size;
- send_buffs[0].BufferType = SECBUFFER_TOKEN;
- send_buffs[0].pvBuffer = ssl->sc_outbuf;
- send_buffs[1].cbBuffer = 0;
- send_buffs[1].BufferType = SECBUFFER_EMPTY;
- send_buffs[1].pvBuffer = 0;
- SecBufferDesc send_buff_desc;
- send_buff_desc.ulVersion = SECBUFFER_VERSION;
- send_buff_desc.cBuffers = 2;
- send_buff_desc.pBuffers = send_buffs;
- SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
- NULL, host, ctxt_requested, 0, 0, NULL, 0,
- &ssl->ctxt_handle, &send_buff_desc,
- &ctxt_attrs, NULL);
-
- if (status == SEC_I_CONTINUE_NEEDED) {
- ssl->sc_out_count = send_buffs[0].cbBuffer;
- ssl->network_out_pending = ssl->sc_out_count;
- // the token is the whole quantity to send
- ssl->network_outp = ssl->sc_outbuf;
- ssl_log(transport, "Sending client hello %d bytes\n", ssl->network_out_pending);
- } else {
- ssl_log_error_status(status, "InitializeSecurityContext failed");
- ssl_failed(transport, 0);
- }
-}
-
-static void client_handshake( pn_transport_t* transport) {
- pni_ssl_t *ssl = transport->ssl;
- // Feed SChannel ongoing responses from the server until the handshake is complete.
- SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
- ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
- ULONG ctxt_attrs;
- size_t max = 0;
-
- // token_buffs describe the buffer that's coming in. It should have
- // a token from the SSL server, or empty if sending final shutdown alert.
- bool shutdown = ssl->state == SHUTTING_DOWN;
- SecBuffer token_buffs[2];
- token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
- token_buffs[0].BufferType = SECBUFFER_TOKEN;
- token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
- token_buffs[1].cbBuffer = 0;
- token_buffs[1].BufferType = SECBUFFER_EMPTY;
- token_buffs[1].pvBuffer = 0;
- SecBufferDesc token_buff_desc;
- token_buff_desc.ulVersion = SECBUFFER_VERSION;
- token_buff_desc.cBuffers = 2;
- token_buff_desc.pBuffers = token_buffs;
-
- // send_buffs will hold information to forward to the peer.
- SecBuffer send_buffs[2];
- send_buffs[0].cbBuffer = ssl->sc_out_size;
- send_buffs[0].BufferType = SECBUFFER_TOKEN;
- send_buffs[0].pvBuffer = ssl->sc_outbuf;
- send_buffs[1].cbBuffer = 0;
- send_buffs[1].BufferType = SECBUFFER_EMPTY;
- send_buffs[1].pvBuffer = 0;
- SecBufferDesc send_buff_desc;
- send_buff_desc.ulVersion = SECBUFFER_VERSION;
- send_buff_desc.cBuffers = 2;
- send_buff_desc.pBuffers = send_buffs;
-
- SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
- &ssl->ctxt_handle, host, ctxt_requested, 0, 0,
- &token_buff_desc, 0, NULL, &send_buff_desc,
- &ctxt_attrs, NULL);
- switch (status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- // Not enough - get more data from the server then try again.
- // Leave input buffers untouched.
- ssl_log(transport, "client handshake: incomplete record\n");
- ssl->sc_in_incomplete = true;
- return;
-
- case SEC_I_CONTINUE_NEEDED:
- // Successful handshake step, requiring data to be sent to peer.
- ssl->sc_out_count = send_buffs[0].cbBuffer;
- // the token is the whole quantity to send
- ssl->network_out_pending = ssl->sc_out_count;
- ssl->network_outp = ssl->sc_outbuf;
- ssl_log(transport, "client handshake token %d bytes\n", ssl->network_out_pending);
- break;
-
- case SEC_E_OK:
- // Handshake complete.
- if (shutdown) {
- if (send_buffs[0].cbBuffer > 0) {
- ssl->sc_out_count = send_buffs[0].cbBuffer;
- // the token is the whole quantity to send
- ssl->network_out_pending = ssl->sc_out_count;
- ssl->network_outp = ssl->sc_outbuf;
- ssl_log(transport, "client shutdown token %d bytes\n", ssl->network_out_pending);
- } else {
- ssl->state = SSL_CLOSED;
- }
- // we didn't touch sc_inbuf, no need to reset
- return;
- }
- if (send_buffs[0].cbBuffer != 0) {
- ssl_failed(transport, "unexpected final server token");
- break;
- }
- if (const char *err = tls_version_check(ssl)) {
- ssl_failed(transport, err);
- break;
- }
- if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
- bool tracing = PN_TRACE_DRV & transport->trace;
- HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, ssl->peer_hostname, tracing);
- if (ec) {
- if (ssl->peer_hostname)
- ssl_log_error_status(ec, "certificate verification failed for host %s\n", ssl->peer_hostname);
- else
- ssl_log_error_status(ec, "certificate verification failed\n");
- ssl_failed(transport, "TLS certificate verification error");
- break;
- }
- }
-
- if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0) {
- // This seems to work but not documented, plus logic differs from decrypt message
- // since the pvBuffer value is not set. Grrr.
- ssl->extra_count = token_buffs[1].cbBuffer;
- ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
- }
-
- QueryContextAttributes(&ssl->ctxt_handle,
- SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
- max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
- if (max > ssl->sc_out_size) {
- ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
- ssl->state = SHUTTING_DOWN;
- ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
- start_ssl_shutdown(transport);
- pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
- break;
- }
-
- ssl->state = RUNNING;
- ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
- ssl_log(transport, "client handshake successful %d max record size\n", max);
- break;
-
- case SEC_I_CONTEXT_EXPIRED:
- // ended before we got going
- default:
- ssl_log(transport, "client handshake failed %d\n", (int) status);
- ssl_failed(transport, 0);
- break;
- }
-
- if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
- !ssl->ssl_closed) {
- // remaining data after the consumed TLS record(s)
- ssl->extra_count = token_buffs[1].cbBuffer;
- ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
- }
-
- ssl->decrypting = false;
- rewind_sc_inbuf(ssl);
-}
-
-
-static void server_handshake(pn_transport_t* transport)
-{
- pni_ssl_t *ssl = transport->ssl;
- if (!ssl->protocol_detected) {
- // SChannel fails less aggressively than openssl on client hello, causing hangs
- // waiting for more bytes. Help out here.
- pni_protocol_type_t type = pni_sniff_header(ssl->sc_inbuf, ssl->sc_in_count);
- if (type == PNI_PROTOCOL_INSUFFICIENT) {
- ssl_log(transport, "server handshake: incomplete record\n");
- ssl->sc_in_incomplete = true;
- return;
- } else {
- ssl->protocol_detected = true;
- if (type != PNI_PROTOCOL_SSL) {
- ssl_failed(transport, "bad client hello");
- ssl->decrypting = false;
- rewind_sc_inbuf(ssl);
- return;
- }
- }
- }
-
- // Feed SChannel ongoing handshake records from the client until the handshake is complete.
- ULONG ctxt_requested = ASC_REQ_STREAM | ASC_REQ_EXTENDED_ERROR;
- if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME)
- ctxt_requested |= ASC_REQ_MUTUAL_AUTH;
- ULONG ctxt_attrs;
- size_t max = 0;
-
- // token_buffs describe the buffer that's coming in. It should have
- // a token from the SSL client except if shutting down or renegotiating.
- bool shutdown = ssl->state == SHUTTING_DOWN;
- SecBuffer token_buffs[2];
- token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
- token_buffs[0].BufferType = SECBUFFER_TOKEN;
- token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
- token_buffs[1].cbBuffer = 0;
- token_buffs[1].BufferType = SECBUFFER_EMPTY;
- token_buffs[1].pvBuffer = 0;
- SecBufferDesc token_buff_desc;
- token_buff_desc.ulVersion = SECBUFFER_VERSION;
- token_buff_desc.cBuffers = 2;
- token_buff_desc.pBuffers = token_buffs;
-
- // send_buffs will hold information to forward to the peer.
- SecBuffer send_buffs[2];
- send_buffs[0].cbBuffer = ssl->sc_out_size;
- send_buffs[0].BufferType = SECBUFFER_TOKEN;
- send_buffs[0].pvBuffer = ssl->sc_outbuf;
- send_buffs[1].cbBuffer = 0;
- send_buffs[1].BufferType = SECBUFFER_EMPTY;
- send_buffs[1].pvBuffer = 0;
- SecBufferDesc send_buff_desc;
- send_buff_desc.ulVersion = SECBUFFER_VERSION;
- send_buff_desc.cBuffers = 2;
- send_buff_desc.pBuffers = send_buffs;
- PCtxtHandle ctxt_handle_ptr = (SecIsValidHandle(&ssl->ctxt_handle)) ? &ssl->ctxt_handle : 0;
-
- SECURITY_STATUS status = AcceptSecurityContext(&ssl->cred_handle, ctxt_handle_ptr,
- &token_buff_desc, ctxt_requested, 0, &ssl->ctxt_handle,
- &send_buff_desc, &ctxt_attrs, NULL);
-
- bool outbound_token = false;
- switch(status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- // Not enough - get more data from the client then try again.
- // Leave input buffers untouched.
- ssl_log(transport, "server handshake: incomplete record\n");
- ssl->sc_in_incomplete = true;
- return;
-
- case SEC_I_CONTINUE_NEEDED:
- outbound_token = true;
- break;
-
- case SEC_E_OK:
- // Handshake complete.
- if (shutdown) {
- if (send_buffs[0].cbBuffer > 0) {
- ssl->sc_out_count = send_buffs[0].cbBuffer;
- // the token is the whole quantity to send
- ssl->network_out_pending = ssl->sc_out_count;
- ssl->network_outp = ssl->sc_outbuf;
- ssl_log(transport, "server shutdown token %d bytes\n", ssl->network_out_pending);
- } else {
- ssl->state = SSL_CLOSED;
- }
- // we didn't touch sc_inbuf, no need to reset
- return;
- }
- if (const char *err = tls_version_check(ssl)) {
- ssl_failed(transport, err);
- break;
- }
- // Handshake complete.
-
- if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
- bool tracing = PN_TRACE_DRV & transport->trace;
- HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, NULL, tracing);
- if (ec) {
- ssl_log_error_status(ec, "certificate verification failed\n");
- ssl_failed(transport, "certificate verification error");
- break;
- }
- }
-
- QueryContextAttributes(&ssl->ctxt_handle,
- SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
- max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
- if (max > ssl->sc_out_size) {
- ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
- ssl->state = SHUTTING_DOWN;
- ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
- start_ssl_shutdown(transport);
- pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
- break;
- }
-
- if (send_buffs[0].cbBuffer != 0)
- outbound_token = true;
-
- ssl->state = RUNNING;
- ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
- ssl_log(transport, "server handshake successful %d max record size\n", max);
- break;
-
- case SEC_I_CONTEXT_EXPIRED:
- // ended before we got going
- default:
- ssl_log(transport, "server handshake failed %d\n", (int) status);
- ssl_failed(transport, 0);
- break;
- }
-
- if (outbound_token) {
- // Successful handshake step, requiring data to be sent to peer.
- assert(ssl->network_out_pending == 0);
- ssl->sc_out_count = send_buffs[0].cbBuffer;
- // the token is the whole quantity to send
- ssl->network_out_pending = ssl->sc_out_count;
- ssl->network_outp = ssl->sc_outbuf;
- ssl_log(transport, "server handshake token %d bytes\n", ssl->network_out_pending);
- }
-
- if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
- !ssl->ssl_closed) {
- // remaining data after the consumed TLS record(s)
- ssl->extra_count = token_buffs[1].cbBuffer;
- ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
- }
-
- ssl->decrypting = false;
- rewind_sc_inbuf(ssl);
-}
-
-static void ssl_handshake(pn_transport_t* transport) {
- if (transport->ssl->domain->mode == PN_SSL_MODE_CLIENT)
- client_handshake(transport);
- else {
- server_handshake(transport);
- }
-}
-
-static bool grow_inbuf2(pn_transport_t *transport, size_t minimum_size) {
- pni_ssl_t *ssl = transport->ssl;
- size_t old_capacity = pn_buffer_capacity(ssl->inbuf2);
- size_t new_capacity = old_capacity ? old_capacity * 2 : 1024;
-
- while (new_capacity < minimum_size)
- new_capacity *= 2;
-
- uint32_t max_frame = pn_transport_get_max_frame(transport);
- if (max_frame != 0) {
- if (old_capacity >= max_frame) {
- // already big enough
- ssl_log(transport, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
- ssl_failed(transport, "TLS: transport maximimum frame size error");
- return false;
- }
- }
-
- size_t extra_bytes = new_capacity - pn_buffer_size(ssl->inbuf2);
- int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
- if (err) {
- ssl_log(transport, "TLS memory allocation failed for %d bytes\n", max_frame);
- ssl_failed(transport, "TLS memory allocation failed");
- return false;
- }
- return true;
-}
-
-
-// Peer initiated a session end by sending us a shutdown alert (and we should politely
-// reciprocate), or else we are initiating the session end (and will not bother to wait
-// for the peer shutdown alert). Stop processing input immediately, and stop processing
-// output once this is sent.
-
-static void start_ssl_shutdown(pn_transport_t *transport)
-{
- pni_ssl_t *ssl = transport->ssl;
- assert(ssl->network_out_pending == 0);
- if (ssl->queued_shutdown)
- return;
- ssl->queued_shutdown = true;
- ssl_log(transport, "Shutting down SSL connection...\n");
-
- DWORD shutdown = SCHANNEL_SHUTDOWN;
- SecBuffer shutBuff;
- shutBuff.cbBuffer = sizeof(DWORD);
- shutBuff.BufferType = SECBUFFER_TOKEN;
- shutBuff.pvBuffer = &shutdown;
- SecBufferDesc desc;
- desc.ulVersion = SECBUFFER_VERSION;
- desc.cBuffers = 1;
- desc.pBuffers = &shutBuff;
- ApplyControlToken(&ssl->ctxt_handle, &desc);
-
- // Next handshake will generate the shudown alert token
- ssl_handshake(transport);
-}
-
-static void rewind_sc_inbuf(pni_ssl_t *ssl)
-{
- // Decrypted bytes have been drained or double buffered. Prepare for the next SSL Record.
- assert(ssl->in_data_count == 0);
- if (ssl->decrypting)
- return;
- ssl->decrypting = true;
- if (ssl->inbuf_extra) {
- // A previous read picked up more than one Record. Move it to the beginning.
- memmove(ssl->sc_inbuf, ssl->inbuf_extra, ssl->extra_count);
- ssl->sc_in_count = ssl->extra_count;
- ssl->inbuf_extra = 0;
- ssl->extra_count = 0;
- } else {
- ssl->sc_in_count = 0;
- }
-}
-
-static void app_inbytes_add(pn_transport_t *transport)
-{
- pni_ssl_t *ssl = transport->ssl;
- if (!ssl->app_inbytes.start) {
- ssl->app_inbytes.start = ssl->in_data;
- ssl->app_inbytes.size = ssl->in_data_count;
- return;
- }
-
- if (ssl->double_buffered) {
- if (pn_buffer_available(ssl->inbuf2) == 0) {
- if (!grow_inbuf2(transport, 1024))
- // could not add room
- return;
- }
- size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
- pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
- ssl->in_data += count;
- ssl->in_data_count -= count;
- ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
- } else {
- assert(ssl->app_inbytes.size == 0);
- ssl->app_inbytes.start = ssl->in_data;
- ssl->app_inbytes.size = ssl->in_data_count;
- }
-}
-
-
-static void app_inbytes_progress(pn_transport_t *transport, size_t minimum)
-{
- pni_ssl_t *ssl = transport->ssl;
- // Make more decrypted data available, if possible. Otherwise, move
- // unread bytes to front of inbuf2 to make room for next bulk decryption.
- // SSL may have chopped up data that app layer expects to be
- // contiguous. Start, continue or stop double buffering here.
- if (ssl->double_buffered) {
- if (ssl->app_inbytes.size == 0) {
- // no straggler bytes, optimistically stop for now
- ssl->double_buffered = false;
- pn_buffer_clear(ssl->inbuf2);
- ssl->app_inbytes.start = ssl->in_data;
- ssl->app_inbytes.size = ssl->in_data_count;
- } else {
- pn_bytes_t ib2 = pn_buffer_bytes(ssl->inbuf2);
- assert(ssl->app_inbytes.size <= ib2.size);
- size_t consumed = ib2.size - ssl->app_inbytes.size;
- if (consumed > 0) {
- memmove((void *)ib2.start, ib2.start + consumed, ssl->app_inbytes.size);
- pn_buffer_trim(ssl->inbuf2, 0, consumed);
- }
- if (!pn_buffer_available(ssl->inbuf2)) {
- if (!grow_inbuf2(transport, minimum))
- // could not add room
- return;
- }
- size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
- pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
- ssl->in_data += count;
- ssl->in_data_count -= count;
- ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
- }
- } else {
- if (ssl->app_inbytes.size) {
- // start double buffering the left over bytes
- ssl->double_buffered = true;
- pn_buffer_clear(ssl->inbuf2);
- if (!pn_buffer_available(ssl->inbuf2)) {
- if (!grow_inbuf2(transport, minimum))
- // could not add room
- return;
- }
- size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
- pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
- ssl->in_data += count;
- ssl->in_data_count -= count;
- ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
- } else {
- // already pointing at all available bytes until next decrypt
- }
- }
- if (ssl->in_data_count == 0)
- rewind_sc_inbuf(ssl);
-}
-
-
-static void app_inbytes_advance(pn_transport_t *transport, size_t consumed)
-{
- pni_ssl_t *ssl = transport->ssl;
- if (consumed == 0) {
- // more contiguous bytes required
- app_inbytes_progress(transport, ssl->app_inbytes.size + 1);
- return;
- }
- assert(consumed <= ssl->app_inbytes.size);
- ssl->app_inbytes.start += consumed;
- ssl->app_inbytes.size -= consumed;
- if (!ssl->double_buffered) {
- ssl->in_data += consumed;
- ssl->in_data_count -= consumed;
- }
- if (ssl->app_inbytes.size == 0)
- app_inbytes_progress(transport, 0);
-}
-
-static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t error)
-{
- pni_ssl_t *ssl = transport->ssl;
- if (ssl->app_input_closed)
- return;
- if (ssl->state == RUNNING && !error) {
- // Signal end of stream
- ssl->app_input_closed = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, 0);
- }
- if (!ssl->app_input_closed)
- ssl->app_input_closed = error ? error : PN_ERR;
-
- if (ssl->app_output_closed) {
- // both sides of app closed, and no more app output pending:
- ssl->state = SHUTTING_DOWN;
- if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
- start_ssl_shutdown(transport);
- }
- }
-}
-
-
-// Read up to "available" bytes from the network, decrypt it and pass plaintext to application.
-
-static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
-{
- pni_ssl_t *ssl = transport->ssl;
- ssl_log( transport, "process_input_ssl( data size=%d )\n",available );
- ssize_t consumed = 0;
- ssize_t forwarded = 0;
- bool new_app_input;
-
- if (available == 0) {
- // No more inbound network data
- read_closed(transport, layer, 0);
- return 0;
- }
-
- do {
- if (ssl->sc_input_shutdown) {
- // TLS protocol shutdown detected on input, so we are done.
- read_closed(transport, layer, 0);
- return PN_EOS;
- }
-
- // sc_inbuf should be ready for new or additional network encrypted bytes.
- // i.e. no straggling decrypted bytes pending.
- assert(ssl->in_data_count == 0 && ssl->decrypting);
- new_app_input = false;
- size_t count;
-
- if (ssl->state != RUNNING) {
- count = _pni_min(ssl->sc_in_size - ssl->sc_in_count, available);
- } else {
- // look for TLS record boundaries
- if (ssl->sc_in_count < 5) {
- ssl->sc_in_incomplete = true;
- size_t hc = _pni_min(available, 5 - ssl->sc_in_count);
- memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, hc);
- ssl->sc_in_count += hc;
- input_data += hc;
- available -= hc;
- consumed += hc;
- if (ssl->sc_in_count < 5 || available == 0)
- break;
- }
-
- // Top up sc_inbuf from network input_data hoping for a complete TLS Record
- // We try to guess the length as an optimization, but let SChannel
- // ultimately decide if there is spoofing going on.
- unsigned char low = (unsigned char) ssl->sc_inbuf[4];
- unsigned char high = (unsigned char) ssl->sc_inbuf[3];
- size_t rec_len = high * 256 + low + 5;
- if (rec_len < 5 || rec_len == ssl->sc_in_count || rec_len > ssl->sc_in_size)
- rec_len = ssl->sc_in_size;
-
- count = _pni_min(rec_len - ssl->sc_in_count, available);
- }
-
- if (count > 0) {
- memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, count);
- ssl->sc_in_count += count;
- input_data += count;
- available -= count;
- consumed += count;
- ssl->sc_in_incomplete = false;
- }
-
- // Try to decrypt another TLS Record.
-
- if (ssl->sc_in_count > 0 && ssl->state <= SHUTTING_DOWN) {
- if (ssl->state == NEGOTIATING) {
- ssl_handshake(transport);
- } else {
- if (ssl_decrypt(transport)) {
- // Ignore TLS Record with 0 length data (does not mean EOS)
- if (ssl->in_data_size > 0) {
- new_app_input = true;
- app_inbytes_add(transport);
- } else {
- assert(ssl->decrypting == false);
- rewind_sc_inbuf(ssl);
- }
- }
- ssl_log(transport, "Next decryption, %d left over\n", available);
- }
- }
-
- if (ssl->state == SHUTTING_DOWN) {
- if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
- start_ssl_shutdown(transport);
- }
- } else if (ssl->state == SSL_CLOSED) {
- return PN_EOS;
- }
-
- // Consume or discard the decrypted bytes
- if (new_app_input && (ssl->state == RUNNING || ssl->state == SHUTTING_DOWN)) {
- // present app_inbytes to io_next only if it has new content
- while (ssl->app_inbytes.size > 0) {
- if (!ssl->app_input_closed) {
- ssize_t count = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, ssl->app_inbytes.size);
- if (count > 0) {
- forwarded += count;
- // advance() can increase app_inbytes.size if double buffered
- app_inbytes_advance(transport, count);
- ssl_log(transport, "Application consumed %d bytes from peer\n", (int) count);
- } else if (count == 0) {
- size_t old_size = ssl->app_inbytes.size;
- app_inbytes_advance(transport, 0);
- if (ssl->app_inbytes.size == old_size) {
- break; // no additional contiguous decrypted data available, get more network data
- }
- } else {
- // count < 0
- ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)\n",
- (int) count, (int)ssl->app_inbytes.size);
- app_inbytes_advance(transport, ssl->app_inbytes.size); // discard
- read_closed(transport, layer, count);
- }
- } else {
- ssl_log(transport, "Input closed discard %d bytes\n",
- (int)ssl->app_inbytes.size);
- app_inbytes_advance(transport, ssl->app_inbytes.size); // discard
- }
- }
- }
- } while (available || (ssl->sc_in_count && !ssl->sc_in_incomplete));
-
- if (ssl->state >= SHUTTING_DOWN) {
- if (ssl->app_input_closed || ssl->sc_input_shutdown) {
- // Next layer doesn't want more bytes, or it can't process without more data than it has seen so far
- // but the ssl stream has ended
- consumed = ssl->app_input_closed ? ssl->app_input_closed : PN_EOS;
- if (transport->io_layers[layer]==&ssl_output_closed_layer) {
- transport->io_layers[layer] = &ssl_closed_layer;
- } else {
- transport->io_layers[layer] = &ssl_input_closed_layer;
- }
- }
- }
- ssl_log(transport, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
- return consumed;
-}
-
-static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
-{
- pni_ssl_t *ssl = transport->ssl;
- if (!ssl) return PN_EOS;
- ssl_log( transport, "process_output_ssl( max_len=%d )\n",max_len );
-
- ssize_t written = 0;
- ssize_t total_app_bytes = 0;
- bool work_pending;
-
- if (ssl->state == CLIENT_HELLO) {
- // output buffers eclusively for internal handshake use until negotiation complete
- client_handshake_init(transport);
- if (ssl->state == SSL_CLOSED)
- return PN_EOS;
- ssl->state = NEGOTIATING;
- }
-
- do {
- work_pending = false;
-
- if (ssl->network_out_pending > 0) {
- size_t wcount = _pni_min(ssl->network_out_pending, max_len);
- memmove(buffer, ssl->network_outp, wcount);
- ssl->network_outp += wcount;
- ssl->network_out_pending -= wcount;
- buffer += wcount;
- max_len -= wcount;
- written += wcount;
- }
-
- if (ssl->network_out_pending == 0 && ssl->state == RUNNING && !ssl->app_output_closed) {
- // refill the buffer with app data and encrypt it
-
- char *app_data = ssl->sc_outbuf + ssl->sc_sizes.cbHeader;
- char *app_outp = app_data;
- size_t remaining = ssl->max_data_size;
- ssize_t app_bytes;
- do {
- app_bytes = transport->io_layers[layer+1]->process_output(transport, layer+1, app_outp, remaining);
- if (app_bytes > 0) {
- app_outp += app_bytes;
- remaining -= app_bytes;
- ssl_log( transport, "Gathered %d bytes from app to send to peer\n", app_bytes );
- } else {
- if (app_bytes < 0) {
- ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)\n",
- (int) app_bytes, (int) ssl->network_out_pending);
- ssl->app_output_closed = app_bytes;
- if (ssl->app_input_closed)
- ssl->state = SHUTTING_DOWN;
- } else if (total_app_bytes == 0 && ssl->app_input_closed) {
- // We've drained all the App layer can provide
- ssl_log(transport, "Application layer blocked on input, closing\n");
- ssl->state = SHUTTING_DOWN;
- ssl->app_output_closed = PN_ERR;
- }
- }
- } while (app_bytes > 0);
- if (app_outp > app_data) {
- work_pending = (max_len > 0);
- ssl_encrypt(transport, app_data, app_outp - app_data);
- }
- }
-
- if (ssl->network_out_pending == 0) {
- if (ssl->state == SHUTTING_DOWN) {
- if (!ssl->queued_shutdown) {
- start_ssl_shutdown(transport);
- work_pending = true;
- } else {
- ssl->state = SSL_CLOSED;
- }
- }
- else if (ssl->state == NEGOTIATING && ssl->app_input_closed) {
- ssl->app_output_closed = PN_EOS;
- ssl->state = SSL_CLOSED;
- }
- }
- } while (work_pending);
-
- if (written == 0 && ssl->state == SSL_CLOSED) {
- written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
- if (transport->io_layers[layer]==&ssl_input_closed_layer) {
- transport->io_layers[layer] = &ssl_closed_layer;
- } else {
- transport->io_layers[layer] = &ssl_output_closed_layer;
- }
- }
- ssl_log(transport, "process_output_ssl() returning %d\n", (int) written);
- return written;
-}
-
-
-static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
-{
- return PN_EOS;
-}
-
-static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
-{
- return PN_EOS;
-}
-
-// return # output bytes sitting in this layer
-static size_t buffered_output(pn_transport_t *transport)
-{
- size_t count = 0;
- pni_ssl_t *ssl = transport->ssl;
- if (ssl) {
- count += ssl->network_out_pending;
- if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
- count++;
- }
- return count;
-}
-
-static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error) {
- *error = 0;
- DWORD sys_store_type = 0;
- HCERTSTORE cert_store = 0;
-
- if (store_name) {
- if (strncmp(store_name, "ss:", 3) == 0) {
- store_name += 3;
- sys_store_type = CERT_SYSTEM_STORE_CURRENT_USER;
- }
- else if (strncmp(store_name, "lmss:", 5) == 0) {
- store_name += 5;
- sys_store_type = CERT_SYSTEM_STORE_LOCAL_MACHINE;
- }
- }
-
- if (sys_store_type) {
- // Opening a system store, names are not case sensitive.
- // Map confusing GUI name to actual registry store name.
- if (!pn_strcasecmp(store_name, "personal")) store_name= "my";
- cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, NULL,
- CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG |
- sys_store_type, store_name);
- if (!cert_store) {
- ssl_log_error_status(GetLastError(), "Failed to open system certificate store %s", store_name);
- *error = -3;
- return NULL;
- }
- } else {
- // PKCS#12 file
- HANDLE cert_file = CreateFile(store_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (INVALID_HANDLE_VALUE == cert_file) {
- HRESULT status = GetLastError();
- ssl_log_error_status(status, "Failed to open the file holding the private key: %s", store_name);
- *error = -4;
- return NULL;
- }
- DWORD nread = 0L;
- const DWORD file_size = GetFileSize(cert_file, NULL);
- char *buf = NULL;
- if (INVALID_FILE_SIZE != file_size)
- buf = (char *) malloc(file_size);
- if (!buf || !ReadFile(cert_file, buf, file_size, &nread, NULL)
- || file_size != nread) {
- HRESULT status = GetLastError();
- CloseHandle(cert_file);
- free(buf);
- ssl_log_error_status(status, "Reading the private key from file failed %s", store_name);
- *error = -5;
- return NULL;
- }
- CloseHandle(cert_file);
-
- CRYPT_DATA_BLOB blob;
- blob.cbData = nread;
- blob.pbData = (BYTE *) buf;
-
- wchar_t *pwUCS2 = NULL;
- int pwlen = 0;
- if (passwd) {
- // convert passwd to null terminated wchar_t (Windows UCS2)
- pwlen = strlen(passwd);
- pwUCS2 = (wchar_t *) calloc(pwlen + 1, sizeof(wchar_t));
- int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, passwd, pwlen, &pwUCS2[0], pwlen);
- if (!nwc) {
- ssl_log_error_status(GetLastError(), "Error converting password from UTF8");
- free(buf);
- free(pwUCS2);
- *error = -6;
- return NULL;
- }
- }
-
- cert_store = PFXImportCertStore(&blob, pwUCS2, 0);
- if (pwUCS2) {
- SecureZeroMemory(pwUCS2, pwlen * sizeof(wchar_t));
- free(pwUCS2);
- }
- if (cert_store == NULL) {
- ssl_log_error_status(GetLastError(), "Failed to import the file based certificate store");
- free(buf);
- *error = -7;
- return NULL;
- }
-
- free(buf);
- }
-
- return cert_store;
-}
-
-static bool store_contains(HCERTSTORE store, PCCERT_CONTEXT cert)
-{
- DWORD find_type = CERT_FIND_EXISTING; // Require exact match
- PCCERT_CONTEXT tcert = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- 0, find_type, cert, 0);
- if (tcert) {
- CertFreeCertificateContext(tcert);
- return true;
- }
- return false;
-}
-
-/* Match the DNS name pattern from the peer certificate against our configured peer
- hostname */
-static bool match_dns_pattern(const char *hostname, const char *pattern, int plen)
-{
- int slen = (int) strlen(hostname);
- if (memchr( pattern, '*', plen ) == NULL)
- return (plen == slen &&
- pn_strncasecmp( pattern, hostname, plen ) == 0);
-
- /* dns wildcarded pattern - RFC2818 */
- char plabel[64]; /* max label length < 63 - RFC1034 */
- char slabel[64];
-
- while (plen > 0 && slen > 0) {
- const char *cptr;
- int len;
-
- cptr = (const char *) memchr( pattern, '.', plen );
- len = (cptr) ? cptr - pattern : plen;
- if (len > (int) sizeof(plabel) - 1) return false;
- memcpy( plabel, pattern, len );
- plabel[len] = 0;
- if (cptr) ++len; // skip matching '.'
- pattern += len;
- plen -= len;
-
- cptr = (const char *) memchr( hostname, '.', slen );
- len = (cptr) ? cptr - hostname : slen;
- if (len > (int) sizeof(slabel) - 1) return false;
- memcpy( slabel, hostname, len );
- slabel[len] = 0;
- if (cptr) ++len; // skip matching '.'
- hostname += len;
- slen -= len;
-
- char *star = strchr( plabel, '*' );
- if (!star) {
- if (pn_strcasecmp( plabel, slabel )) return false;
- } else {
- *star = '\0';
- char *prefix = plabel;
- int prefix_len = strlen(prefix);
- char *suffix = star + 1;
- int suffix_len = strlen(suffix);
- if (prefix_len && pn_strncasecmp( prefix, slabel, prefix_len )) return false;
- if (suffix_len && pn_strncasecmp( suffix,
- slabel + (strlen(slabel) - suffix_len),
- suffix_len )) return false;
- }
- }
-
- return plen == slen;
-}
-
-// Caller must free the returned buffer
-static char* wide_to_utf8(LPWSTR wstring)
-{
- int len = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, 0, 0, 0, 0);
- if (!len) {
- ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
- return NULL;
- }
- char *p = (char *) malloc(len);
- if (!p) return NULL;
- if (WideCharToMultiByte(CP_UTF8, 0, wstring, -1, p, len, 0, 0))
- return p;
- ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
- free (p);
- return NULL;
-}
-
-static bool server_name_matches(const char *server_name, CERT_EXTENSION *alt_name_ext, PCCERT_CONTEXT cert)
-{
- // As for openssl.c: alt names first, then CN
- bool matched = false;
-
- if (alt_name_ext) {
- CERT_ALT_NAME_INFO* alt_name_info = NULL;
- DWORD size = 0;
- if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME2,
- alt_name_ext->Value.pbData, alt_name_ext->Value.cbData,
- CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
- 0, &alt_name_info, &size)) {
- ssl_log_error_status(GetLastError(), "Alternative name match internal error");
- return false;
- }
-
- int name_ct = alt_name_info->cAltEntry;
- for (int i = 0; !matched && i < name_ct; ++i) {
- if (alt_name_info->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) {
- char *alt_name = wide_to_utf8(alt_name_info->rgAltEntry[i].pwszDNSName);
- if (alt_name) {
- matched = match_dns_pattern(server_name, (const char *) alt_name, strlen(alt_name));
- free(alt_name);
- }
- }
- }
- LocalFree(&alt_name_info);
- }
-
- if (!matched) {
- PCERT_INFO info = cert->pCertInfo;
- DWORD len = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, 0, 0);
- char *name = (char *) malloc(len);
- if (name) {
- int count = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, name, len);
- if (count)
- matched = match_dns_pattern(server_name, (const char *) name, strlen(name));
- free(name);
- }
- }
- return matched;
-}
-
-const char* pn_ssl_get_remote_subject_subfield(pn_ssl_t *ssl0, pn_ssl_cert_subject_subfield field)
-{
- return NULL;
-}
-
-int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0,
- char *fingerprint,
- size_t fingerprint_length,
- pn_ssl_hash_alg hash_alg)
-{
- return -1;
-}
-
-static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing)
-{
- // Free/release the following before return:
- PCCERT_CONTEXT peer_cc = 0;
- PCCERT_CONTEXT trust_anchor = 0;
- PCCERT_CHAIN_CONTEXT chain_context = 0;
- wchar_t *nameUCS2 = 0;
-
- if (server_name && strlen(server_name) > 255) {
- ssl_log_error("invalid server name: %s\n", server_name);
- return WSAENAMETOOLONG;
- }
-
- // Get peer's certificate.
- SECURITY_STATUS status;
- status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
- if (status != SEC_E_OK) {
- ssl_log_error_status(status, "can't obtain remote peer certificate information");
- return status;
- }
-
- // Build the peer's certificate chain. Multiple chains may be built but we
- // care about rgpChain[0], which is the best. Custom root stores are not
- // allowed until W8/server 2012: see CERT_CHAIN_ENGINE_CONFIG. For now, we
- // manually override to taste.
-
- // Chain verification functions give false reports for CRL if the trust anchor
- // is not in the official root store. We ignore CRL completely if it doesn't
- // apply to any untrusted certs in the chain, and defer to SChannel's veto
- // otherwise. To rely on CRL, the CA must be in both the official system
- // trusted root store and the Proton cred->trust_store. To defeat CRL, the
- // most distal cert with CRL must be placed in the Proton cred->trust_store.
- // Similarly, certificate usage checking is overly strict at times.
-
- CERT_CHAIN_PARA desc;
- memset(&desc, 0, sizeof(desc));
- desc.cbSize = sizeof(desc);
-
- LPSTR usages[] = { szOID_PKIX_KP_SERVER_AUTH };
- DWORD n_usages = sizeof(usages) / sizeof(LPSTR);
- desc.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
- desc.RequestedUsage.Usage.cUsageIdentifier = n_usages;
- desc.RequestedUsage.Usage.rgpszUsageIdentifier = usages;
-
- if(!CertGetCertificateChain(0, peer_cc, 0, peer_cc->hCertStore, &desc,
- CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT |
- CERT_CHAIN_CACHE_END_CERT,
- 0, &chain_context)){
- HRESULT st = GetLastError();
- ssl_log_error_status(st, "Basic certificate chain check failed");
- CertFreeCertificateContext(peer_cc);
- return st;
- }
- if (chain_context->cChain < 1 || chain_context->rgpChain[0]->cElement < 1) {
- ssl_log_error("empty chain with status %x %x\n", chain_context->TrustStatus.dwErrorStatus,
- chain_context->TrustStatus.dwInfoStatus);
- return SEC_E_CERT_UNKNOWN;
- }
-
- int chain_len = chain_context->rgpChain[0]->cElement;
- PCCERT_CONTEXT leaf_cert = chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
- PCCERT_CONTEXT trunk_cert = chain_context->rgpChain[0]->rgpElement[chain_len - 1]->pCertContext;
- if (tracing)
- // See doc for CERT_CHAIN_POLICY_STATUS for bit field error and info status values
- ssl_log_error("status for complete chain: error bits %x info bits %x\n",
- chain_context->TrustStatus.dwErrorStatus, chain_context->TrustStatus.dwInfoStatus);
-
- // Supplement with checks against Proton's trusted_ca_db, custom revocation and usage.
- HRESULT error = 0;
- do {
- // Do not return from this do loop. Set error = SEC_E_XXX and break.
- bool revocable = false; // unless we see any untrusted certs that could be
- for (int i = 0; i < chain_len; i++) {
- CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[i];
- PCCERT_CONTEXT cc = ce->pCertContext;
- if (cc->pCertInfo->dwVersion != CERT_V3) {
- if (tracing)
- ssl_log_error("certificate chain element %d is not version 3\n", i);
- error = SEC_E_CERT_WRONG_USAGE; // A fossil
- break;
- }
-
- if (!trust_anchor && store_contains(root_store, cc))
- trust_anchor = CertDuplicateCertificateContext(cc);
-
- int n_ext = cc->pCertInfo->cExtension;
- for (int ii = 0; ii < n_ext && !revocable && !trust_anchor; ii++) {
- CERT_EXTENSION *p = &cc->pCertInfo->rgExtension[ii];
- // rfc 5280 extensions for revocation
- if (!strcmp(p->pszObjId, szOID_AUTHORITY_INFO_ACCESS) ||
- !strcmp(p->pszObjId, szOID_CRL_DIST_POINTS) ||
- !strcmp(p->pszObjId, szOID_FRESHEST_CRL)) {
- revocable = true;
- }
- }
-
- if (tracing) {
- char name[512];
- const char *is_anchor = (cc == trust_anchor) ? " trust anchor" : "";
- if (!CertNameToStr(cc->dwCertEncodingType, &cc->pCertInfo->Subject,
- CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG, name, sizeof(name)))
- strcpy(name, "[too long]");
- ssl_log_error("element %d (name: %s)%s error bits %x info bits %x\n", i, name, is_anchor,
- ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
- }
- }
- if (error)
- break;
-
- if (!trust_anchor) {
- // We don't trust any of the certs in the chain, see if the last cert
- // is issued by a Proton trusted CA.
- DWORD flags = CERT_STORE_NO_ISSUER_FLAG || CERT_STORE_SIGNATURE_FLAG ||
- CERT_STORE_TIME_VALIDITY_FLAG;
- trust_anchor = CertGetIssuerCertificateFromStore(root_store, trunk_cert, 0, &flags);
- if (trust_anchor) {
- if (tracing) {
- if (flags & CERT_STORE_SIGNATURE_FLAG)
- ssl_log_error("root certificate signature failure\n");
- if (flags & CERT_STORE_TIME_VALIDITY_FLAG)
- ssl_log_error("root certificate time validity failure\n");
- }
- if (flags) {
- CertFreeCertificateContext(trust_anchor);
- trust_anchor = 0;
- }
- }
- }
- if (!trust_anchor) {
- error = SEC_E_UNTRUSTED_ROOT;
- break;
- }
-
- bool strict_usage = false;
- CERT_EXTENSION *leaf_alt_names = 0;
- if (leaf_cert != trust_anchor) {
- int n_ext = leaf_cert->pCertInfo->cExtension;
- for (int ii = 0; ii < n_ext; ii++) {
- CERT_EXTENSION *p = &leaf_cert->pCertInfo->rgExtension[ii];
- if (!strcmp(p->pszObjId, szOID_ENHANCED_KEY_USAGE))
- strict_usage = true;
- if (!strcmp(p->pszObjId, szOID_SUBJECT_ALT_NAME2))
- if (p->Value.pbData)
- leaf_alt_names = p;
- }
- }
-
- if (server_name) {
- int len = strlen(server_name);
- nameUCS2 = (wchar_t *) calloc(len + 1, sizeof(wchar_t));
- int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, server_name, len, &nameUCS2[0], len);
- if (!nwc) {
- error = GetLastError();
- ssl_log_error_status(error, "Error converting server name from UTF8");
- break;
- }
- }
-
- // SSL-specific parameters (ExtraPolicy below)
- SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_desc;
- memset(&ssl_desc, 0, sizeof(ssl_desc));
- ssl_desc.cbSize = sizeof(ssl_desc);
- ssl_desc.pwszServerName = nameUCS2;
- ssl_desc.dwAuthType = nameUCS2 ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT;
- ssl_desc.fdwChecks = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
- if (server_name)
- ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
- if (!revocable)
- ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_REVOCATION;
- if (!strict_usage)
- ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_WRONG_USAGE;
-
- // General certificate chain parameters
- CERT_CHAIN_POLICY_PARA chain_desc;
- memset(&chain_desc, 0, sizeof(chain_desc));
- chain_desc.cbSize = sizeof(chain_desc);
- chain_desc.dwFlags = CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG;
- if (!revocable)
- chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
- if (!strict_usage)
- chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
- chain_desc.pvExtraPolicyPara = &ssl_desc;
-
- CERT_CHAIN_POLICY_STATUS chain_status;
- memset(&chain_status, 0, sizeof(chain_status));
- chain_status.cbSize = sizeof(chain_status);
-
- if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context,
- &chain_desc, &chain_status)) {
- error = GetLastError();
- // Failure to complete the check, does not (in)validate the cert.
- ssl_log_error_status(error, "Supplemental certificate chain check failed");
- break;
- }
-
- if (chain_status.dwError) {
- error = chain_status.dwError;
- if (tracing) {
- ssl_log_error_status(chain_status.dwError, "Certificate chain verification error");
- if (chain_status.lChainIndex == 0 && chain_status.lElementIndex != -1) {
- int idx = chain_status.lElementIndex;
- CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[idx];
- ssl_log_error(" chain failure at %d error/info: %x %x\n", idx,
- ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
- }
- }
- break;
- }
-
- if (server_name && ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME &&
- !server_name_matches(server_name, leaf_alt_names, leaf_cert)) {
- error = SEC_E_WRONG_PRINCIPAL;
- break;
- }
- else if (ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME && !server_name) {
- ssl_log_error("Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
- error = SEC_E_WRONG_PRINCIPAL;
- break;
- }
- } while (0);
-
- if (tracing && !error)
- ssl_log_error("peer certificate authenticated\n");
-
- // Lots to clean up.
- if (peer_cc)
- CertFreeCertificateContext(peer_cc);
- if (trust_anchor)
- CertFreeCertificateContext(trust_anchor);
- if (chain_context)
- CertFreeCertificateChain(chain_context);
- free(nameUCS2);
- return error;
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[16/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/codec.c b/proton-c/src/core/codec.c
new file mode 100644
index 0000000..67769ad
--- /dev/null
+++ b/proton-c/src/core/codec.c
@@ -0,0 +1,2141 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <proton/codec.h>
+#include <proton/error.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "encodings.h"
+#define DEFINE_FIELDS
+#include "protocol.h"
+#include "platform/platform_fmt.h"
+#include "util.h"
+#include "decoder.h"
+#include "encoder.h"
+#include "data.h"
+#include "log_private.h"
+
+const char *pn_type_name(pn_type_t type)
+{
+ switch (type)
+ {
+ case PN_NULL: return "PN_NULL";
+ case PN_BOOL: return "PN_BOOL";
+ case PN_UBYTE: return "PN_UBYTE";
+ case PN_BYTE: return "PN_BYTE";
+ case PN_USHORT: return "PN_USHORT";
+ case PN_SHORT: return "PN_SHORT";
+ case PN_UINT: return "PN_UINT";
+ case PN_INT: return "PN_INT";
+ case PN_CHAR: return "PN_CHAR";
+ case PN_ULONG: return "PN_ULONG";
+ case PN_LONG: return "PN_LONG";
+ case PN_TIMESTAMP: return "PN_TIMESTAMP";
+ case PN_FLOAT: return "PN_FLOAT";
+ case PN_DOUBLE: return "PN_DOUBLE";
+ case PN_DECIMAL32: return "PN_DECIMAL32";
+ case PN_DECIMAL64: return "PN_DECIMAL64";
+ case PN_DECIMAL128: return "PN_DECIMAL128";
+ case PN_UUID: return "PN_UUID";
+ case PN_BINARY: return "PN_BINARY";
+ case PN_STRING: return "PN_STRING";
+ case PN_SYMBOL: return "PN_SYMBOL";
+ case PN_DESCRIBED: return "PN_DESCRIBED";
+ case PN_ARRAY: return "PN_ARRAY";
+ case PN_LIST: return "PN_LIST";
+ case PN_MAP: return "PN_MAP";
+ default: break;
+ }
+
+ return "<UNKNOWN>";
+}
+
+static inline void pni_atom_init(pn_atom_t *atom, pn_type_t type)
+{
+ memset(atom, 0, sizeof(pn_atom_t));
+ atom->type = type;
+}
+
+// data
+
+static void pn_data_finalize(void *object)
+{
+ pn_data_t *data = (pn_data_t *) object;
+ free(data->nodes);
+ pn_buffer_free(data->buf);
+ pn_free(data->str);
+ pn_error_free(data->error);
+ pn_free(data->decoder);
+ pn_free(data->encoder);
+}
+
+static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
+{
+ if (!node) return NULL;
+ if (node->atom.type != PN_DESCRIBED) return NULL;
+
+ pni_node_t *descriptor = pn_data_node(data, node->down);
+
+ if (!descriptor || descriptor->atom.type != PN_ULONG) {
+ return NULL;
+ }
+
+ if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong <= FIELD_MAX) {
+ const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN];
+ return (f->name_index!=0) ? f : NULL;
+ } else {
+ return NULL;
+ }
+}
+
+static int pni_node_index(pn_data_t *data, pni_node_t *node)
+{
+ int count = 0;
+ while (node) {
+ node = pn_data_node(data, node->prev);
+ count++;
+ }
+ return count - 1;
+}
+
+int pni_inspect_atom(pn_atom_t *atom, pn_string_t *str)
+{
+ switch (atom->type) {
+ case PN_NULL:
+ return pn_string_addf(str, "null");
+ case PN_BOOL:
+ return pn_string_addf(str, atom->u.as_bool ? "true" : "false");
+ case PN_UBYTE:
+ return pn_string_addf(str, "%" PRIu8, atom->u.as_ubyte);
+ case PN_BYTE:
+ return pn_string_addf(str, "%" PRIi8, atom->u.as_byte);
+ case PN_USHORT:
+ return pn_string_addf(str, "%" PRIu16, atom->u.as_ushort);
+ case PN_SHORT:
+ return pn_string_addf(str, "%" PRIi16, atom->u.as_short);
+ case PN_UINT:
+ return pn_string_addf(str, "%" PRIu32, atom->u.as_uint);
+ case PN_INT:
+ return pn_string_addf(str, "%" PRIi32, atom->u.as_int);
+ case PN_CHAR:
+ return pn_string_addf(str, "%c", atom->u.as_char);
+ case PN_ULONG:
+ return pn_string_addf(str, "%" PRIu64, atom->u.as_ulong);
+ case PN_LONG:
+ return pn_string_addf(str, "%" PRIi64, atom->u.as_long);
+ case PN_TIMESTAMP:
+ return pn_string_addf(str, "%" PRIi64, atom->u.as_timestamp);
+ case PN_FLOAT:
+ return pn_string_addf(str, "%g", atom->u.as_float);
+ case PN_DOUBLE:
+ return pn_string_addf(str, "%g", atom->u.as_double);
+ case PN_DECIMAL32:
+ return pn_string_addf(str, "D32(%" PRIu32 ")", atom->u.as_decimal32);
+ case PN_DECIMAL64:
+ return pn_string_addf(str, "D64(%" PRIu64 ")", atom->u.as_decimal64);
+ case PN_DECIMAL128:
+ return pn_string_addf(str, "D128(%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+ "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+ "%02hhx%02hhx)",
+ atom->u.as_decimal128.bytes[0],
+ atom->u.as_decimal128.bytes[1],
+ atom->u.as_decimal128.bytes[2],
+ atom->u.as_decimal128.bytes[3],
+ atom->u.as_decimal128.bytes[4],
+ atom->u.as_decimal128.bytes[5],
+ atom->u.as_decimal128.bytes[6],
+ atom->u.as_decimal128.bytes[7],
+ atom->u.as_decimal128.bytes[8],
+ atom->u.as_decimal128.bytes[9],
+ atom->u.as_decimal128.bytes[10],
+ atom->u.as_decimal128.bytes[11],
+ atom->u.as_decimal128.bytes[12],
+ atom->u.as_decimal128.bytes[13],
+ atom->u.as_decimal128.bytes[14],
+ atom->u.as_decimal128.bytes[15]);
+ case PN_UUID:
+ return pn_string_addf(str, "UUID(%02hhx%02hhx%02hhx%02hhx-"
+ "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
+ "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx)",
+ atom->u.as_uuid.bytes[0],
+ atom->u.as_uuid.bytes[1],
+ atom->u.as_uuid.bytes[2],
+ atom->u.as_uuid.bytes[3],
+ atom->u.as_uuid.bytes[4],
+ atom->u.as_uuid.bytes[5],
+ atom->u.as_uuid.bytes[6],
+ atom->u.as_uuid.bytes[7],
+ atom->u.as_uuid.bytes[8],
+ atom->u.as_uuid.bytes[9],
+ atom->u.as_uuid.bytes[10],
+ atom->u.as_uuid.bytes[11],
+ atom->u.as_uuid.bytes[12],
+ atom->u.as_uuid.bytes[13],
+ atom->u.as_uuid.bytes[14],
+ atom->u.as_uuid.bytes[15]);
+ case PN_BINARY:
+ case PN_STRING:
+ case PN_SYMBOL:
+ {
+ int err;
+ const char *pfx;
+ pn_bytes_t bin = atom->u.as_bytes;
+ bool quote;
+ switch (atom->type) {
+ case PN_BINARY:
+ pfx = "b";
+ quote = true;
+ break;
+ case PN_STRING:
+ pfx = "";
+ quote = true;
+ break;
+ case PN_SYMBOL:
+ pfx = ":";
+ quote = false;
+ for (unsigned i = 0; i < bin.size; i++) {
+ if (!isalpha(bin.start[i])) {
+ quote = true;
+ break;
+ }
+ }
+ break;
+ default:
+ assert(false);
+ return PN_ERR;
+ }
+
+ if ((err = pn_string_addf(str, "%s", pfx))) return err;
+ if (quote) if ((err = pn_string_addf(str, "\""))) return err;
+ if ((err = pn_quote(str, bin.start, bin.size))) return err;
+ if (quote) if ((err = pn_string_addf(str, "\""))) return err;
+ return 0;
+ }
+ case PN_LIST:
+ return pn_string_addf(str, "<list>");
+ case PN_MAP:
+ return pn_string_addf(str, "<map>");
+ case PN_ARRAY:
+ return pn_string_addf(str, "<array>");
+ case PN_DESCRIBED:
+ return pn_string_addf(str, "<described>");
+ default:
+ return pn_string_addf(str, "<undefined: %i>", atom->type);
+ }
+}
+
+int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+ pn_string_t *str = (pn_string_t *) ctx;
+ pn_atom_t *atom = (pn_atom_t *) &node->atom;
+
+ pni_node_t *parent = pn_data_node(data, node->parent);
+ const pn_fields_t *fields = pni_node_fields(data, parent);
+ pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
+ const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+ int index = pni_node_index(data, node);
+
+ int err;
+
+ if (grandfields) {
+ if (atom->type == PN_NULL) {
+ return 0;
+ }
+ const char *name = (index < grandfields->field_count)
+ ? FIELD_STRINGPOOL.STRING0+FIELD_FIELDS[grandfields->first_field_index+index]
+ : NULL;
+ if (name) {
+ err = pn_string_addf(str, "%s=", name);
+ if (err) return err;
+ }
+ }
+
+ switch (atom->type) {
+ case PN_DESCRIBED:
+ return pn_string_addf(str, "@");
+ case PN_ARRAY:
+ // XXX: need to fix for described arrays
+ return pn_string_addf(str, "@%s[", pn_type_name(node->type));
+ case PN_LIST:
+ return pn_string_addf(str, "[");
+ case PN_MAP:
+ return pn_string_addf(str, "{");
+ default:
+ if (fields && index == 0) {
+ err = pn_string_addf(str, "%s", FIELD_STRINGPOOL.STRING0+FIELD_NAME[fields->name_index]);
+ if (err) return err;
+ err = pn_string_addf(str, "(");
+ if (err) return err;
+ err = pni_inspect_atom(atom, str);
+ if (err) return err;
+ return pn_string_addf(str, ")");
+ } else {
+ return pni_inspect_atom(atom, str);
+ }
+ }
+}
+
+pni_node_t *pni_next_nonnull(pn_data_t *data, pni_node_t *node)
+{
+ while (node) {
+ node = pn_data_node(data, node->next);
+ if (node && node->atom.type != PN_NULL) {
+ return node;
+ }
+ }
+
+ return NULL;
+}
+
+int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+ pn_string_t *str = (pn_string_t *) ctx;
+ pni_node_t *parent = pn_data_node(data, node->parent);
+ pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
+ const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+ pni_node_t *next = pn_data_node(data, node->next);
+ int err;
+
+ switch (node->atom.type) {
+ case PN_ARRAY:
+ case PN_LIST:
+ err = pn_string_addf(str, "]");
+ if (err) return err;
+ break;
+ case PN_MAP:
+ err = pn_string_addf(str, "}");
+ if (err) return err;
+ break;
+ default:
+ break;
+ }
+
+ if (!grandfields || node->atom.type != PN_NULL) {
+ if (next) {
+ int index = pni_node_index(data, node);
+ if (parent && parent->atom.type == PN_MAP && (index % 2) == 0) {
+ err = pn_string_addf(str, "=");
+ } else if (parent && parent->atom.type == PN_DESCRIBED && index == 0) {
+ err = pn_string_addf(str, " ");
+ if (err) return err;
+ } else {
+ if (!grandfields || pni_next_nonnull(data, node)) {
+ err = pn_string_addf(str, ", ");
+ if (err) return err;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int pn_data_inspect(void *obj, pn_string_t *dst)
+{
+ pn_data_t *data = (pn_data_t *) obj;
+
+ return pni_data_traverse(data, pni_inspect_enter, pni_inspect_exit, dst);
+}
+
+#define pn_data_initialize NULL
+#define pn_data_hashcode NULL
+#define pn_data_compare NULL
+
+pn_data_t *pn_data(size_t capacity)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_data);
+ pn_data_t *data = (pn_data_t *) pn_class_new(&clazz, sizeof(pn_data_t));
+ data->capacity = capacity;
+ data->size = 0;
+ data->nodes = capacity ? (pni_node_t *) malloc(capacity * sizeof(pni_node_t)) : NULL;
+ data->buf = pn_buffer(64);
+ data->parent = 0;
+ data->current = 0;
+ data->base_parent = 0;
+ data->base_current = 0;
+ data->decoder = pn_decoder();
+ data->encoder = pn_encoder();
+ data->error = pn_error();
+ data->str = pn_string(NULL);
+ return data;
+}
+
+void pn_data_free(pn_data_t *data)
+{
+ pn_free(data);
+}
+
+int pn_data_errno(pn_data_t *data)
+{
+ return pn_error_code(data->error);
+}
+
+pn_error_t *pn_data_error(pn_data_t *data)
+{
+ return data->error;
+}
+
+size_t pn_data_size(pn_data_t *data)
+{
+ return data ? data->size : 0;
+}
+
+void pn_data_clear(pn_data_t *data)
+{
+ if (data) {
+ data->size = 0;
+ data->parent = 0;
+ data->current = 0;
+ data->base_parent = 0;
+ data->base_current = 0;
+ pn_buffer_clear(data->buf);
+ }
+}
+
+static int pni_data_grow(pn_data_t *data)
+{
+ size_t capacity = data->capacity ? data->capacity : 2;
+ if (capacity >= PNI_NID_MAX) return PN_OUT_OF_MEMORY;
+ else if (capacity < PNI_NID_MAX/2) capacity *= 2;
+ else capacity = PNI_NID_MAX;
+
+ pni_node_t *new_nodes = (pni_node_t *)realloc(data->nodes, capacity * sizeof(pni_node_t));
+ if (new_nodes == NULL) return PN_OUT_OF_MEMORY;
+ data->capacity = capacity;
+ data->nodes = new_nodes;
+ return 0;
+}
+
+static ssize_t pni_data_intern(pn_data_t *data, const char *start, size_t size)
+{
+ size_t offset = pn_buffer_size(data->buf);
+ int err = pn_buffer_append(data->buf, start, size);
+ if (err) return err;
+ err = pn_buffer_append(data->buf, "\0", 1);
+ if (err) return err;
+ return offset;
+}
+
+static pn_bytes_t *pni_data_bytes(pn_data_t *data, pni_node_t *node)
+{
+ switch (node->atom.type) {
+ case PN_BINARY:
+ case PN_STRING:
+ case PN_SYMBOL:
+ return &node->atom.u.as_bytes;
+ default: return NULL;
+ }
+}
+
+static void pni_data_rebase(pn_data_t *data, char *base)
+{
+ for (unsigned i = 0; i < data->size; i++) {
+ pni_node_t *node = &data->nodes[i];
+ if (node->data) {
+ pn_bytes_t *bytes = pni_data_bytes(data, node);
+ bytes->start = base + node->data_offset;
+ }
+ }
+}
+
+static int pni_data_intern_node(pn_data_t *data, pni_node_t *node)
+{
+ pn_bytes_t *bytes = pni_data_bytes(data, node);
+ if (!bytes) return 0;
+ size_t oldcap = pn_buffer_capacity(data->buf);
+ ssize_t offset = pni_data_intern(data, bytes->start, bytes->size);
+ if (offset < 0) return offset;
+ node->data = true;
+ node->data_offset = offset;
+ node->data_size = bytes->size;
+ pn_rwbytes_t buf = pn_buffer_memory(data->buf);
+ bytes->start = buf.start + offset;
+
+ if (pn_buffer_capacity(data->buf) != oldcap) {
+ pni_data_rebase(data, buf.start);
+ }
+
+ return 0;
+}
+
+int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap)
+{
+ int err = 0;
+ const char *begin = fmt;
+ while (*fmt) {
+ char code = *(fmt++);
+ if (!code) return 0;
+
+ switch (code) {
+ case 'n':
+ err = pn_data_put_null(data);
+ break;
+ case 'o':
+ err = pn_data_put_bool(data, va_arg(ap, int));
+ break;
+ case 'B':
+ err = pn_data_put_ubyte(data, va_arg(ap, unsigned int));
+ break;
+ case 'b':
+ err = pn_data_put_byte(data, va_arg(ap, int));
+ break;
+ case 'H':
+ err = pn_data_put_ushort(data, va_arg(ap, unsigned int));
+ break;
+ case 'h':
+ err = pn_data_put_short(data, va_arg(ap, int));
+ break;
+ case 'I':
+ err = pn_data_put_uint(data, va_arg(ap, uint32_t));
+ break;
+ case 'i':
+ err = pn_data_put_int(data, va_arg(ap, uint32_t));
+ break;
+ case 'L':
+ err = pn_data_put_ulong(data, va_arg(ap, uint64_t));
+ break;
+ case 'l':
+ err = pn_data_put_long(data, va_arg(ap, int64_t));
+ break;
+ case 't':
+ err = pn_data_put_timestamp(data, va_arg(ap, pn_timestamp_t));
+ break;
+ case 'f':
+ err = pn_data_put_float(data, va_arg(ap, double));
+ break;
+ case 'd':
+ err = pn_data_put_double(data, va_arg(ap, double));
+ break;
+ case 'z':
+ {
+ // For maximum portability, caller must pass these as two separate args, not a single struct
+ size_t size = va_arg(ap, size_t);
+ char *start = va_arg(ap, char *);
+ if (start) {
+ err = pn_data_put_binary(data, pn_bytes(size, start));
+ } else {
+ err = pn_data_put_null(data);
+ }
+ }
+ break;
+ case 'S':
+ case 's':
+ {
+ char *start = va_arg(ap, char *);
+ size_t size;
+ if (start) {
+ size = strlen(start);
+ if (code == 'S') {
+ err = pn_data_put_string(data, pn_bytes(size, start));
+ } else {
+ err = pn_data_put_symbol(data, pn_bytes(size, start));
+ }
+ } else {
+ err = pn_data_put_null(data);
+ }
+ }
+ break;
+ case 'D':
+ err = pn_data_put_described(data);
+ pn_data_enter(data);
+ break;
+ case 'T':
+ {
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ if (parent->atom.type == PN_ARRAY) {
+ parent->type = (pn_type_t) va_arg(ap, int);
+ } else {
+ return pn_error_format(data->error, PN_ERR, "naked type");
+ }
+ }
+ break;
+ case '@':
+ {
+ bool described;
+ if (*(fmt + 1) == 'D') {
+ fmt++;
+ described = true;
+ } else {
+ described = false;
+ }
+ err = pn_data_put_array(data, described, (pn_type_t) 0);
+ pn_data_enter(data);
+ }
+ break;
+ case '[':
+ if (fmt < (begin + 2) || *(fmt - 2) != 'T') {
+ err = pn_data_put_list(data);
+ if (err) return err;
+ pn_data_enter(data);
+ }
+ break;
+ case '{':
+ err = pn_data_put_map(data);
+ if (err) return err;
+ pn_data_enter(data);
+ break;
+ case '}':
+ case ']':
+ if (!pn_data_exit(data))
+ return pn_error_format(data->error, PN_ERR, "exit failed");
+ break;
+ case '?':
+ if (!va_arg(ap, int)) {
+ err = pn_data_put_null(data);
+ if (err) return err;
+ pn_data_enter(data);
+ }
+ break;
+ case '*':
+ {
+ int count = va_arg(ap, int);
+ void *ptr = va_arg(ap, void *);
+
+ char c = *(fmt++);
+
+ switch (c)
+ {
+ case 's':
+ {
+ char **sptr = (char **) ptr;
+ for (int i = 0; i < count; i++)
+ {
+ char *sym = *(sptr++);
+ err = pn_data_fill(data, "s", sym);
+ if (err) return err;
+ }
+ }
+ break;
+ default:
+ pn_logf("unrecognized * code: 0x%.2X '%c'", code, code);
+ return PN_ARG_ERR;
+ }
+ }
+ break;
+ case 'C':
+ {
+ pn_data_t *src = va_arg(ap, pn_data_t *);
+ if (src && pn_data_size(src) > 0) {
+ err = pn_data_appendn(data, src, 1);
+ if (err) return err;
+ } else {
+ err = pn_data_put_null(data);
+ if (err) return err;
+ }
+ }
+ break;
+ default:
+ pn_logf("unrecognized fill code: 0x%.2X '%c'", code, code);
+ return PN_ARG_ERR;
+ }
+
+ if (err) return err;
+
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ while (parent) {
+ if (parent->atom.type == PN_DESCRIBED && parent->children == 2) {
+ pn_data_exit(data);
+ parent = pn_data_node(data, data->parent);
+ } else if (parent->atom.type == PN_NULL && parent->children == 1) {
+ pn_data_exit(data);
+ pni_node_t *current = pn_data_node(data, data->current);
+ current->down = 0;
+ current->children = 0;
+ parent = pn_data_node(data, data->parent);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int pn_data_fill(pn_data_t *data, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int err = pn_data_vfill(data, fmt, ap);
+ va_end(ap);
+ return err;
+}
+
+static bool pn_scan_next(pn_data_t *data, pn_type_t *type, bool suspend)
+{
+ if (suspend) return false;
+ bool found = pn_data_next(data);
+ if (found) {
+ *type = pn_data_type(data);
+ return true;
+ } else {
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ if (parent && parent->atom.type == PN_DESCRIBED) {
+ pn_data_exit(data);
+ return pn_scan_next(data, type, suspend);
+ } else {
+ *type = PN_INVALID;
+ return false;
+ }
+ }
+}
+
+static pni_node_t *pni_data_peek(pn_data_t *data);
+
+int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap)
+{
+ pn_data_rewind(data);
+ bool *scanarg = NULL;
+ bool at = false;
+ int level = 0;
+ int count_level = -1;
+ int resume_count = 0;
+
+ while (*fmt) {
+ char code = *(fmt++);
+
+ bool found = false;
+ pn_type_t type;
+
+ bool scanned = false;
+ bool suspend = resume_count > 0;
+
+ switch (code) {
+ case 'n':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_NULL) {
+ scanned = true;
+ } else {
+ scanned = false;
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'o':
+ {
+ bool *value = va_arg(ap, bool *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_BOOL) {
+ *value = pn_data_get_bool(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'B':
+ {
+ uint8_t *value = va_arg(ap, uint8_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_UBYTE) {
+ *value = pn_data_get_ubyte(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'b':
+ {
+ int8_t *value = va_arg(ap, int8_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_BYTE) {
+ *value = pn_data_get_byte(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'H':
+ {
+ uint16_t *value = va_arg(ap, uint16_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_USHORT) {
+ *value = pn_data_get_ushort(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'h':
+ {
+ int16_t *value = va_arg(ap, int16_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_SHORT) {
+ *value = pn_data_get_short(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'I':
+ {
+ uint32_t *value = va_arg(ap, uint32_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_UINT) {
+ *value = pn_data_get_uint(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'i':
+ {
+ int32_t *value = va_arg(ap, int32_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_INT) {
+ *value = pn_data_get_int(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'c':
+ {
+ pn_char_t *value = va_arg(ap, pn_char_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_CHAR) {
+ *value = pn_data_get_char(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'L':
+ {
+ uint64_t *value = va_arg(ap, uint64_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_ULONG) {
+ *value = pn_data_get_ulong(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'l':
+ {
+ int64_t *value = va_arg(ap, int64_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_LONG) {
+ *value = pn_data_get_long(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 't':
+ {
+ pn_timestamp_t *value = va_arg(ap, pn_timestamp_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_TIMESTAMP) {
+ *value = pn_data_get_timestamp(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'f':
+ {
+ float *value = va_arg(ap, float *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_FLOAT) {
+ *value = pn_data_get_float(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'd':
+ {
+ double *value = va_arg(ap, double *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_DOUBLE) {
+ *value = pn_data_get_double(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'z':
+ {
+ pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_BINARY) {
+ *bytes = pn_data_get_binary(data);
+ scanned = true;
+ } else {
+ bytes->start = 0;
+ bytes->size = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'S':
+ {
+ pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_STRING) {
+ *bytes = pn_data_get_string(data);
+ scanned = true;
+ } else {
+ bytes->start = 0;
+ bytes->size = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 's':
+ {
+ pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_SYMBOL) {
+ *bytes = pn_data_get_symbol(data);
+ scanned = true;
+ } else {
+ bytes->start = 0;
+ bytes->size = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'D':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_DESCRIBED) {
+ pn_data_enter(data);
+ scanned = true;
+ } else {
+ if (!suspend) {
+ resume_count = 3;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '@':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_ARRAY) {
+ pn_data_enter(data);
+ scanned = true;
+ at = true;
+ } else {
+ if (!suspend) {
+ resume_count = 3;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '[':
+ if (at) {
+ scanned = true;
+ at = false;
+ } else {
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_LIST) {
+ pn_data_enter(data);
+ scanned = true;
+ } else {
+ if (!suspend) {
+ resume_count = 1;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ }
+ level++;
+ break;
+ case '{':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_MAP) {
+ pn_data_enter(data);
+ scanned = true;
+ } else {
+ if (resume_count) {
+ resume_count = 1;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ level++;
+ break;
+ case ']':
+ case '}':
+ level--;
+ if (!suspend && !pn_data_exit(data))
+ return pn_error_format(data->error, PN_ERR, "exit failed");
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '.':
+ found = pn_scan_next(data, &type, suspend);
+ scanned = found;
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '?':
+ if (!*fmt || *fmt == '?')
+ return pn_error_format(data->error, PN_ARG_ERR, "codes must follow a ?");
+ scanarg = va_arg(ap, bool *);
+ break;
+ case 'C':
+ {
+ pn_data_t *dst = va_arg(ap, pn_data_t *);
+ if (!suspend) {
+ size_t old = pn_data_size(dst);
+ pni_node_t *next = pni_data_peek(data);
+ if (next && next->atom.type != PN_NULL) {
+ pn_data_narrow(data);
+ int err = pn_data_appendn(dst, data, 1);
+ pn_data_widen(data);
+ if (err) return err;
+ scanned = pn_data_size(dst) > old;
+ } else {
+ scanned = false;
+ }
+ pn_data_next(data);
+ } else {
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ default:
+ return pn_error_format(data->error, PN_ARG_ERR, "unrecognized scan code: 0x%.2X '%c'", code, code);
+ }
+
+ if (scanarg && code != '?') {
+ *scanarg = scanned;
+ scanarg = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int pn_data_scan(pn_data_t *data, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int err = pn_data_vscan(data, fmt, ap);
+ va_end(ap);
+ return err;
+}
+
+static int pni_data_inspectify(pn_data_t *data)
+{
+ int err = pn_string_set(data->str, "");
+ if (err) return err;
+ return pn_data_inspect(data, data->str);
+}
+
+int pn_data_print(pn_data_t *data)
+{
+ int err = pni_data_inspectify(data);
+ if (err) return err;
+ printf("%s", pn_string_get(data->str));
+ return 0;
+}
+
+int pn_data_format(pn_data_t *data, char *bytes, size_t *size)
+{
+ int err = pni_data_inspectify(data);
+ if (err) return err;
+ if (pn_string_size(data->str) >= *size) {
+ return PN_OVERFLOW;
+ } else {
+ pn_string_put(data->str, bytes);
+ *size = pn_string_size(data->str);
+ return 0;
+ }
+}
+
+static size_t pni_data_id(pn_data_t *data, pni_node_t *node)
+{
+ return node - data->nodes + 1;
+}
+
+static pni_node_t *pni_data_new(pn_data_t *data)
+{
+ if ((data->capacity <= data->size) && (pni_data_grow(data) != 0)) return NULL;
+ pni_node_t *node = pn_data_node(data, ++(data->size));
+ node->next = 0;
+ node->down = 0;
+ node->children = 0;
+ return node;
+}
+
+void pn_data_rewind(pn_data_t *data)
+{
+ data->parent = data->base_parent;
+ data->current = data->base_current;
+}
+
+static pni_node_t *pni_data_current(pn_data_t *data)
+{
+ return pn_data_node(data, data->current);
+}
+
+void pn_data_narrow(pn_data_t *data)
+{
+ data->base_parent = data->parent;
+ data->base_current = data->current;
+}
+
+void pn_data_widen(pn_data_t *data)
+{
+ data->base_parent = 0;
+ data->base_current = 0;
+}
+
+pn_handle_t pn_data_point(pn_data_t *data)
+{
+ if (data->current) {
+ return (pn_handle_t)(uintptr_t)data->current;
+ } else {
+ return (pn_handle_t)(uintptr_t)-data->parent;
+ }
+}
+
+bool pn_data_restore(pn_data_t *data, pn_handle_t point)
+{
+ pn_shandle_t spoint = (pn_shandle_t) point;
+ if (spoint <= 0 && ((size_t) (-spoint)) <= data->size) {
+ data->parent = -((pn_shandle_t) point);
+ data->current = 0;
+ return true;
+ } else if (spoint && spoint <= data->size) {
+ data->current = spoint;
+ pni_node_t *current = pni_data_current(data);
+ data->parent = current->parent;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static pni_node_t *pni_data_peek(pn_data_t *data)
+{
+ pni_node_t *current = pni_data_current(data);
+ if (current) {
+ return pn_data_node(data, current->next);
+ }
+
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ if (parent) {
+ return pn_data_node(data, parent->down);
+ }
+
+ return NULL;
+}
+
+bool pn_data_next(pn_data_t *data)
+{
+ pni_node_t *current = pni_data_current(data);
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ size_t next;
+
+ if (current) {
+ next = current->next;
+ } else if (parent && parent->down) {
+ next = parent->down;
+ } else if (!parent && data->size) {
+ next = 1;
+ } else {
+ return false;
+ }
+
+ if (next) {
+ data->current = next;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool pn_data_prev(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->prev) {
+ data->current = node->prev;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int pni_data_traverse(pn_data_t *data,
+ int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
+ int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
+ void *ctx)
+{
+ pni_node_t *node = data->size ? pn_data_node(data, 1) : NULL;
+ while (node) {
+ pni_node_t *parent = pn_data_node(data, node->parent);
+
+ int err = enter(ctx, data, node);
+ if (err) return err;
+
+ size_t next = 0;
+ if (node->down) {
+ next = node->down;
+ } else if (node->next) {
+ err = exit(ctx, data, node);
+ if (err) return err;
+ next = node->next;
+ } else {
+ err = exit(ctx, data, node);
+ if (err) return err;
+ while (parent) {
+ err = exit(ctx, data, parent);
+ if (err) return err;
+ if (parent->next) {
+ next = parent->next;
+ break;
+ } else {
+ parent = pn_data_node(data, parent->parent);
+ }
+ }
+ }
+
+ node = pn_data_node(data, next);
+ }
+
+ return 0;
+}
+
+pn_type_t pn_data_type(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node) {
+ return node->atom.type;
+ } else {
+ return PN_INVALID;
+ }
+}
+
+pn_type_t pni_data_parent_type(pn_data_t *data)
+{
+ pni_node_t *node = pn_data_node(data, data->parent);
+ if (node) {
+ return node->atom.type;
+ } else {
+ return PN_INVALID;
+ }
+}
+
+size_t pn_data_siblings(pn_data_t *data)
+{
+ pni_node_t *node = pn_data_node(data, data->parent);
+ if (node) {
+ return node->children;
+ } else {
+ return 0;
+ }
+}
+
+bool pn_data_enter(pn_data_t *data)
+{
+ if (data->current) {
+ data->parent = data->current;
+ data->current = 0;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool pn_data_exit(pn_data_t *data)
+{
+ if (data->parent) {
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ data->current = data->parent;
+ data->parent = parent->parent;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool pn_data_lookup(pn_data_t *data, const char *name)
+{
+ while (pn_data_next(data)) {
+ pn_type_t type = pn_data_type(data);
+
+ switch (type) {
+ case PN_STRING:
+ case PN_SYMBOL:
+ {
+ pn_bytes_t bytes = pn_data_get_bytes(data);
+ if (strlen(name) == bytes.size && !strncmp(name, bytes.start, bytes.size)) {
+ return pn_data_next(data);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // skip the value
+ pn_data_next(data);
+ }
+
+ return false;
+}
+
+void pn_data_dump(pn_data_t *data)
+{
+ printf("{current=%" PN_ZI ", parent=%" PN_ZI "}\n", (size_t) data->current, (size_t) data->parent);
+ for (unsigned i = 0; i < data->size; i++)
+ {
+ pni_node_t *node = &data->nodes[i];
+ pn_string_set(data->str, "");
+ pni_inspect_atom((pn_atom_t *) &node->atom, data->str);
+ printf("Node %i: prev=%" PN_ZI ", next=%" PN_ZI ", parent=%" PN_ZI ", down=%" PN_ZI
+ ", children=%" PN_ZI ", type=%s (%s)\n",
+ i + 1, (size_t) node->prev,
+ (size_t) node->next,
+ (size_t) node->parent,
+ (size_t) node->down,
+ (size_t) node->children,
+ pn_type_name(node->atom.type), pn_string_get(data->str));
+ }
+}
+
+static pni_node_t *pni_data_add(pn_data_t *data)
+{
+ pni_node_t *current = pni_data_current(data);
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ pni_node_t *node;
+
+ if (current) {
+ if (current->next) {
+ node = pn_data_node(data, current->next);
+ } else {
+ node = pni_data_new(data);
+ if (!node) return NULL;
+
+ // refresh the pointers in case we grew
+ current = pni_data_current(data);
+ parent = pn_data_node(data, data->parent);
+ node->prev = data->current;
+ current->next = pni_data_id(data, node);
+ node->parent = data->parent;
+ if (parent) {
+ if (!parent->down) {
+ parent->down = pni_data_id(data, node);
+ }
+ parent->children++;
+ }
+ }
+ } else if (parent) {
+ if (parent->down) {
+ node = pn_data_node(data, parent->down);
+ } else {
+ node = pni_data_new(data);
+ if (!node) return NULL;
+
+ // refresh the pointers in case we grew
+ parent = pn_data_node(data, data->parent);
+ node->prev = 0;
+ node->parent = data->parent;
+ parent->down = pni_data_id(data, node);
+ parent->children++;
+ }
+ } else if (data->size) {
+ node = pn_data_node(data, 1);
+ } else {
+ node = pni_data_new(data);
+ if (!node) return NULL;
+
+ node->prev = 0;
+ node->parent = 0;
+ }
+
+ node->down = 0;
+ node->children = 0;
+ node->data = false;
+ node->data_offset = 0;
+ node->data_size = 0;
+ data->current = pni_data_id(data, node);
+ return node;
+}
+
+ssize_t pn_data_encode(pn_data_t *data, char *bytes, size_t size)
+{
+ return pn_encoder_encode(data->encoder, data, bytes, size);
+}
+
+ssize_t pn_data_encoded_size(pn_data_t *data)
+{
+ return pn_encoder_size(data->encoder, data);
+}
+
+ssize_t pn_data_decode(pn_data_t *data, const char *bytes, size_t size)
+{
+ return pn_decoder_decode(data->decoder, bytes, size, data);
+}
+
+int pn_data_put_list(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_LIST;
+ return 0;
+}
+
+int pn_data_put_map(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_MAP;
+ return 0;
+}
+
+int pn_data_put_array(pn_data_t *data, bool described, pn_type_t type)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_ARRAY;
+ node->described = described;
+ node->type = type;
+ return 0;
+}
+
+void pni_data_set_array_type(pn_data_t *data, pn_type_t type)
+{
+ pni_node_t *array = pni_data_current(data);
+ if (array) array->type = type;
+}
+
+int pn_data_put_described(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DESCRIBED;
+ return 0;
+}
+
+int pn_data_put_null(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ pni_atom_init(&node->atom, PN_NULL);
+ return 0;
+}
+
+int pn_data_put_bool(pn_data_t *data, bool b)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_BOOL;
+ node->atom.u.as_bool = b;
+ return 0;
+}
+
+int pn_data_put_ubyte(pn_data_t *data, uint8_t ub)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_UBYTE;
+ node->atom.u.as_ubyte = ub;
+ return 0;
+}
+
+int pn_data_put_byte(pn_data_t *data, int8_t b)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_BYTE;
+ node->atom.u.as_byte = b;
+ return 0;
+}
+
+int pn_data_put_ushort(pn_data_t *data, uint16_t us)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_USHORT;
+ node->atom.u.as_ushort = us;
+ return 0;
+}
+
+int pn_data_put_short(pn_data_t *data, int16_t s)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_SHORT;
+ node->atom.u.as_short = s;
+ return 0;
+}
+
+int pn_data_put_uint(pn_data_t *data, uint32_t ui)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_UINT;
+ node->atom.u.as_uint = ui;
+ return 0;
+}
+
+int pn_data_put_int(pn_data_t *data, int32_t i)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_INT;
+ node->atom.u.as_int = i;
+ return 0;
+}
+
+int pn_data_put_char(pn_data_t *data, pn_char_t c)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_CHAR;
+ node->atom.u.as_char = c;
+ return 0;
+}
+
+int pn_data_put_ulong(pn_data_t *data, uint64_t ul)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_ULONG;
+ node->atom.u.as_ulong = ul;
+ return 0;
+}
+
+int pn_data_put_long(pn_data_t *data, int64_t l)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_LONG;
+ node->atom.u.as_long = l;
+ return 0;
+}
+
+int pn_data_put_timestamp(pn_data_t *data, pn_timestamp_t t)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_TIMESTAMP;
+ node->atom.u.as_timestamp = t;
+ return 0;
+}
+
+int pn_data_put_float(pn_data_t *data, float f)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_FLOAT;
+ node->atom.u.as_float = f;
+ return 0;
+}
+
+int pn_data_put_double(pn_data_t *data, double d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DOUBLE;
+ node->atom.u.as_double = d;
+ return 0;
+}
+
+int pn_data_put_decimal32(pn_data_t *data, pn_decimal32_t d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DECIMAL32;
+ node->atom.u.as_decimal32 = d;
+ return 0;
+}
+
+int pn_data_put_decimal64(pn_data_t *data, pn_decimal64_t d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DECIMAL64;
+ node->atom.u.as_decimal64 = d;
+ return 0;
+}
+
+int pn_data_put_decimal128(pn_data_t *data, pn_decimal128_t d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DECIMAL128;
+ memmove(node->atom.u.as_decimal128.bytes, d.bytes, 16);
+ return 0;
+}
+
+int pn_data_put_uuid(pn_data_t *data, pn_uuid_t u)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_UUID;
+ memmove(node->atom.u.as_uuid.bytes, u.bytes, 16);
+ return 0;
+}
+
+int pn_data_put_binary(pn_data_t *data, pn_bytes_t bytes)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_BINARY;
+ node->atom.u.as_bytes = bytes;
+ return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_string(pn_data_t *data, pn_bytes_t string)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_STRING;
+ node->atom.u.as_bytes = string;
+ return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_symbol(pn_data_t *data, pn_bytes_t symbol)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_SYMBOL;
+ node->atom.u.as_bytes = symbol;
+ return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_atom(pn_data_t *data, pn_atom_t atom)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom = atom;
+ return pni_data_intern_node(data, node);
+}
+
+size_t pn_data_get_list(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_LIST) {
+ return node->children;
+ } else {
+ return 0;
+ }
+}
+
+size_t pn_data_get_map(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_MAP) {
+ return node->children;
+ } else {
+ return 0;
+ }
+}
+
+size_t pn_data_get_array(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ARRAY) {
+ if (node->described) {
+ return node->children - 1;
+ } else {
+ return node->children;
+ }
+ } else {
+ return 0;
+ }
+}
+
+bool pn_data_is_array_described(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ARRAY) {
+ return node->described;
+ } else {
+ return false;
+ }
+}
+
+pn_type_t pn_data_get_array_type(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ARRAY) {
+ return node->type;
+ } else {
+ return PN_INVALID;
+ }
+}
+
+bool pn_data_is_described(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ return node && node->atom.type == PN_DESCRIBED;
+}
+
+bool pn_data_is_null(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ return node && node->atom.type == PN_NULL;
+}
+
+bool pn_data_get_bool(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_BOOL) {
+ return node->atom.u.as_bool;
+ } else {
+ return false;
+ }
+}
+
+uint8_t pn_data_get_ubyte(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_UBYTE) {
+ return node->atom.u.as_ubyte;
+ } else {
+ return 0;
+ }
+}
+
+int8_t pn_data_get_byte(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_BYTE) {
+ return node->atom.u.as_byte;
+ } else {
+ return 0;
+ }
+}
+
+uint16_t pn_data_get_ushort(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_USHORT) {
+ return node->atom.u.as_ushort;
+ } else {
+ return 0;
+ }
+}
+
+int16_t pn_data_get_short(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_SHORT) {
+ return node->atom.u.as_short;
+ } else {
+ return 0;
+ }
+}
+
+uint32_t pn_data_get_uint(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_UINT) {
+ return node->atom.u.as_uint;
+ } else {
+ return 0;
+ }
+}
+
+int32_t pn_data_get_int(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_INT) {
+ return node->atom.u.as_int;
+ } else {
+ return 0;
+ }
+}
+
+pn_char_t pn_data_get_char(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_CHAR) {
+ return node->atom.u.as_char;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t pn_data_get_ulong(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ULONG) {
+ return node->atom.u.as_ulong;
+ } else {
+ return 0;
+ }
+}
+
+int64_t pn_data_get_long(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_LONG) {
+ return node->atom.u.as_long;
+ } else {
+ return 0;
+ }
+}
+
+pn_timestamp_t pn_data_get_timestamp(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_TIMESTAMP) {
+ return node->atom.u.as_timestamp;
+ } else {
+ return 0;
+ }
+}
+
+float pn_data_get_float(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_FLOAT) {
+ return node->atom.u.as_float;
+ } else {
+ return 0;
+ }
+}
+
+double pn_data_get_double(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DOUBLE) {
+ return node->atom.u.as_double;
+ } else {
+ return 0;
+ }
+}
+
+pn_decimal32_t pn_data_get_decimal32(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DECIMAL32) {
+ return node->atom.u.as_decimal32;
+ } else {
+ return 0;
+ }
+}
+
+pn_decimal64_t pn_data_get_decimal64(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DECIMAL64) {
+ return node->atom.u.as_decimal64;
+ } else {
+ return 0;
+ }
+}
+
+pn_decimal128_t pn_data_get_decimal128(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DECIMAL128) {
+ return node->atom.u.as_decimal128;
+ } else {
+ pn_decimal128_t t = {{0}};
+ return t;
+ }
+}
+
+pn_uuid_t pn_data_get_uuid(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_UUID) {
+ return node->atom.u.as_uuid;
+ } else {
+ pn_uuid_t t = {{0}};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_binary(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_BINARY) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_string(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_STRING) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_symbol(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_SYMBOL) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_bytes(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && (node->atom.type == PN_BINARY ||
+ node->atom.type == PN_STRING ||
+ node->atom.type == PN_SYMBOL)) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_atom_t pn_data_get_atom(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node) {
+ return *((pn_atom_t *) &node->atom);
+ } else {
+ pn_atom_t t = {PN_NULL, {0,}};
+ return t;
+ }
+}
+
+int pn_data_copy(pn_data_t *data, pn_data_t *src)
+{
+ pn_data_clear(data);
+ int err = pn_data_append(data, src);
+ pn_data_rewind(data);
+ return err;
+}
+
+int pn_data_append(pn_data_t *data, pn_data_t *src)
+{
+ return pn_data_appendn(data, src, -1);
+}
+
+int pn_data_appendn(pn_data_t *data, pn_data_t *src, int limit)
+{
+ int err = 0;
+ int level = 0, count = 0;
+ bool stop = false;
+ pn_handle_t point = pn_data_point(src);
+ pn_data_rewind(src);
+
+ while (true) {
+ while (!pn_data_next(src)) {
+ if (level > 0) {
+ pn_data_exit(data);
+ pn_data_exit(src);
+ level--;
+ continue;
+ }
+
+ if (!pn_data_next(src)) {
+ stop = true;
+ }
+ break;
+ }
+
+ if (stop) break;
+
+ if (level == 0 && count == limit)
+ break;
+
+ pn_type_t type = pn_data_type(src);
+ switch (type) {
+ case PN_NULL:
+ err = pn_data_put_null(data);
+ if (level == 0) count++;
+ break;
+ case PN_BOOL:
+ err = pn_data_put_bool(data, pn_data_get_bool(src));
+ if (level == 0) count++;
+ break;
+ case PN_UBYTE:
+ err = pn_data_put_ubyte(data, pn_data_get_ubyte(src));
+ if (level == 0) count++;
+ break;
+ case PN_BYTE:
+ err = pn_data_put_byte(data, pn_data_get_byte(src));
+ if (level == 0) count++;
+ break;
+ case PN_USHORT:
+ err = pn_data_put_ushort(data, pn_data_get_ushort(src));
+ if (level == 0) count++;
+ break;
+ case PN_SHORT:
+ err = pn_data_put_short(data, pn_data_get_short(src));
+ if (level == 0) count++;
+ break;
+ case PN_UINT:
+ err = pn_data_put_uint(data, pn_data_get_uint(src));
+ if (level == 0) count++;
+ break;
+ case PN_INT:
+ err = pn_data_put_int(data, pn_data_get_int(src));
+ if (level == 0) count++;
+ break;
+ case PN_CHAR:
+ err = pn_data_put_char(data, pn_data_get_char(src));
+ if (level == 0) count++;
+ break;
+ case PN_ULONG:
+ err = pn_data_put_ulong(data, pn_data_get_ulong(src));
+ if (level == 0) count++;
+ break;
+ case PN_LONG:
+ err = pn_data_put_long(data, pn_data_get_long(src));
+ if (level == 0) count++;
+ break;
+ case PN_TIMESTAMP:
+ err = pn_data_put_timestamp(data, pn_data_get_timestamp(src));
+ if (level == 0) count++;
+ break;
+ case PN_FLOAT:
+ err = pn_data_put_float(data, pn_data_get_float(src));
+ if (level == 0) count++;
+ break;
+ case PN_DOUBLE:
+ err = pn_data_put_double(data, pn_data_get_double(src));
+ if (level == 0) count++;
+ break;
+ case PN_DECIMAL32:
+ err = pn_data_put_decimal32(data, pn_data_get_decimal32(src));
+ if (level == 0) count++;
+ break;
+ case PN_DECIMAL64:
+ err = pn_data_put_decimal64(data, pn_data_get_decimal64(src));
+ if (level == 0) count++;
+ break;
+ case PN_DECIMAL128:
+ err = pn_data_put_decimal128(data, pn_data_get_decimal128(src));
+ if (level == 0) count++;
+ break;
+ case PN_UUID:
+ err = pn_data_put_uuid(data, pn_data_get_uuid(src));
+ if (level == 0) count++;
+ break;
+ case PN_BINARY:
+ err = pn_data_put_binary(data, pn_data_get_binary(src));
+ if (level == 0) count++;
+ break;
+ case PN_STRING:
+ err = pn_data_put_string(data, pn_data_get_string(src));
+ if (level == 0) count++;
+ break;
+ case PN_SYMBOL:
+ err = pn_data_put_symbol(data, pn_data_get_symbol(src));
+ if (level == 0) count++;
+ break;
+ case PN_DESCRIBED:
+ err = pn_data_put_described(data);
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ case PN_ARRAY:
+ err = pn_data_put_array(data, pn_data_is_array_described(src),
+ pn_data_get_array_type(src));
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ case PN_LIST:
+ err = pn_data_put_list(data);
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ case PN_MAP:
+ err = pn_data_put_map(data);
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ default:
+ break;
+ }
+
+ if (err) { pn_data_restore(src, point); return err; }
+ }
+
+ pn_data_restore(src, point);
+
+ return 0;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/config.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/config.h b/proton-c/src/core/config.h
new file mode 100644
index 0000000..5a2e7bc
--- /dev/null
+++ b/proton-c/src/core/config.h
@@ -0,0 +1,32 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+#ifndef _PROTON_SRC_CONFIG_H
+#define _PROTON_SRC_CONFIG_H
+
+#ifndef PN_TRANSPORT_INITIAL_FRAME_SIZE
+# define PN_TRANSPORT_INITIAL_FRAME_SIZE (512) /* bytes */
+#endif
+
+#ifndef PN_SASL_MAX_BUFFSIZE
+# define PN_SASL_MAX_BUFFSIZE (32768) /* bytes */
+#endif
+
+#endif /* _PROTON_SRC_CONFIG_H */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/connection_engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_engine.c b/proton-c/src/core/connection_engine.c
new file mode 100644
index 0000000..5d184a1
--- /dev/null
+++ b/proton-c/src/core/connection_engine.c
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "engine-internal.h"
+
+#include <proton/connection.h>
+#include <proton/connection_engine.h>
+#include <proton/transport.h>
+#include <string.h>
+
+int pn_connection_engine_init(pn_connection_engine_t* e) {
+ memset(e, 0, sizeof(*e));
+ e->connection = pn_connection();
+ e->transport = pn_transport();
+ e->collector = pn_collector();
+ if (!e->connection || !e->transport || !e->collector) {
+ pn_connection_engine_final(e);
+ return PN_OUT_OF_MEMORY;
+ }
+ pn_connection_collect(e->connection, e->collector);
+ return PN_OK;
+}
+
+void pn_connection_engine_final(pn_connection_engine_t* e) {
+ if (e->transport && e->connection) {
+ pn_transport_unbind(e->transport);
+ pn_decref(e->transport);
+ }
+ if (e->collector)
+ pn_collector_free(e->collector); /* Break cycle with connection */
+ if (e->connection)
+ pn_decref(e->connection);
+ memset(e, 0, sizeof(*e));
+}
+
+pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t* e) {
+ ssize_t cap = pn_transport_capacity(e->transport);
+ if (cap > 0)
+ return pn_rwbytes(cap, pn_transport_tail(e->transport));
+ else
+ return pn_rwbytes(0, 0);
+}
+
+void pn_connection_engine_read_done(pn_connection_engine_t* e, size_t n) {
+ if (n > 0)
+ pn_transport_process(e->transport, n);
+}
+
+void pn_connection_engine_read_close(pn_connection_engine_t* e) {
+ pn_transport_close_tail(e->transport);
+}
+
+pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t* e) {
+ ssize_t pending = pn_transport_pending(e->transport);
+ if (pending > 0)
+ return pn_bytes(pending, pn_transport_head(e->transport));
+ else
+ return pn_bytes(0, 0);
+}
+
+void pn_connection_engine_write_done(pn_connection_engine_t* e, size_t n) {
+ if (n > 0)
+ pn_transport_pop(e->transport, n);
+}
+
+void pn_connection_engine_write_close(pn_connection_engine_t* e){
+ pn_transport_close_head(e->transport);
+}
+
+void pn_connection_engine_disconnected(pn_connection_engine_t* e) {
+ pn_connection_engine_read_close(e);
+ pn_connection_engine_write_close(e);
+}
+
+static void log_event(pn_connection_engine_t *engine, pn_event_t* event) {
+ if (event && engine->transport->trace & PN_TRACE_EVT) {
+ pn_string_t *str = pn_string(NULL);
+ pn_inspect(event, str);
+ pn_transport_log(engine->transport, pn_string_get(str));
+ pn_free(str);
+ }
+}
+
+pn_event_t* pn_connection_engine_dispatch(pn_connection_engine_t* e) {
+ if (e->event) { /* Already returned */
+ if (pn_event_type(e->event) == PN_CONNECTION_INIT)
+ pn_transport_bind(e->transport, e->connection);
+ pn_collector_pop(e->collector);
+ }
+ e->event = pn_collector_peek(e->collector);
+ log_event(e, e->event);
+ return e->event;
+}
+
+bool pn_connection_engine_finished(pn_connection_engine_t* e) {
+ return pn_transport_closed(e->transport) && (pn_collector_peek(e->collector) == NULL);
+}
+
+pn_connection_t* pn_connection_engine_connection(pn_connection_engine_t* e) {
+ return e->connection;
+}
+
+pn_transport_t* pn_connection_engine_transport(pn_connection_engine_t* e) {
+ return e->transport;
+}
+
+pn_condition_t* pn_connection_engine_condition(pn_connection_engine_t* e) {
+ return pn_transport_condition(e->transport);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/data.h b/proton-c/src/core/data.h
new file mode 100644
index 0000000..94dc7d6
--- /dev/null
+++ b/proton-c/src/core/data.h
@@ -0,0 +1,75 @@
+#ifndef _PROTON_DATA_H
+#define _PROTON_DATA_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/codec.h>
+#include "buffer.h"
+#include "decoder.h"
+#include "encoder.h"
+
+typedef uint16_t pni_nid_t;
+#define PNI_NID_MAX ((pni_nid_t)-1)
+
+typedef struct {
+ char *start;
+ size_t data_offset;
+ size_t data_size;
+ pn_atom_t atom;
+ pn_type_t type;
+ pni_nid_t next;
+ pni_nid_t prev;
+ pni_nid_t down;
+ pni_nid_t parent;
+ pni_nid_t children;
+ // for arrays
+ bool described;
+ bool data;
+ bool small;
+} pni_node_t;
+
+struct pn_data_t {
+ pni_node_t *nodes;
+ pn_buffer_t *buf;
+ pn_decoder_t *decoder;
+ pn_encoder_t *encoder;
+ pn_error_t *error;
+ pn_string_t *str;
+ pni_nid_t capacity;
+ pni_nid_t size;
+ pni_nid_t parent;
+ pni_nid_t current;
+ pni_nid_t base_parent;
+ pni_nid_t base_current;
+};
+
+static inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd)
+{
+ return nd ? (data->nodes + nd - 1) : NULL;
+}
+
+int pni_data_traverse(pn_data_t *data,
+ int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
+ int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
+ void *ctx);
+
+#endif /* data.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/decoder.c b/proton-c/src/core/decoder.c
new file mode 100644
index 0000000..b0c8d79
--- /dev/null
+++ b/proton-c/src/core/decoder.c
@@ -0,0 +1,497 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/error.h>
+#include <proton/object.h>
+#include <proton/codec.h>
+#include "encodings.h"
+#include "decoder.h"
+
+#include <string.h>
+
+struct pn_decoder_t {
+ const char *input;
+ size_t size;
+ const char *position;
+ pn_error_t *error;
+};
+
+static void pn_decoder_initialize(void *obj)
+{
+ pn_decoder_t *decoder = (pn_decoder_t *) obj;
+ decoder->input = NULL;
+ decoder->size = 0;
+ decoder->position = NULL;
+ decoder->error = pn_error();
+}
+
+static void pn_decoder_finalize(void *obj) {
+ pn_decoder_t *decoder = (pn_decoder_t *) obj;
+ pn_error_free(decoder->error);
+}
+
+#define pn_decoder_hashcode NULL
+#define pn_decoder_compare NULL
+#define pn_decoder_inspect NULL
+
+pn_decoder_t *pn_decoder()
+{
+ static const pn_class_t clazz = PN_CLASS(pn_decoder);
+ return (pn_decoder_t *) pn_class_new(&clazz, sizeof(pn_decoder_t));
+}
+
+static inline uint8_t pn_decoder_readf8(pn_decoder_t *decoder)
+{
+ uint8_t r = decoder->position[0];
+ decoder->position++;
+ return r;
+}
+
+static inline uint16_t pn_decoder_readf16(pn_decoder_t *decoder)
+{
+ uint16_t a = (uint8_t) decoder->position[0];
+ uint16_t b = (uint8_t) decoder->position[1];
+ uint16_t r = a << 8
+ | b;
+ decoder->position += 2;
+ return r;
+}
+
+static inline uint32_t pn_decoder_readf32(pn_decoder_t *decoder)
+{
+ uint32_t a = (uint8_t) decoder->position[0];
+ uint32_t b = (uint8_t) decoder->position[1];
+ uint32_t c = (uint8_t) decoder->position[2];
+ uint32_t d = (uint8_t) decoder->position[3];
+ uint32_t r = a << 24
+ | b << 16
+ | c << 8
+ | d;
+ decoder->position += 4;
+ return r;
+}
+
+static inline uint64_t pn_decoder_readf64(pn_decoder_t *decoder)
+{
+ uint64_t a = pn_decoder_readf32(decoder);
+ uint64_t b = pn_decoder_readf32(decoder);
+ return a << 32 | b;
+}
+
+static inline void pn_decoder_readf128(pn_decoder_t *decoder, void *dst)
+{
+ memmove(dst, decoder->position, 16);
+ decoder->position += 16;
+}
+
+static inline size_t pn_decoder_remaining(pn_decoder_t *decoder)
+{
+ return decoder->input + decoder->size - decoder->position;
+}
+
+typedef union {
+ uint32_t i;
+ uint32_t a[2];
+ uint64_t l;
+ float f;
+ double d;
+} conv_t;
+
+static inline pn_type_t pn_code2type(uint8_t code)
+{
+ switch (code)
+ {
+ case PNE_DESCRIPTOR:
+ return (pn_type_t) PN_ARG_ERR;
+ case PNE_NULL:
+ return PN_NULL;
+ case PNE_TRUE:
+ case PNE_FALSE:
+ case PNE_BOOLEAN:
+ return PN_BOOL;
+ case PNE_UBYTE:
+ return PN_UBYTE;
+ case PNE_BYTE:
+ return PN_BYTE;
+ case PNE_USHORT:
+ return PN_USHORT;
+ case PNE_SHORT:
+ return PN_SHORT;
+ case PNE_UINT0:
+ case PNE_SMALLUINT:
+ case PNE_UINT:
+ return PN_UINT;
+ case PNE_SMALLINT:
+ case PNE_INT:
+ return PN_INT;
+ case PNE_UTF32:
+ return PN_CHAR;
+ case PNE_FLOAT:
+ return PN_FLOAT;
+ case PNE_LONG:
+ case PNE_SMALLLONG:
+ return PN_LONG;
+ case PNE_MS64:
+ return PN_TIMESTAMP;
+ case PNE_DOUBLE:
+ return PN_DOUBLE;
+ case PNE_DECIMAL32:
+ return PN_DECIMAL32;
+ case PNE_DECIMAL64:
+ return PN_DECIMAL64;
+ case PNE_DECIMAL128:
+ return PN_DECIMAL128;
+ case PNE_UUID:
+ return PN_UUID;
+ case PNE_ULONG0:
+ case PNE_SMALLULONG:
+ case PNE_ULONG:
+ return PN_ULONG;
+ case PNE_VBIN8:
+ case PNE_VBIN32:
+ return PN_BINARY;
+ case PNE_STR8_UTF8:
+ case PNE_STR32_UTF8:
+ return PN_STRING;
+ case PNE_SYM8:
+ case PNE_SYM32:
+ return PN_SYMBOL;
+ case PNE_LIST0:
+ case PNE_LIST8:
+ case PNE_LIST32:
+ return PN_LIST;
+ case PNE_ARRAY8:
+ case PNE_ARRAY32:
+ return PN_ARRAY;
+ case PNE_MAP8:
+ case PNE_MAP32:
+ return PN_MAP;
+ default:
+ return (pn_type_t) PN_ARG_ERR;
+ }
+}
+
+static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code);
+static int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data);
+void pni_data_set_array_type(pn_data_t *data, pn_type_t type);
+
+static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code)
+{
+ int err;
+ conv_t conv;
+ pn_decimal128_t dec128;
+ pn_uuid_t uuid;
+ size_t size;
+ size_t count;
+
+ switch (code)
+ {
+ case PNE_NULL:
+ err = pn_data_put_null(data);
+ break;
+ case PNE_TRUE:
+ err = pn_data_put_bool(data, true);
+ break;
+ case PNE_FALSE:
+ err = pn_data_put_bool(data, false);
+ break;
+ case PNE_BOOLEAN:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_bool(data, pn_decoder_readf8(decoder) != 0);
+ break;
+ case PNE_UBYTE:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_ubyte(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_BYTE:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_byte(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_USHORT:
+ if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+ err = pn_data_put_ushort(data, pn_decoder_readf16(decoder));
+ break;
+ case PNE_SHORT:
+ if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+ err = pn_data_put_short(data, pn_decoder_readf16(decoder));
+ break;
+ case PNE_UINT:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_uint(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_UINT0:
+ err = pn_data_put_uint(data, 0);
+ break;
+ case PNE_SMALLUINT:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_uint(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_SMALLINT:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_int(data, (int8_t)pn_decoder_readf8(decoder));
+ break;
+ case PNE_INT:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_int(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_UTF32:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_char(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_FLOAT:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ // XXX: this assumes the platform uses IEEE floats
+ conv.i = pn_decoder_readf32(decoder);
+ err = pn_data_put_float(data, conv.f);
+ break;
+ case PNE_DECIMAL32:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_decimal32(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_ULONG:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_ulong(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_LONG:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_long(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_MS64:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_timestamp(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_DOUBLE:
+ // XXX: this assumes the platform uses IEEE floats
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ conv.l = pn_decoder_readf64(decoder);
+ err = pn_data_put_double(data, conv.d);
+ break;
+ case PNE_DECIMAL64:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_decimal64(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_ULONG0:
+ err = pn_data_put_ulong(data, 0);
+ break;
+ case PNE_SMALLULONG:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_ulong(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_SMALLLONG:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_long(data, (int8_t)pn_decoder_readf8(decoder));
+ break;
+ case PNE_DECIMAL128:
+ if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
+ pn_decoder_readf128(decoder, &dec128);
+ err = pn_data_put_decimal128(data, dec128);
+ break;
+ case PNE_UUID:
+ if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
+ pn_decoder_readf128(decoder, &uuid);
+ err = pn_data_put_uuid(data, uuid);
+ break;
+ case PNE_VBIN8:
+ case PNE_STR8_UTF8:
+ case PNE_SYM8:
+ case PNE_VBIN32:
+ case PNE_STR32_UTF8:
+ case PNE_SYM32:
+ switch (code & 0xF0)
+ {
+ case 0xA0:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ size = pn_decoder_readf8(decoder);
+ break;
+ case 0xB0:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ size = pn_decoder_readf32(decoder);
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+
+ if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
+
+ {
+ char *start = (char *) decoder->position;
+ pn_bytes_t bytes = {size, start};
+ switch (code & 0x0F)
+ {
+ case 0x0:
+ err = pn_data_put_binary(data, bytes);
+ break;
+ case 0x1:
+ err = pn_data_put_string(data, bytes);
+ break;
+ case 0x3:
+ err = pn_data_put_symbol(data, bytes);
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+ }
+
+ decoder->position += size;
+ break;
+ case PNE_LIST0:
+ err = pn_data_put_list(data);
+ break;
+ case PNE_ARRAY8:
+ case PNE_ARRAY32:
+ case PNE_LIST8:
+ case PNE_LIST32:
+ case PNE_MAP8:
+ case PNE_MAP32:
+ switch (code)
+ {
+ case PNE_ARRAY8:
+ case PNE_LIST8:
+ case PNE_MAP8:
+ if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+ size = pn_decoder_readf8(decoder);
+ count = pn_decoder_readf8(decoder);
+ break;
+ case PNE_ARRAY32:
+ case PNE_LIST32:
+ case PNE_MAP32:
+ size = pn_decoder_readf32(decoder);
+ count = pn_decoder_readf32(decoder);
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+
+ switch (code)
+ {
+ case PNE_ARRAY8:
+ case PNE_ARRAY32:
+ {
+ uint8_t next = *decoder->position;
+ bool described = (next == PNE_DESCRIPTOR);
+ err = pn_data_put_array(data, described, (pn_type_t) 0);
+ if (err) return err;
+
+ pn_data_enter(data);
+ uint8_t acode;
+ int e = pni_decoder_decode_type(decoder, data, &acode);
+ if (e) return e;
+ pn_type_t type = pn_code2type(acode);
+ if ((int)type < 0) return (int)type;
+ for (size_t i = 0; i < count; i++)
+ {
+ e = pni_decoder_decode_value(decoder, data, acode);
+ if (e) return e;
+ }
+ pn_data_exit(data);
+
+ pni_data_set_array_type(data, type);
+ }
+ return 0;
+ case PNE_LIST8:
+ case PNE_LIST32:
+ err = pn_data_put_list(data);
+ if (err) return err;
+ break;
+ case PNE_MAP8:
+ case PNE_MAP32:
+ err = pn_data_put_map(data);
+ if (err) return err;
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+
+ pn_data_enter(data);
+ for (size_t i = 0; i < count; i++)
+ {
+ int e = pni_decoder_single(decoder, data);
+ if (e) return e;
+ }
+ pn_data_exit(data);
+
+ return 0;
+ default:
+ return pn_error_format(decoder->error, PN_ARG_ERR, "unrecognized typecode: %u", code);
+ }
+
+ return err;
+}
+
+pn_type_t pni_data_parent_type(pn_data_t *data);
+
+static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code)
+{
+ int err;
+
+ if (!pn_decoder_remaining(decoder)) {
+ return PN_UNDERFLOW;
+ }
+
+ uint8_t next = *decoder->position++;
+
+ if (next == PNE_DESCRIPTOR) {
+ if (pni_data_parent_type(data) != PN_ARRAY) {
+ err = pn_data_put_described(data);
+ if (err) return err;
+ // pni_decoder_single has the corresponding exit
+ pn_data_enter(data);
+ }
+ err = pni_decoder_single(decoder, data);
+ if (err) return err;
+ err = pni_decoder_decode_type(decoder, data, code);
+ if (err) return err;
+ } else {
+ *code = next;
+ }
+
+ return 0;
+}
+
+size_t pn_data_siblings(pn_data_t *data);
+
+int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data)
+{
+ uint8_t code;
+ int err = pni_decoder_decode_type(decoder, data, &code);
+ if (err) return err;
+ err = pni_decoder_decode_value(decoder, data, code);
+ if (err) return err;
+ if (pni_data_parent_type(data) == PN_DESCRIBED && pn_data_siblings(data) > 1) {
+ pn_data_exit(data);
+ }
+ return 0;
+}
+
+ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst)
+{
+ decoder->input = src;
+ decoder->size = size;
+ decoder->position = src;
+
+ int err = pni_decoder_single(decoder, dst);
+
+ if (err == PN_UNDERFLOW)
+ return pn_error_format(pn_data_error(dst), PN_UNDERFLOW, "not enough data to decode");
+ if (err) return err;
+
+ return decoder->position - decoder->input;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/decoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/decoder.h b/proton-c/src/core/decoder.h
new file mode 100644
index 0000000..b7de898
--- /dev/null
+++ b/proton-c/src/core/decoder.h
@@ -0,0 +1,30 @@
+#ifndef _PROTON_DECODER_H
+#define _PROTON_DECODER_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+typedef struct pn_decoder_t pn_decoder_t;
+
+pn_decoder_t *pn_decoder(void);
+ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst);
+
+#endif /* decoder.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/dispatch_actions.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/dispatch_actions.h b/proton-c/src/core/dispatch_actions.h
new file mode 100644
index 0000000..ea2d8b2
--- /dev/null
+++ b/proton-c/src/core/dispatch_actions.h
@@ -0,0 +1,49 @@
+#ifndef _PROTON_DISPATCH_ACTIONS_H
+#define _PROTON_DISPATCH_ACTIONS_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "dispatcher.h"
+
+#define AMQP_FRAME_TYPE (0)
+#define SASL_FRAME_TYPE (1)
+
+
+/* AMQP actions */
+int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+/* SASL actions */
+int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+#endif // _PROTON_DISPATCH_ACTIONS_H
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[15/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/dispatcher.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/dispatcher.c b/proton-c/src/core/dispatcher.c
new file mode 100644
index 0000000..36f8cc9
--- /dev/null
+++ b/proton-c/src/core/dispatcher.c
@@ -0,0 +1,158 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "dispatcher.h"
+
+#include "framing.h"
+#include "protocol.h"
+#include "engine-internal.h"
+
+#include "dispatch_actions.h"
+
+int pni_bad_frame(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
+ pn_transport_logf(transport, "Error dispatching frame: type: %d: Unknown performative", frame_type);
+ return PN_ERR;
+}
+
+int pni_bad_frame_type(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
+ pn_transport_logf(transport, "Error dispatching frame: Unknown frame type: %d", frame_type);
+ return PN_ERR;
+}
+
+// We could use a table based approach here if we needed to dynamically
+// add new performatives
+static inline int pni_dispatch_action(pn_transport_t* transport, uint64_t lcode, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+ pn_action_t *action;
+ switch (frame_type) {
+ case AMQP_FRAME_TYPE:
+ /* Regular AMQP fames */
+ switch (lcode) {
+ case OPEN: action = pn_do_open; break;
+ case BEGIN: action = pn_do_begin; break;
+ case ATTACH: action = pn_do_attach; break;
+ case FLOW: action = pn_do_flow; break;
+ case TRANSFER: action = pn_do_transfer; break;
+ case DISPOSITION: action = pn_do_disposition; break;
+ case DETACH: action = pn_do_detach; break;
+ case END: action = pn_do_end; break;
+ case CLOSE: action = pn_do_close; break;
+ default: action = pni_bad_frame; break;
+ };
+ break;
+ case SASL_FRAME_TYPE:
+ /* SASL frames */
+ switch (lcode) {
+ case SASL_MECHANISMS: action = pn_do_mechanisms; break;
+ case SASL_INIT: action = pn_do_init; break;
+ case SASL_CHALLENGE: action = pn_do_challenge; break;
+ case SASL_RESPONSE: action = pn_do_response; break;
+ case SASL_OUTCOME: action = pn_do_outcome; break;
+ default: action = pni_bad_frame; break;
+ };
+ break;
+ default: action = pni_bad_frame_type; break;
+ };
+ return action(transport, frame_type, channel, args, payload);
+}
+
+static int pni_dispatch_frame(pn_transport_t * transport, pn_data_t *args, pn_frame_t frame)
+{
+ if (frame.size == 0) { // ignore null frames
+ if (transport->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, "%u <- (EMPTY FRAME)", frame.channel);
+ return 0;
+ }
+
+ ssize_t dsize = pn_data_decode(args, frame.payload, frame.size);
+ if (dsize < 0) {
+ pn_string_format(transport->scratch,
+ "Error decoding frame: %s %s\n", pn_code(dsize),
+ pn_error_text(pn_data_error(args)));
+ pn_quote(transport->scratch, frame.payload, frame.size);
+ pn_transport_log(transport, pn_string_get(transport->scratch));
+ return dsize;
+ }
+
+ uint8_t frame_type = frame.type;
+ uint16_t channel = frame.channel;
+ // XXX: assuming numeric -
+ // if we get a symbol we should map it to the numeric value and dispatch on that
+ uint64_t lcode;
+ bool scanned;
+ int e = pn_data_scan(args, "D?L.", &scanned, &lcode);
+ if (e) {
+ pn_transport_log(transport, "Scan error");
+ return e;
+ }
+ if (!scanned) {
+ pn_transport_log(transport, "Error dispatching frame");
+ return PN_ERR;
+ }
+ size_t payload_size = frame.size - dsize;
+ const char *payload_mem = payload_size ? frame.payload + dsize : NULL;
+ pn_bytes_t payload = {payload_size, payload_mem};
+
+ pn_do_trace(transport, channel, IN, args, payload_mem, payload_size);
+
+ int err = pni_dispatch_action(transport, lcode, frame_type, channel, args, &payload);
+
+ pn_data_clear(args);
+
+ return err;
+}
+
+ssize_t pn_dispatcher_input(pn_transport_t *transport, const char *bytes, size_t available, bool batch, bool *halt)
+{
+ size_t read = 0;
+
+ while (available && !*halt) {
+ pn_frame_t frame;
+
+ ssize_t n = pn_read_frame(&frame, bytes + read, available, transport->local_max_frame);
+ if (n > 0) {
+ read += n;
+ available -= n;
+ transport->input_frames_ct += 1;
+ int e = pni_dispatch_frame(transport, transport->args, frame);
+ if (e) return e;
+ } else if (n < 0) {
+ pn_do_error(transport, "amqp:connection:framing-error", "malformed frame");
+ return n;
+ } else {
+ break;
+ }
+
+ if (!batch) break;
+ }
+
+ return read;
+}
+
+ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size)
+{
+ int n = transport->available < size ? transport->available : size;
+ memmove(bytes, transport->output, n);
+ memmove(transport->output, transport->output + n, transport->available - n);
+ transport->available -= n;
+ // XXX: need to check for errors
+ return n;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/dispatcher.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/dispatcher.h b/proton-c/src/core/dispatcher.h
new file mode 100644
index 0000000..29881b5
--- /dev/null
+++ b/proton-c/src/core/dispatcher.h
@@ -0,0 +1,37 @@
+#ifndef _PROTON_DISPATCHER_H
+#define _PROTON_DISPATCHER_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include "proton/codec.h"
+#include "proton/types.h"
+
+typedef int (pn_action_t)(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+ssize_t pn_dispatcher_input(pn_transport_t* transport, const char* bytes, size_t available, bool batch, bool* halt);
+ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size);
+
+#endif /* dispatcher.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/encoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/encoder.c b/proton-c/src/core/encoder.c
new file mode 100644
index 0000000..f8145fc
--- /dev/null
+++ b/proton-c/src/core/encoder.c
@@ -0,0 +1,383 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/error.h>
+#include <proton/object.h>
+#include <proton/codec.h>
+#include "encodings.h"
+#include "encoder.h"
+
+#include <string.h>
+
+#include "data.h"
+
+struct pn_encoder_t {
+ char *output;
+ size_t size;
+ char *position;
+ pn_error_t *error;
+};
+
+static void pn_encoder_initialize(void *obj)
+{
+ pn_encoder_t *encoder = (pn_encoder_t *) obj;
+ encoder->output = NULL;
+ encoder->size = 0;
+ encoder->position = NULL;
+ encoder->error = pn_error();
+}
+
+static void pn_encoder_finalize(void *obj) {
+ pn_encoder_t *encoder = (pn_encoder_t *) obj;
+ pn_error_free(encoder->error);
+}
+
+#define pn_encoder_hashcode NULL
+#define pn_encoder_compare NULL
+#define pn_encoder_inspect NULL
+
+pn_encoder_t *pn_encoder()
+{
+ static const pn_class_t clazz = PN_CLASS(pn_encoder);
+ return (pn_encoder_t *) pn_class_new(&clazz, sizeof(pn_encoder_t));
+}
+
+static uint8_t pn_type2code(pn_encoder_t *encoder, pn_type_t type)
+{
+ switch (type)
+ {
+ case PN_NULL: return PNE_NULL;
+ case PN_BOOL: return PNE_BOOLEAN;
+ case PN_UBYTE: return PNE_UBYTE;
+ case PN_BYTE: return PNE_BYTE;
+ case PN_USHORT: return PNE_USHORT;
+ case PN_SHORT: return PNE_SHORT;
+ case PN_UINT: return PNE_UINT;
+ case PN_INT: return PNE_INT;
+ case PN_CHAR: return PNE_UTF32;
+ case PN_FLOAT: return PNE_FLOAT;
+ case PN_LONG: return PNE_LONG;
+ case PN_TIMESTAMP: return PNE_MS64;
+ case PN_DOUBLE: return PNE_DOUBLE;
+ case PN_DECIMAL32: return PNE_DECIMAL32;
+ case PN_DECIMAL64: return PNE_DECIMAL64;
+ case PN_DECIMAL128: return PNE_DECIMAL128;
+ case PN_UUID: return PNE_UUID;
+ case PN_ULONG: return PNE_ULONG;
+ case PN_BINARY: return PNE_VBIN32;
+ case PN_STRING: return PNE_STR32_UTF8;
+ case PN_SYMBOL: return PNE_SYM32;
+ case PN_LIST: return PNE_LIST32;
+ case PN_ARRAY: return PNE_ARRAY32;
+ case PN_MAP: return PNE_MAP32;
+ case PN_DESCRIBED: return PNE_DESCRIPTOR;
+ default:
+ return pn_error_format(encoder->error, PN_ERR, "not a value type: %u\n", type);
+ }
+}
+
+static uint8_t pn_node2code(pn_encoder_t *encoder, pni_node_t *node)
+{
+ switch (node->atom.type) {
+ case PN_LONG:
+ if (-128 <= node->atom.u.as_long && node->atom.u.as_long <= 127) {
+ return PNE_SMALLLONG;
+ } else {
+ return PNE_LONG;
+ }
+ case PN_INT:
+ if (-128 <= node->atom.u.as_int && node->atom.u.as_int <= 127) {
+ return PNE_SMALLINT;
+ } else {
+ return PNE_INT;
+ }
+ case PN_ULONG:
+ if (node->atom.u.as_ulong < 256) {
+ return PNE_SMALLULONG;
+ } else {
+ return PNE_ULONG;
+ }
+ case PN_UINT:
+ if (node->atom.u.as_uint < 256) {
+ return PNE_SMALLUINT;
+ } else {
+ return PNE_UINT;
+ }
+ case PN_BOOL:
+ if (node->atom.u.as_bool) {
+ return PNE_TRUE;
+ } else {
+ return PNE_FALSE;
+ }
+ case PN_STRING:
+ if (node->atom.u.as_bytes.size < 256) {
+ return PNE_STR8_UTF8;
+ } else {
+ return PNE_STR32_UTF8;
+ }
+ case PN_SYMBOL:
+ if (node->atom.u.as_bytes.size < 256) {
+ return PNE_SYM8;
+ } else {
+ return PNE_SYM32;
+ }
+ case PN_BINARY:
+ if (node->atom.u.as_bytes.size < 256) {
+ return PNE_VBIN8;
+ } else {
+ return PNE_VBIN32;
+ }
+ default:
+ return pn_type2code(encoder, node->atom.type);
+ }
+}
+
+static size_t pn_encoder_remaining(pn_encoder_t *encoder) {
+ char * end = encoder->output + encoder->size;
+ if (end > encoder->position)
+ return end - encoder->position;
+ else
+ return 0;
+}
+
+static inline void pn_encoder_writef8(pn_encoder_t *encoder, uint8_t value)
+{
+ if (pn_encoder_remaining(encoder)) {
+ encoder->position[0] = value;
+ }
+ encoder->position++;
+}
+
+static inline void pn_encoder_writef16(pn_encoder_t *encoder, uint16_t value)
+{
+ if (pn_encoder_remaining(encoder) >= 2) {
+ encoder->position[0] = 0xFF & (value >> 8);
+ encoder->position[1] = 0xFF & (value );
+ }
+ encoder->position += 2;
+}
+
+static inline void pn_encoder_writef32(pn_encoder_t *encoder, uint32_t value)
+{
+ if (pn_encoder_remaining(encoder) >= 4) {
+ encoder->position[0] = 0xFF & (value >> 24);
+ encoder->position[1] = 0xFF & (value >> 16);
+ encoder->position[2] = 0xFF & (value >> 8);
+ encoder->position[3] = 0xFF & (value );
+ }
+ encoder->position += 4;
+}
+
+static inline void pn_encoder_writef64(pn_encoder_t *encoder, uint64_t value) {
+ if (pn_encoder_remaining(encoder) >= 8) {
+ encoder->position[0] = 0xFF & (value >> 56);
+ encoder->position[1] = 0xFF & (value >> 48);
+ encoder->position[2] = 0xFF & (value >> 40);
+ encoder->position[3] = 0xFF & (value >> 32);
+ encoder->position[4] = 0xFF & (value >> 24);
+ encoder->position[5] = 0xFF & (value >> 16);
+ encoder->position[6] = 0xFF & (value >> 8);
+ encoder->position[7] = 0xFF & (value );
+ }
+ encoder->position += 8;
+}
+
+static inline void pn_encoder_writef128(pn_encoder_t *encoder, char *value) {
+ if (pn_encoder_remaining(encoder) >= 16) {
+ memmove(encoder->position, value, 16);
+ }
+ encoder->position += 16;
+}
+
+static inline void pn_encoder_writev8(pn_encoder_t *encoder, const pn_bytes_t *value)
+{
+ pn_encoder_writef8(encoder, value->size);
+ if (pn_encoder_remaining(encoder) >= value->size)
+ memmove(encoder->position, value->start, value->size);
+ encoder->position += value->size;
+}
+
+static inline void pn_encoder_writev32(pn_encoder_t *encoder, const pn_bytes_t *value)
+{
+ pn_encoder_writef32(encoder, value->size);
+ if (pn_encoder_remaining(encoder) >= value->size)
+ memmove(encoder->position, value->start, value->size);
+ encoder->position += value->size;
+}
+
+/* True if node is an element of an array - not the descriptor. */
+static bool pn_is_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
+ return (parent && parent->atom.type == PN_ARRAY) /* In array */
+ && !(parent->described && !node->prev); /* Not the descriptor */
+}
+
+/** True if node is the first element of an array, not the descriptor.
+ *@pre pn_is_in_array(data, parent, node)
+ */
+static bool pn_is_first_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
+ if (!node->prev) return !parent->described; /* First node */
+ return parent->described && (!pn_data_node(data, node->prev)->prev);
+}
+
+typedef union {
+ uint32_t i;
+ uint32_t a[2];
+ uint64_t l;
+ float f;
+ double d;
+} conv_t;
+
+static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+ pn_encoder_t *encoder = (pn_encoder_t *) ctx;
+ pni_node_t *parent = pn_data_node(data, node->parent);
+ pn_atom_t *atom = &node->atom;
+ uint8_t code;
+ conv_t c;
+
+ /** In an array we don't write the code before each element, only the first. */
+ if (pn_is_in_array(data, parent, node)) {
+ code = pn_type2code(encoder, parent->type);
+ if (pn_is_first_in_array(data, parent, node)) {
+ pn_encoder_writef8(encoder, code);
+ }
+ } else {
+ code = pn_node2code(encoder, node);
+ pn_encoder_writef8(encoder, code);
+ }
+
+ switch (code) {
+ case PNE_DESCRIPTOR:
+ case PNE_NULL:
+ case PNE_TRUE:
+ case PNE_FALSE: return 0;
+ case PNE_BOOLEAN: pn_encoder_writef8(encoder, atom->u.as_bool); return 0;
+ case PNE_UBYTE: pn_encoder_writef8(encoder, atom->u.as_ubyte); return 0;
+ case PNE_BYTE: pn_encoder_writef8(encoder, atom->u.as_byte); return 0;
+ case PNE_USHORT: pn_encoder_writef16(encoder, atom->u.as_ushort); return 0;
+ case PNE_SHORT: pn_encoder_writef16(encoder, atom->u.as_short); return 0;
+ case PNE_UINT0: return 0;
+ case PNE_SMALLUINT: pn_encoder_writef8(encoder, atom->u.as_uint); return 0;
+ case PNE_UINT: pn_encoder_writef32(encoder, atom->u.as_uint); return 0;
+ case PNE_SMALLINT: pn_encoder_writef8(encoder, atom->u.as_int); return 0;
+ case PNE_INT: pn_encoder_writef32(encoder, atom->u.as_int); return 0;
+ case PNE_UTF32: pn_encoder_writef32(encoder, atom->u.as_char); return 0;
+ case PNE_ULONG: pn_encoder_writef64(encoder, atom->u.as_ulong); return 0;
+ case PNE_SMALLULONG: pn_encoder_writef8(encoder, atom->u.as_ulong); return 0;
+ case PNE_LONG: pn_encoder_writef64(encoder, atom->u.as_long); return 0;
+ case PNE_SMALLLONG: pn_encoder_writef8(encoder, atom->u.as_long); return 0;
+ case PNE_MS64: pn_encoder_writef64(encoder, atom->u.as_timestamp); return 0;
+ case PNE_FLOAT: c.f = atom->u.as_float; pn_encoder_writef32(encoder, c.i); return 0;
+ case PNE_DOUBLE: c.d = atom->u.as_double; pn_encoder_writef64(encoder, c.l); return 0;
+ case PNE_DECIMAL32: pn_encoder_writef32(encoder, atom->u.as_decimal32); return 0;
+ case PNE_DECIMAL64: pn_encoder_writef64(encoder, atom->u.as_decimal64); return 0;
+ case PNE_DECIMAL128: pn_encoder_writef128(encoder, atom->u.as_decimal128.bytes); return 0;
+ case PNE_UUID: pn_encoder_writef128(encoder, atom->u.as_uuid.bytes); return 0;
+ case PNE_VBIN8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
+ case PNE_VBIN32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
+ case PNE_STR8_UTF8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
+ case PNE_STR32_UTF8: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
+ case PNE_SYM8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
+ case PNE_SYM32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
+ case PNE_ARRAY32:
+ node->start = encoder->position;
+ node->small = false;
+ // we'll backfill the size on exit
+ encoder->position += 4;
+ pn_encoder_writef32(encoder, node->described ? node->children - 1 : node->children);
+ if (node->described)
+ pn_encoder_writef8(encoder, 0);
+ return 0;
+ case PNE_LIST32:
+ case PNE_MAP32:
+ node->start = encoder->position;
+ node->small = false;
+ // we'll backfill the size later
+ encoder->position += 4;
+ pn_encoder_writef32(encoder, node->children);
+ return 0;
+ default:
+ return pn_error_format(data->error, PN_ERR, "unrecognized encoding: %u", code);
+ }
+}
+
+#include <stdio.h>
+
+static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+ pn_encoder_t *encoder = (pn_encoder_t *) ctx;
+ char *pos;
+
+ switch (node->atom.type) {
+ case PN_ARRAY:
+ if ((node->described && node->children == 1) || (!node->described && node->children == 0)) {
+ pn_encoder_writef8(encoder, pn_type2code(encoder, node->type));
+ }
+ // Fallthrough
+ case PN_LIST:
+ case PN_MAP:
+ pos = encoder->position;
+ encoder->position = node->start;
+ if (node->small) {
+ // backfill size
+ size_t size = pos - node->start - 1;
+ pn_encoder_writef8(encoder, size);
+ } else {
+ // backfill size
+ size_t size = pos - node->start - 4;
+ pn_encoder_writef32(encoder, size);
+ }
+ encoder->position = pos;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size)
+{
+ encoder->output = dst;
+ encoder->position = dst;
+ encoder->size = size;
+
+ int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
+ if (err) return err;
+ size_t encoded = encoder->position - encoder->output;
+ if (encoded > size) {
+ pn_error_format(pn_data_error(src), PN_OVERFLOW, "not enough space to encode");
+ return PN_OVERFLOW;
+ }
+ return (ssize_t)encoded;
+}
+
+ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src)
+{
+ encoder->output = 0;
+ encoder->position = 0;
+ encoder->size = 0;
+
+ pn_handle_t save = pn_data_point(src);
+ int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
+ pn_data_restore(src, save);
+
+ if (err) return err;
+ return encoder->position - encoder->output;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/encoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/encoder.h b/proton-c/src/core/encoder.h
new file mode 100644
index 0000000..20876cb
--- /dev/null
+++ b/proton-c/src/core/encoder.h
@@ -0,0 +1,31 @@
+#ifndef _PROTON_ENCODER_H
+#define _PROTON_ENCODER_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+typedef struct pn_encoder_t pn_encoder_t;
+
+pn_encoder_t *pn_encoder(void);
+ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size);
+ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src);
+
+#endif /* encoder.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/engine-internal.h b/proton-c/src/core/engine-internal.h
new file mode 100644
index 0000000..fdaf272
--- /dev/null
+++ b/proton-c/src/core/engine-internal.h
@@ -0,0 +1,375 @@
+#ifndef _PROTON_ENGINE_INTERNAL_H
+#define _PROTON_ENGINE_INTERNAL_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <proton/engine.h>
+#include <proton/types.h>
+
+#include "buffer.h"
+#include "dispatcher.h"
+#include "util.h"
+
+typedef enum pn_endpoint_type_t {CONNECTION, SESSION, SENDER, RECEIVER} pn_endpoint_type_t;
+
+typedef struct pn_endpoint_t pn_endpoint_t;
+
+struct pn_condition_t {
+ pn_string_t *name;
+ pn_string_t *description;
+ pn_data_t *info;
+};
+
+struct pn_endpoint_t {
+ pn_endpoint_type_t type;
+ pn_state_t state;
+ pn_error_t *error;
+ pn_condition_t condition;
+ pn_condition_t remote_condition;
+ pn_endpoint_t *endpoint_next;
+ pn_endpoint_t *endpoint_prev;
+ pn_endpoint_t *transport_next;
+ pn_endpoint_t *transport_prev;
+ int refcount; // when this hits zero we generate a final event
+ bool modified;
+ bool freed;
+ bool referenced;
+};
+
+typedef struct {
+ pn_sequence_t id;
+ bool sent;
+ bool init;
+} pn_delivery_state_t;
+
+typedef struct {
+ pn_sequence_t next;
+ pn_hash_t *deliveries;
+} pn_delivery_map_t;
+
+typedef struct {
+ // XXX: stop using negative numbers
+ uint32_t local_handle;
+ uint32_t remote_handle;
+ pn_sequence_t delivery_count;
+ pn_sequence_t link_credit;
+} pn_link_state_t;
+
+typedef struct {
+ // XXX: stop using negative numbers
+ uint16_t local_channel;
+ uint16_t remote_channel;
+ bool incoming_init;
+ pn_delivery_map_t incoming;
+ pn_delivery_map_t outgoing;
+ pn_sequence_t incoming_transfer_count;
+ pn_sequence_t incoming_window;
+ pn_sequence_t remote_incoming_window;
+ pn_sequence_t outgoing_transfer_count;
+ pn_sequence_t outgoing_window;
+ pn_hash_t *local_handles;
+ pn_hash_t *remote_handles;
+
+ uint64_t disp_code;
+ bool disp_settled;
+ bool disp_type;
+ pn_sequence_t disp_first;
+ pn_sequence_t disp_last;
+ bool disp;
+} pn_session_state_t;
+
+typedef struct pn_io_layer_t {
+ ssize_t (*process_input)(struct pn_transport_t *transport, unsigned int layer, const char *, size_t);
+ ssize_t (*process_output)(struct pn_transport_t *transport, unsigned int layer, char *, size_t);
+ void (*handle_error)(struct pn_transport_t* transport, unsigned int layer);
+ pn_timestamp_t (*process_tick)(struct pn_transport_t *transport, unsigned int layer, pn_timestamp_t);
+ size_t (*buffered_output)(struct pn_transport_t *transport); // how much output is held
+} pn_io_layer_t;
+
+extern const pn_io_layer_t pni_passthru_layer;
+extern const pn_io_layer_t ssl_layer;
+extern const pn_io_layer_t sasl_header_layer;
+extern const pn_io_layer_t sasl_write_header_layer;
+
+// Bit flag defines for the protocol layers
+typedef uint8_t pn_io_layer_flags_t;
+#define LAYER_NONE 0
+#define LAYER_AMQP1 1
+#define LAYER_AMQPSASL 2
+#define LAYER_AMQPSSL 4
+#define LAYER_SSL 8
+
+typedef struct pni_sasl_t pni_sasl_t;
+typedef struct pni_ssl_t pni_ssl_t;
+
+struct pn_transport_t {
+ pn_tracer_t tracer;
+ pni_sasl_t *sasl;
+ pni_ssl_t *ssl;
+ pn_connection_t *connection; // reference counted
+ char *remote_container;
+ char *remote_hostname;
+ pn_data_t *remote_offered_capabilities;
+ pn_data_t *remote_desired_capabilities;
+ pn_data_t *remote_properties;
+ pn_data_t *disp_data;
+ //#define PN_DEFAULT_MAX_FRAME_SIZE (16*1024)
+#define PN_DEFAULT_MAX_FRAME_SIZE (0) /* for now, allow unlimited size */
+ uint32_t local_max_frame;
+ uint32_t remote_max_frame;
+ pn_condition_t remote_condition;
+ pn_condition_t condition;
+ pn_error_t *error;
+
+#define PN_IO_LAYER_CT 3
+ const pn_io_layer_t *io_layers[PN_IO_LAYER_CT];
+
+ /* dead remote detection */
+ pn_millis_t local_idle_timeout;
+ pn_millis_t remote_idle_timeout;
+ pn_timestamp_t dead_remote_deadline;
+ uint64_t last_bytes_input;
+
+ /* keepalive */
+ pn_timestamp_t keepalive_deadline;
+ uint64_t last_bytes_output;
+
+ pn_hash_t *local_channels;
+ pn_hash_t *remote_channels;
+
+
+ /* scratch area */
+ pn_string_t *scratch;
+ pn_data_t *args;
+ pn_data_t *output_args;
+ pn_buffer_t *frame; // frame under construction
+ // Temporary
+ size_t capacity;
+ size_t available; /* number of raw bytes pending output */
+ char *output;
+
+ /* statistics */
+ uint64_t bytes_input;
+ uint64_t bytes_output;
+ uint64_t output_frames_ct;
+ uint64_t input_frames_ct;
+
+ /* output buffered for send */
+ size_t output_size;
+ size_t output_pending;
+ char *output_buf;
+
+ /* input from peer */
+ size_t input_size;
+ size_t input_pending;
+ char *input_buf;
+
+ pn_record_t *context;
+
+ pn_trace_t trace;
+
+ /*
+ * The maximum channel number can be constrained in several ways:
+ * 1. an unchangeable limit imposed by this library code
+ * 2. a limit imposed by the remote peer when the connection is opened,
+ * which this app must honor
+ * 3. a limit imposed by this app, which may be raised and lowered
+ * until the OPEN frame is sent.
+ * These constraints are all summed up in channel_max, below.
+ */
+ #define PN_IMPL_CHANNEL_MAX 32767
+ uint16_t local_channel_max;
+ uint16_t remote_channel_max;
+ uint16_t channel_max;
+
+ pn_io_layer_flags_t allowed_layers;
+ pn_io_layer_flags_t present_layers;
+
+ bool freed;
+ bool open_sent;
+ bool open_rcvd;
+ bool close_sent;
+ bool close_rcvd;
+ bool tail_closed; // input stream closed by driver
+ bool head_closed;
+ bool done_processing; // if true, don't call pn_process again
+ bool posted_idle_timeout;
+ bool server;
+ bool halt;
+ bool auth_required;
+ bool authenticated;
+ bool encryption_required;
+
+ bool referenced;
+};
+
+struct pn_connection_t {
+ pn_endpoint_t endpoint;
+ pn_endpoint_t *endpoint_head;
+ pn_endpoint_t *endpoint_tail;
+ pn_endpoint_t *transport_head; // reference counted
+ pn_endpoint_t *transport_tail;
+ pn_list_t *sessions;
+ pn_list_t *freed;
+ pn_transport_t *transport;
+ pn_delivery_t *work_head;
+ pn_delivery_t *work_tail;
+ pn_delivery_t *tpwork_head; // reference counted
+ pn_delivery_t *tpwork_tail;
+ pn_string_t *container;
+ pn_string_t *hostname;
+ pn_string_t *auth_user;
+ pn_string_t *auth_password;
+ pn_data_t *offered_capabilities;
+ pn_data_t *desired_capabilities;
+ pn_data_t *properties;
+ pn_collector_t *collector;
+ pn_record_t *context;
+ pn_list_t *delivery_pool;
+};
+
+struct pn_session_t {
+ pn_endpoint_t endpoint;
+ pn_connection_t *connection; // reference counted
+ pn_list_t *links;
+ pn_list_t *freed;
+ pn_record_t *context;
+ size_t incoming_capacity;
+ pn_sequence_t incoming_bytes;
+ pn_sequence_t outgoing_bytes;
+ pn_sequence_t incoming_deliveries;
+ pn_sequence_t outgoing_deliveries;
+ pn_sequence_t outgoing_window;
+ pn_session_state_t state;
+};
+
+struct pn_terminus_t {
+ pn_string_t *address;
+ pn_data_t *properties;
+ pn_data_t *capabilities;
+ pn_data_t *outcomes;
+ pn_data_t *filter;
+ pn_durability_t durability;
+ pn_expiry_policy_t expiry_policy;
+ pn_seconds_t timeout;
+ pn_terminus_type_t type;
+ pn_distribution_mode_t distribution_mode;
+ bool dynamic;
+};
+
+struct pn_link_t {
+ pn_endpoint_t endpoint;
+ pn_terminus_t source;
+ pn_terminus_t target;
+ pn_terminus_t remote_source;
+ pn_terminus_t remote_target;
+ pn_link_state_t state;
+ pn_string_t *name;
+ pn_session_t *session; // reference counted
+ pn_delivery_t *unsettled_head;
+ pn_delivery_t *unsettled_tail;
+ pn_delivery_t *current;
+ pn_record_t *context;
+ size_t unsettled_count;
+ pn_sequence_t available;
+ pn_sequence_t credit;
+ pn_sequence_t queued;
+ int drained; // number of drained credits
+ uint8_t snd_settle_mode;
+ uint8_t rcv_settle_mode;
+ uint8_t remote_snd_settle_mode;
+ uint8_t remote_rcv_settle_mode;
+ bool drain_flag_mode; // receiver only
+ bool drain;
+ bool detached;
+};
+
+struct pn_disposition_t {
+ pn_condition_t condition;
+ uint64_t type;
+ pn_data_t *data;
+ pn_data_t *annotations;
+ uint64_t section_offset;
+ uint32_t section_number;
+ bool failed;
+ bool undeliverable;
+ bool settled;
+};
+
+struct pn_delivery_t {
+ pn_disposition_t local;
+ pn_disposition_t remote;
+ pn_link_t *link; // reference counted
+ pn_buffer_t *tag;
+ pn_delivery_t *unsettled_next;
+ pn_delivery_t *unsettled_prev;
+ pn_delivery_t *work_next;
+ pn_delivery_t *work_prev;
+ pn_delivery_t *tpwork_next;
+ pn_delivery_t *tpwork_prev;
+ pn_delivery_state_t state;
+ pn_buffer_t *bytes;
+ pn_record_t *context;
+ bool updated;
+ bool settled; // tracks whether we're in the unsettled list or not
+ bool work;
+ bool tpwork;
+ bool done;
+ bool referenced;
+};
+
+#define PN_SET_LOCAL(OLD, NEW) \
+ (OLD) = ((OLD) & PN_REMOTE_MASK) | (NEW)
+
+#define PN_SET_REMOTE(OLD, NEW) \
+ (OLD) = ((OLD) & PN_LOCAL_MASK) | (NEW)
+
+void pn_link_dump(pn_link_t *link);
+
+void pn_dump(pn_connection_t *conn);
+void pn_transport_sasl_init(pn_transport_t *transport);
+
+void pn_condition_init(pn_condition_t *condition);
+void pn_condition_tini(pn_condition_t *condition);
+void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit);
+void pn_real_settle(pn_delivery_t *delivery); // will free delivery if link is freed
+void pn_clear_tpwork(pn_delivery_t *delivery);
+void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery);
+void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint);
+void pn_connection_bound(pn_connection_t *conn);
+void pn_connection_unbound(pn_connection_t *conn);
+int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...);
+void pn_set_error_layer(pn_transport_t *transport);
+void pn_session_unbound(pn_session_t* ssn);
+void pn_link_unbound(pn_link_t* link);
+void pn_ep_incref(pn_endpoint_t *endpoint);
+void pn_ep_decref(pn_endpoint_t *endpoint);
+
+int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...);
+
+typedef enum {IN, OUT} pn_dir_t;
+
+void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
+ pn_data_t *args, const char *payload, size_t size);
+
+#endif /* engine-internal.h */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[14/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/engine.c b/proton-c/src/core/engine.c
new file mode 100644
index 0000000..e238d5c
--- /dev/null
+++ b/proton-c/src/core/engine.c
@@ -0,0 +1,2231 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "engine-internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include "protocol.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "platform/platform.h"
+#include "platform/platform_fmt.h"
+#include "transport.h"
+
+
+static void pni_session_bound(pn_session_t *ssn);
+static void pni_link_bound(pn_link_t *link);
+
+
+// endpoints
+
+static pn_connection_t *pni_ep_get_connection(pn_endpoint_t *endpoint)
+{
+ switch (endpoint->type) {
+ case CONNECTION:
+ return (pn_connection_t *) endpoint;
+ case SESSION:
+ return ((pn_session_t *) endpoint)->connection;
+ case SENDER:
+ case RECEIVER:
+ return ((pn_link_t *) endpoint)->session->connection;
+ }
+
+ return NULL;
+}
+
+static pn_event_type_t endpoint_event(pn_endpoint_type_t type, bool open) {
+ switch (type) {
+ case CONNECTION:
+ return open ? PN_CONNECTION_LOCAL_OPEN : PN_CONNECTION_LOCAL_CLOSE;
+ case SESSION:
+ return open ? PN_SESSION_LOCAL_OPEN : PN_SESSION_LOCAL_CLOSE;
+ case SENDER:
+ case RECEIVER:
+ return open ? PN_LINK_LOCAL_OPEN : PN_LINK_LOCAL_CLOSE;
+ default:
+ assert(false);
+ return PN_EVENT_NONE;
+ }
+}
+
+static void pn_endpoint_open(pn_endpoint_t *endpoint)
+{
+ if (!(endpoint->state & PN_LOCAL_ACTIVE)) {
+ PN_SET_LOCAL(endpoint->state, PN_LOCAL_ACTIVE);
+ pn_connection_t *conn = pni_ep_get_connection(endpoint);
+ pn_collector_put(conn->collector, PN_OBJECT, endpoint,
+ endpoint_event(endpoint->type, true));
+ pn_modified(conn, endpoint, true);
+ }
+}
+
+static void pn_endpoint_close(pn_endpoint_t *endpoint)
+{
+ if (!(endpoint->state & PN_LOCAL_CLOSED)) {
+ PN_SET_LOCAL(endpoint->state, PN_LOCAL_CLOSED);
+ pn_connection_t *conn = pni_ep_get_connection(endpoint);
+ pn_collector_put(conn->collector, PN_OBJECT, endpoint,
+ endpoint_event(endpoint->type, false));
+ pn_modified(conn, endpoint, true);
+ }
+}
+
+void pn_connection_reset(pn_connection_t *connection)
+{
+ assert(connection);
+ pn_endpoint_t *endpoint = &connection->endpoint;
+ endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
+}
+
+void pn_connection_open(pn_connection_t *connection)
+{
+ assert(connection);
+ pn_endpoint_open(&connection->endpoint);
+}
+
+void pn_connection_close(pn_connection_t *connection)
+{
+ assert(connection);
+ pn_endpoint_close(&connection->endpoint);
+}
+
+static void pni_endpoint_tini(pn_endpoint_t *endpoint);
+
+void pn_connection_release(pn_connection_t *connection)
+{
+ assert(!connection->endpoint.freed);
+ // free those endpoints that haven't been freed by the application
+ LL_REMOVE(connection, endpoint, &connection->endpoint);
+ while (connection->endpoint_head) {
+ pn_endpoint_t *ep = connection->endpoint_head;
+ switch (ep->type) {
+ case SESSION:
+ // note: this will free all child links:
+ pn_session_free((pn_session_t *)ep);
+ break;
+ case SENDER:
+ case RECEIVER:
+ pn_link_free((pn_link_t *)ep);
+ break;
+ default:
+ assert(false);
+ }
+ }
+ connection->endpoint.freed = true;
+ if (!connection->transport) {
+ // no transport available to consume transport work items,
+ // so manually clear them:
+ pn_ep_incref(&connection->endpoint);
+ pn_connection_unbound(connection);
+ }
+ pn_ep_decref(&connection->endpoint);
+}
+
+void pn_connection_free(pn_connection_t *connection) {
+ pn_connection_release(connection);
+ pn_decref(connection);
+}
+
+void pn_connection_bound(pn_connection_t *connection)
+{
+ pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_BOUND);
+ pn_ep_incref(&connection->endpoint);
+
+ size_t nsessions = pn_list_size(connection->sessions);
+ for (size_t i = 0; i < nsessions; i++) {
+ pni_session_bound((pn_session_t *) pn_list_get(connection->sessions, i));
+ }
+}
+
+// invoked when transport has been removed:
+void pn_connection_unbound(pn_connection_t *connection)
+{
+ connection->transport = NULL;
+ if (connection->endpoint.freed) {
+ // connection has been freed prior to unbinding, thus it
+ // cannot be re-assigned to a new transport. Clear the
+ // transport work lists to allow the connection to be freed.
+ while (connection->transport_head) {
+ pn_clear_modified(connection, connection->transport_head);
+ }
+ while (connection->tpwork_head) {
+ pn_clear_tpwork(connection->tpwork_head);
+ }
+ }
+ pn_ep_decref(&connection->endpoint);
+}
+
+pn_record_t *pn_connection_attachments(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->context;
+}
+
+void *pn_connection_get_context(pn_connection_t *conn)
+{
+ // XXX: we should really assert on conn here, but this causes
+ // messenger tests to fail
+ return conn ? pn_record_get(conn->context, PN_LEGCTX) : NULL;
+}
+
+void pn_connection_set_context(pn_connection_t *conn, void *context)
+{
+ assert(conn);
+ pn_record_set(conn->context, PN_LEGCTX, context);
+}
+
+pn_transport_t *pn_connection_transport(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->transport;
+}
+
+void pn_condition_init(pn_condition_t *condition)
+{
+ condition->name = pn_string(NULL);
+ condition->description = pn_string(NULL);
+ condition->info = pn_data(0);
+}
+
+void pn_condition_tini(pn_condition_t *condition)
+{
+ pn_data_free(condition->info);
+ pn_free(condition->description);
+ pn_free(condition->name);
+}
+
+static void pni_add_session(pn_connection_t *conn, pn_session_t *ssn)
+{
+ pn_list_add(conn->sessions, ssn);
+ ssn->connection = conn;
+ pn_incref(conn); // keep around until finalized
+ pn_ep_incref(&conn->endpoint);
+}
+
+static void pni_remove_session(pn_connection_t *conn, pn_session_t *ssn)
+{
+ if (pn_list_remove(conn->sessions, ssn)) {
+ pn_ep_decref(&conn->endpoint);
+ LL_REMOVE(conn, endpoint, &ssn->endpoint);
+ }
+}
+
+pn_connection_t *pn_session_connection(pn_session_t *session)
+{
+ if (!session) return NULL;
+ return session->connection;
+}
+
+void pn_session_open(pn_session_t *session)
+{
+ assert(session);
+ pn_endpoint_open(&session->endpoint);
+}
+
+void pn_session_close(pn_session_t *session)
+{
+ assert(session);
+ pn_endpoint_close(&session->endpoint);
+}
+
+void pn_session_free(pn_session_t *session)
+{
+ assert(!session->endpoint.freed);
+ while(pn_list_size(session->links)) {
+ pn_link_t *link = (pn_link_t *)pn_list_get(session->links, 0);
+ pn_link_free(link);
+ }
+ pni_remove_session(session->connection, session);
+ pn_list_add(session->connection->freed, session);
+ session->endpoint.freed = true;
+ pn_ep_decref(&session->endpoint);
+
+ // the finalize logic depends on endpoint.freed, so we incref/decref
+ // to give it a chance to rerun
+ pn_incref(session);
+ pn_decref(session);
+}
+
+pn_record_t *pn_session_attachments(pn_session_t *session)
+{
+ assert(session);
+ return session->context;
+}
+
+void *pn_session_get_context(pn_session_t *session)
+{
+ return session ? pn_record_get(session->context, PN_LEGCTX) : 0;
+}
+
+void pn_session_set_context(pn_session_t *session, void *context)
+{
+ assert(context);
+ pn_record_set(session->context, PN_LEGCTX, context);
+}
+
+
+static void pni_add_link(pn_session_t *ssn, pn_link_t *link)
+{
+ pn_list_add(ssn->links, link);
+ link->session = ssn;
+ pn_ep_incref(&ssn->endpoint);
+}
+
+static void pni_remove_link(pn_session_t *ssn, pn_link_t *link)
+{
+ if (pn_list_remove(ssn->links, link)) {
+ pn_ep_decref(&ssn->endpoint);
+ LL_REMOVE(ssn->connection, endpoint, &link->endpoint);
+ }
+}
+
+void pn_link_open(pn_link_t *link)
+{
+ assert(link);
+ pn_endpoint_open(&link->endpoint);
+}
+
+void pn_link_close(pn_link_t *link)
+{
+ assert(link);
+ pn_endpoint_close(&link->endpoint);
+}
+
+void pn_link_detach(pn_link_t *link)
+{
+ assert(link);
+ if (link->detached) return;
+
+ link->detached = true;
+ pn_collector_put(link->session->connection->collector, PN_OBJECT, link, PN_LINK_LOCAL_DETACH);
+ pn_modified(link->session->connection, &link->endpoint, true);
+
+}
+
+static void pni_terminus_free(pn_terminus_t *terminus)
+{
+ pn_free(terminus->address);
+ pn_free(terminus->properties);
+ pn_free(terminus->capabilities);
+ pn_free(terminus->outcomes);
+ pn_free(terminus->filter);
+}
+
+void pn_link_free(pn_link_t *link)
+{
+ assert(!link->endpoint.freed);
+ pni_remove_link(link->session, link);
+ pn_list_add(link->session->freed, link);
+ pn_delivery_t *delivery = link->unsettled_head;
+ while (delivery) {
+ pn_delivery_t *next = delivery->unsettled_next;
+ pn_delivery_settle(delivery);
+ delivery = next;
+ }
+ link->endpoint.freed = true;
+ pn_ep_decref(&link->endpoint);
+
+ // the finalize logic depends on endpoint.freed (modified above), so
+ // we incref/decref to give it a chance to rerun
+ pn_incref(link);
+ pn_decref(link);
+}
+
+void *pn_link_get_context(pn_link_t *link)
+{
+ assert(link);
+ return pn_record_get(link->context, PN_LEGCTX);
+}
+
+void pn_link_set_context(pn_link_t *link, void *context)
+{
+ assert(link);
+ pn_record_set(link->context, PN_LEGCTX, context);
+}
+
+pn_record_t *pn_link_attachments(pn_link_t *link)
+{
+ assert(link);
+ return link->context;
+}
+
+void pn_endpoint_init(pn_endpoint_t *endpoint, int type, pn_connection_t *conn)
+{
+ endpoint->type = (pn_endpoint_type_t) type;
+ endpoint->referenced = true;
+ endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
+ endpoint->error = pn_error();
+ pn_condition_init(&endpoint->condition);
+ pn_condition_init(&endpoint->remote_condition);
+ endpoint->endpoint_next = NULL;
+ endpoint->endpoint_prev = NULL;
+ endpoint->transport_next = NULL;
+ endpoint->transport_prev = NULL;
+ endpoint->modified = false;
+ endpoint->freed = false;
+ endpoint->refcount = 1;
+ //fprintf(stderr, "initting 0x%lx\n", (uintptr_t) endpoint);
+
+ LL_ADD(conn, endpoint, endpoint);
+}
+
+void pn_ep_incref(pn_endpoint_t *endpoint)
+{
+ endpoint->refcount++;
+}
+
+static pn_event_type_t pn_final_type(pn_endpoint_type_t type) {
+ switch (type) {
+ case CONNECTION:
+ return PN_CONNECTION_FINAL;
+ case SESSION:
+ return PN_SESSION_FINAL;
+ case SENDER:
+ case RECEIVER:
+ return PN_LINK_FINAL;
+ default:
+ assert(false);
+ return PN_EVENT_NONE;
+ }
+}
+
+static pn_endpoint_t *pn_ep_parent(pn_endpoint_t *endpoint) {
+ switch (endpoint->type) {
+ case CONNECTION:
+ return NULL;
+ case SESSION:
+ return &((pn_session_t *) endpoint)->connection->endpoint;
+ case SENDER:
+ case RECEIVER:
+ return &((pn_link_t *) endpoint)->session->endpoint;
+ default:
+ assert(false);
+ return NULL;
+ }
+}
+
+void pn_ep_decref(pn_endpoint_t *endpoint)
+{
+ assert(endpoint->refcount > 0);
+ endpoint->refcount--;
+ if (endpoint->refcount == 0) {
+ pn_connection_t *conn = pni_ep_get_connection(endpoint);
+ pn_collector_put(conn->collector, PN_OBJECT, endpoint, pn_final_type(endpoint->type));
+ }
+}
+
+static void pni_endpoint_tini(pn_endpoint_t *endpoint)
+{
+ pn_error_free(endpoint->error);
+ pn_condition_tini(&endpoint->remote_condition);
+ pn_condition_tini(&endpoint->condition);
+}
+
+static void pni_free_children(pn_list_t *children, pn_list_t *freed)
+{
+ while (pn_list_size(children) > 0) {
+ pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(children, 0);
+ assert(!endpoint->referenced);
+ pn_free(endpoint);
+ }
+
+ while (pn_list_size(freed) > 0) {
+ pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(freed, 0);
+ assert(!endpoint->referenced);
+ pn_free(endpoint);
+ }
+
+ pn_free(children);
+ pn_free(freed);
+}
+
+static void pn_connection_finalize(void *object)
+{
+ pn_connection_t *conn = (pn_connection_t *) object;
+ pn_endpoint_t *endpoint = &conn->endpoint;
+
+ if (conn->transport) {
+ assert(!conn->transport->referenced);
+ pn_free(conn->transport);
+ }
+
+ // freeing the transport could post events
+ if (pn_refcount(conn) > 0) {
+ return;
+ }
+
+ pni_free_children(conn->sessions, conn->freed);
+ pn_free(conn->context);
+ pn_decref(conn->collector);
+
+ pn_free(conn->container);
+ pn_free(conn->hostname);
+ pn_free(conn->auth_user);
+ pn_free(conn->auth_password);
+ pn_free(conn->offered_capabilities);
+ pn_free(conn->desired_capabilities);
+ pn_free(conn->properties);
+ pni_endpoint_tini(endpoint);
+ pn_free(conn->delivery_pool);
+}
+
+#define pn_connection_initialize NULL
+#define pn_connection_hashcode NULL
+#define pn_connection_compare NULL
+#define pn_connection_inspect NULL
+
+pn_connection_t *pn_connection(void)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_connection);
+ pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, sizeof(pn_connection_t));
+ if (!conn) return NULL;
+
+ conn->endpoint_head = NULL;
+ conn->endpoint_tail = NULL;
+ pn_endpoint_init(&conn->endpoint, CONNECTION, conn);
+ conn->transport_head = NULL;
+ conn->transport_tail = NULL;
+ conn->sessions = pn_list(PN_WEAKREF, 0);
+ conn->freed = pn_list(PN_WEAKREF, 0);
+ conn->transport = NULL;
+ conn->work_head = NULL;
+ conn->work_tail = NULL;
+ conn->tpwork_head = NULL;
+ conn->tpwork_tail = NULL;
+ conn->container = pn_string(NULL);
+ conn->hostname = pn_string(NULL);
+ conn->auth_user = pn_string(NULL);
+ conn->auth_password = pn_string(NULL);
+ conn->offered_capabilities = pn_data(0);
+ conn->desired_capabilities = pn_data(0);
+ conn->properties = pn_data(0);
+ conn->collector = NULL;
+ conn->context = pn_record();
+ conn->delivery_pool = pn_list(PN_OBJECT, 0);
+
+ return conn;
+}
+
+static const pn_event_type_t endpoint_init_event_map[] = {
+ PN_CONNECTION_INIT, /* CONNECTION */
+ PN_SESSION_INIT, /* SESSION */
+ PN_LINK_INIT, /* SENDER */
+ PN_LINK_INIT}; /* RECEIVER */
+
+void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collector)
+{
+ pn_decref(connection->collector);
+ connection->collector = collector;
+ pn_incref(connection->collector);
+ pn_endpoint_t *endpoint = connection->endpoint_head;
+ while (endpoint) {
+ pn_collector_put(connection->collector, PN_OBJECT, endpoint, endpoint_init_event_map[endpoint->type]);
+ endpoint = endpoint->endpoint_next;
+ }
+}
+
+pn_state_t pn_connection_state(pn_connection_t *connection)
+{
+ return connection ? connection->endpoint.state : 0;
+}
+
+pn_error_t *pn_connection_error(pn_connection_t *connection)
+{
+ return connection ? connection->endpoint.error : NULL;
+}
+
+const char *pn_connection_get_container(pn_connection_t *connection)
+{
+ assert(connection);
+ return pn_string_get(connection->container);
+}
+
+void pn_connection_set_container(pn_connection_t *connection, const char *container)
+{
+ assert(connection);
+ pn_string_set(connection->container, container);
+}
+
+const char *pn_connection_get_hostname(pn_connection_t *connection)
+{
+ assert(connection);
+ return pn_string_get(connection->hostname);
+}
+
+void pn_connection_set_hostname(pn_connection_t *connection, const char *hostname)
+{
+ assert(connection);
+ pn_string_set(connection->hostname, hostname);
+}
+
+const char *pn_connection_get_user(pn_connection_t *connection)
+{
+ assert(connection);
+ return pn_string_get(connection->auth_user);
+}
+
+void pn_connection_set_user(pn_connection_t *connection, const char *user)
+{
+ assert(connection);
+ pn_string_set(connection->auth_user, user);
+}
+
+void pn_connection_set_password(pn_connection_t *connection, const char *password)
+{
+ assert(connection);
+ // Make sure the previous password is erased, if there was one.
+ size_t n = pn_string_size(connection->auth_password);
+ const char* s = pn_string_get(connection->auth_password);
+ if (n > 0 && s) memset((void*)s, 0, n);
+ pn_string_set(connection->auth_password, password);
+}
+
+pn_data_t *pn_connection_offered_capabilities(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->offered_capabilities;
+}
+
+pn_data_t *pn_connection_desired_capabilities(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->desired_capabilities;
+}
+
+pn_data_t *pn_connection_properties(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->properties;
+}
+
+pn_data_t *pn_connection_remote_offered_capabilities(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->transport ? connection->transport->remote_offered_capabilities : NULL;
+}
+
+pn_data_t *pn_connection_remote_desired_capabilities(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->transport ? connection->transport->remote_desired_capabilities : NULL;
+}
+
+pn_data_t *pn_connection_remote_properties(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->transport ? connection->transport->remote_properties : NULL;
+}
+
+const char *pn_connection_remote_container(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->transport ? connection->transport->remote_container : NULL;
+}
+
+const char *pn_connection_remote_hostname(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->transport ? connection->transport->remote_hostname : NULL;
+}
+
+pn_delivery_t *pn_work_head(pn_connection_t *connection)
+{
+ assert(connection);
+ return connection->work_head;
+}
+
+pn_delivery_t *pn_work_next(pn_delivery_t *delivery)
+{
+ assert(delivery);
+
+ if (delivery->work)
+ return delivery->work_next;
+ else
+ return pn_work_head(delivery->link->session->connection);
+}
+
+static void pni_add_work(pn_connection_t *connection, pn_delivery_t *delivery)
+{
+ if (!delivery->work)
+ {
+ assert(!delivery->local.settled); // never allow settled deliveries
+ LL_ADD(connection, work, delivery);
+ delivery->work = true;
+ }
+}
+
+static void pni_clear_work(pn_connection_t *connection, pn_delivery_t *delivery)
+{
+ if (delivery->work)
+ {
+ LL_REMOVE(connection, work, delivery);
+ delivery->work = false;
+ }
+}
+
+void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery)
+{
+ pn_link_t *link = pn_delivery_link(delivery);
+ pn_delivery_t *current = pn_link_current(link);
+ if (delivery->updated && !delivery->local.settled) {
+ pni_add_work(connection, delivery);
+ } else if (delivery == current) {
+ if (link->endpoint.type == SENDER) {
+ if (pn_link_credit(link) > 0) {
+ pni_add_work(connection, delivery);
+ } else {
+ pni_clear_work(connection, delivery);
+ }
+ } else {
+ pni_add_work(connection, delivery);
+ }
+ } else {
+ pni_clear_work(connection, delivery);
+ }
+}
+
+static void pni_add_tpwork(pn_delivery_t *delivery)
+{
+ pn_connection_t *connection = delivery->link->session->connection;
+ if (!delivery->tpwork)
+ {
+ LL_ADD(connection, tpwork, delivery);
+ delivery->tpwork = true;
+ }
+ pn_modified(connection, &connection->endpoint, true);
+}
+
+void pn_clear_tpwork(pn_delivery_t *delivery)
+{
+ pn_connection_t *connection = delivery->link->session->connection;
+ if (delivery->tpwork)
+ {
+ LL_REMOVE(connection, tpwork, delivery);
+ delivery->tpwork = false;
+ if (pn_refcount(delivery) > 0) {
+ pn_incref(delivery);
+ pn_decref(delivery);
+ }
+ }
+}
+
+void pn_dump(pn_connection_t *conn)
+{
+ pn_endpoint_t *endpoint = conn->transport_head;
+ while (endpoint)
+ {
+ printf("%p", (void *) endpoint);
+ endpoint = endpoint->transport_next;
+ if (endpoint)
+ printf(" -> ");
+ }
+ printf("\n");
+}
+
+void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit)
+{
+ if (!endpoint->modified) {
+ LL_ADD(connection, transport, endpoint);
+ endpoint->modified = true;
+ }
+
+ if (emit && connection->transport) {
+ pn_collector_put(connection->collector, PN_OBJECT, connection->transport,
+ PN_TRANSPORT);
+ }
+}
+
+void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint)
+{
+ if (endpoint->modified) {
+ LL_REMOVE(connection, transport, endpoint);
+ endpoint->transport_next = NULL;
+ endpoint->transport_prev = NULL;
+ endpoint->modified = false;
+ }
+}
+
+static bool pni_matches(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
+{
+ if (endpoint->type != type) return false;
+
+ if (!state) return true;
+
+ int st = endpoint->state;
+ if ((state & PN_REMOTE_MASK) == 0 || (state & PN_LOCAL_MASK) == 0)
+ return st & state;
+ else
+ return st == state;
+}
+
+pn_endpoint_t *pn_find(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
+{
+ while (endpoint)
+ {
+ if (pni_matches(endpoint, type, state))
+ return endpoint;
+ endpoint = endpoint->endpoint_next;
+ }
+ return NULL;
+}
+
+pn_session_t *pn_session_head(pn_connection_t *conn, pn_state_t state)
+{
+ if (conn)
+ return (pn_session_t *) pn_find(conn->endpoint_head, SESSION, state);
+ else
+ return NULL;
+}
+
+pn_session_t *pn_session_next(pn_session_t *ssn, pn_state_t state)
+{
+ if (ssn)
+ return (pn_session_t *) pn_find(ssn->endpoint.endpoint_next, SESSION, state);
+ else
+ return NULL;
+}
+
+pn_link_t *pn_link_head(pn_connection_t *conn, pn_state_t state)
+{
+ if (!conn) return NULL;
+
+ pn_endpoint_t *endpoint = conn->endpoint_head;
+
+ while (endpoint)
+ {
+ if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
+ return (pn_link_t *) endpoint;
+ endpoint = endpoint->endpoint_next;
+ }
+
+ return NULL;
+}
+
+pn_link_t *pn_link_next(pn_link_t *link, pn_state_t state)
+{
+ if (!link) return NULL;
+
+ pn_endpoint_t *endpoint = link->endpoint.endpoint_next;
+
+ while (endpoint)
+ {
+ if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
+ return (pn_link_t *) endpoint;
+ endpoint = endpoint->endpoint_next;
+ }
+
+ return NULL;
+}
+
+static void pn_session_incref(void *object)
+{
+ pn_session_t *session = (pn_session_t *) object;
+ if (!session->endpoint.referenced) {
+ session->endpoint.referenced = true;
+ pn_incref(session->connection);
+ } else {
+ pn_object_incref(object);
+ }
+}
+
+static bool pn_ep_bound(pn_endpoint_t *endpoint)
+{
+ pn_connection_t *conn = pni_ep_get_connection(endpoint);
+ pn_session_t *ssn;
+ pn_link_t *lnk;
+
+ if (!conn->transport) return false;
+ if (endpoint->modified) return true;
+
+ switch (endpoint->type) {
+ case CONNECTION:
+ return ((pn_connection_t *)endpoint)->transport;
+ case SESSION:
+ ssn = (pn_session_t *) endpoint;
+ return (((int16_t) ssn->state.local_channel) >= 0 || ((int16_t) ssn->state.remote_channel) >= 0);
+ case SENDER:
+ case RECEIVER:
+ lnk = (pn_link_t *) endpoint;
+ return ((int32_t) lnk->state.local_handle) >= 0 || ((int32_t) lnk->state.remote_handle) >= 0;
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+static bool pni_connection_live(pn_connection_t *conn) {
+ return pn_refcount(conn) > 1;
+}
+
+static bool pni_session_live(pn_session_t *ssn) {
+ return pni_connection_live(ssn->connection) || pn_refcount(ssn) > 1;
+}
+
+static bool pni_link_live(pn_link_t *link) {
+ return pni_session_live(link->session) || pn_refcount(link) > 1;
+}
+
+static bool pni_endpoint_live(pn_endpoint_t *endpoint) {
+ switch (endpoint->type) {
+ case CONNECTION:
+ return pni_connection_live((pn_connection_t *)endpoint);
+ case SESSION:
+ return pni_session_live((pn_session_t *) endpoint);
+ case SENDER:
+ case RECEIVER:
+ return pni_link_live((pn_link_t *) endpoint);
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+static bool pni_preserve_child(pn_endpoint_t *endpoint)
+{
+ pn_connection_t *conn = pni_ep_get_connection(endpoint);
+ pn_endpoint_t *parent = pn_ep_parent(endpoint);
+ if (pni_endpoint_live(parent) && (!endpoint->freed || (pn_ep_bound(endpoint)))
+ && endpoint->referenced) {
+ pn_object_incref(endpoint);
+ endpoint->referenced = false;
+ pn_decref(parent);
+ return true;
+ } else {
+ LL_REMOVE(conn, transport, endpoint);
+ return false;
+ }
+}
+
+static void pn_session_finalize(void *object)
+{
+ pn_session_t *session = (pn_session_t *) object;
+ pn_endpoint_t *endpoint = &session->endpoint;
+
+ if (pni_preserve_child(endpoint)) {
+ return;
+ }
+
+ pn_free(session->context);
+ pni_free_children(session->links, session->freed);
+ pni_endpoint_tini(endpoint);
+ pn_delivery_map_free(&session->state.incoming);
+ pn_delivery_map_free(&session->state.outgoing);
+ pn_free(session->state.local_handles);
+ pn_free(session->state.remote_handles);
+ pni_remove_session(session->connection, session);
+ pn_list_remove(session->connection->freed, session);
+
+ if (session->connection->transport) {
+ pn_transport_t *transport = session->connection->transport;
+ pn_hash_del(transport->local_channels, session->state.local_channel);
+ pn_hash_del(transport->remote_channels, session->state.remote_channel);
+ }
+
+ if (endpoint->referenced) {
+ pn_decref(session->connection);
+ }
+}
+
+#define pn_session_new pn_object_new
+#define pn_session_refcount pn_object_refcount
+#define pn_session_decref pn_object_decref
+#define pn_session_reify pn_object_reify
+#define pn_session_initialize NULL
+#define pn_session_hashcode NULL
+#define pn_session_compare NULL
+#define pn_session_inspect NULL
+
+pn_session_t *pn_session(pn_connection_t *conn)
+{
+ assert(conn);
+
+
+ pn_transport_t * transport = pn_connection_transport(conn);
+
+ if(transport) {
+ // channel_max is an index, not a count.
+ if(pn_hash_size(transport->local_channels) > (size_t)transport->channel_max) {
+ pn_transport_logf(transport,
+ "pn_session: too many sessions: %d channel_max is %d",
+ pn_hash_size(transport->local_channels),
+ transport->channel_max);
+ return (pn_session_t *) 0;
+ }
+ }
+
+#define pn_session_free pn_object_free
+ static const pn_class_t clazz = PN_METACLASS(pn_session);
+#undef pn_session_free
+ pn_session_t *ssn = (pn_session_t *) pn_class_new(&clazz, sizeof(pn_session_t));
+ if (!ssn) return NULL;
+ pn_endpoint_init(&ssn->endpoint, SESSION, conn);
+ pni_add_session(conn, ssn);
+ ssn->links = pn_list(PN_WEAKREF, 0);
+ ssn->freed = pn_list(PN_WEAKREF, 0);
+ ssn->context = pn_record();
+ ssn->incoming_capacity = 1024*1024;
+ ssn->incoming_bytes = 0;
+ ssn->outgoing_bytes = 0;
+ ssn->incoming_deliveries = 0;
+ ssn->outgoing_deliveries = 0;
+ ssn->outgoing_window = 2147483647;
+
+ // begin transport state
+ memset(&ssn->state, 0, sizeof(ssn->state));
+ ssn->state.local_channel = (uint16_t)-1;
+ ssn->state.remote_channel = (uint16_t)-1;
+ pn_delivery_map_init(&ssn->state.incoming, 0);
+ pn_delivery_map_init(&ssn->state.outgoing, 0);
+ ssn->state.local_handles = pn_hash(PN_WEAKREF, 0, 0.75);
+ ssn->state.remote_handles = pn_hash(PN_WEAKREF, 0, 0.75);
+ // end transport state
+
+ pn_collector_put(conn->collector, PN_OBJECT, ssn, PN_SESSION_INIT);
+ if (conn->transport) {
+ pni_session_bound(ssn);
+ }
+ pn_decref(ssn);
+ return ssn;
+}
+
+static void pni_session_bound(pn_session_t *ssn)
+{
+ assert(ssn);
+ size_t nlinks = pn_list_size(ssn->links);
+ for (size_t i = 0; i < nlinks; i++) {
+ pni_link_bound((pn_link_t *) pn_list_get(ssn->links, i));
+ }
+}
+
+void pn_session_unbound(pn_session_t* ssn)
+{
+ assert(ssn);
+ ssn->state.local_channel = (uint16_t)-1;
+ ssn->state.remote_channel = (uint16_t)-1;
+ ssn->incoming_bytes = 0;
+ ssn->outgoing_bytes = 0;
+ ssn->incoming_deliveries = 0;
+ ssn->outgoing_deliveries = 0;
+}
+
+size_t pn_session_get_incoming_capacity(pn_session_t *ssn)
+{
+ assert(ssn);
+ return ssn->incoming_capacity;
+}
+
+void pn_session_set_incoming_capacity(pn_session_t *ssn, size_t capacity)
+{
+ assert(ssn);
+ // XXX: should this trigger a flow?
+ ssn->incoming_capacity = capacity;
+}
+
+size_t pn_session_get_outgoing_window(pn_session_t *ssn)
+{
+ assert(ssn);
+ return ssn->outgoing_window;
+}
+
+void pn_session_set_outgoing_window(pn_session_t *ssn, size_t window)
+{
+ assert(ssn);
+ ssn->outgoing_window = window;
+}
+
+size_t pn_session_outgoing_bytes(pn_session_t *ssn)
+{
+ assert(ssn);
+ return ssn->outgoing_bytes;
+}
+
+size_t pn_session_incoming_bytes(pn_session_t *ssn)
+{
+ assert(ssn);
+ return ssn->incoming_bytes;
+}
+
+pn_state_t pn_session_state(pn_session_t *session)
+{
+ return session->endpoint.state;
+}
+
+pn_error_t *pn_session_error(pn_session_t *session)
+{
+ return session->endpoint.error;
+}
+
+static void pni_terminus_init(pn_terminus_t *terminus, pn_terminus_type_t type)
+{
+ terminus->type = type;
+ terminus->address = pn_string(NULL);
+ terminus->durability = PN_NONDURABLE;
+ terminus->expiry_policy = PN_EXPIRE_WITH_SESSION;
+ terminus->timeout = 0;
+ terminus->dynamic = false;
+ terminus->distribution_mode = PN_DIST_MODE_UNSPECIFIED;
+ terminus->properties = pn_data(0);
+ terminus->capabilities = pn_data(0);
+ terminus->outcomes = pn_data(0);
+ terminus->filter = pn_data(0);
+}
+
+static void pn_link_incref(void *object)
+{
+ pn_link_t *link = (pn_link_t *) object;
+ if (!link->endpoint.referenced) {
+ link->endpoint.referenced = true;
+ pn_incref(link->session);
+ } else {
+ pn_object_incref(object);
+ }
+}
+
+static void pn_link_finalize(void *object)
+{
+ pn_link_t *link = (pn_link_t *) object;
+ pn_endpoint_t *endpoint = &link->endpoint;
+
+ if (pni_preserve_child(endpoint)) {
+ return;
+ }
+
+ while (link->unsettled_head) {
+ assert(!link->unsettled_head->referenced);
+ pn_free(link->unsettled_head);
+ }
+
+ pn_free(link->context);
+ pni_terminus_free(&link->source);
+ pni_terminus_free(&link->target);
+ pni_terminus_free(&link->remote_source);
+ pni_terminus_free(&link->remote_target);
+ pn_free(link->name);
+ pni_endpoint_tini(endpoint);
+ pni_remove_link(link->session, link);
+ pn_hash_del(link->session->state.local_handles, link->state.local_handle);
+ pn_hash_del(link->session->state.remote_handles, link->state.remote_handle);
+ pn_list_remove(link->session->freed, link);
+ if (endpoint->referenced) {
+ pn_decref(link->session);
+ }
+}
+
+#define pn_link_refcount pn_object_refcount
+#define pn_link_decref pn_object_decref
+#define pn_link_reify pn_object_reify
+#define pn_link_initialize NULL
+#define pn_link_hashcode NULL
+#define pn_link_compare NULL
+#define pn_link_inspect NULL
+
+pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
+{
+#define pn_link_new pn_object_new
+#define pn_link_free pn_object_free
+ static const pn_class_t clazz = PN_METACLASS(pn_link);
+#undef pn_link_new
+#undef pn_link_free
+ pn_link_t *link = (pn_link_t *) pn_class_new(&clazz, sizeof(pn_link_t));
+
+ pn_endpoint_init(&link->endpoint, type, session->connection);
+ pni_add_link(session, link);
+ pn_incref(session); // keep session until link finalized
+ link->name = pn_string(name);
+ pni_terminus_init(&link->source, PN_SOURCE);
+ pni_terminus_init(&link->target, PN_TARGET);
+ pni_terminus_init(&link->remote_source, PN_UNSPECIFIED);
+ pni_terminus_init(&link->remote_target, PN_UNSPECIFIED);
+ link->unsettled_head = link->unsettled_tail = link->current = NULL;
+ link->unsettled_count = 0;
+ link->available = 0;
+ link->credit = 0;
+ link->queued = 0;
+ link->drain = false;
+ link->drain_flag_mode = true;
+ link->drained = 0;
+ link->context = pn_record();
+ link->snd_settle_mode = PN_SND_MIXED;
+ link->rcv_settle_mode = PN_RCV_FIRST;
+ link->remote_snd_settle_mode = PN_SND_MIXED;
+ link->remote_rcv_settle_mode = PN_RCV_FIRST;
+ link->detached = false;
+
+ // begin transport state
+ link->state.local_handle = -1;
+ link->state.remote_handle = -1;
+ link->state.delivery_count = 0;
+ link->state.link_credit = 0;
+ // end transport state
+
+ pn_collector_put(session->connection->collector, PN_OBJECT, link, PN_LINK_INIT);
+ if (session->connection->transport) {
+ pni_link_bound(link);
+ }
+ pn_decref(link);
+ return link;
+}
+
+static void pni_link_bound(pn_link_t *link)
+{
+}
+
+void pn_link_unbound(pn_link_t* link)
+{
+ assert(link);
+ link->state.local_handle = -1;
+ link->state.remote_handle = -1;
+ link->state.delivery_count = 0;
+ link->state.link_credit = 0;
+}
+
+pn_terminus_t *pn_link_source(pn_link_t *link)
+{
+ return link ? &link->source : NULL;
+}
+
+pn_terminus_t *pn_link_target(pn_link_t *link)
+{
+ return link ? &link->target : NULL;
+}
+
+pn_terminus_t *pn_link_remote_source(pn_link_t *link)
+{
+ return link ? &link->remote_source : NULL;
+}
+
+pn_terminus_t *pn_link_remote_target(pn_link_t *link)
+{
+ return link ? &link->remote_target : NULL;
+}
+
+int pn_terminus_set_type(pn_terminus_t *terminus, pn_terminus_type_t type)
+{
+ if (!terminus) return PN_ARG_ERR;
+ terminus->type = type;
+ return 0;
+}
+
+pn_terminus_type_t pn_terminus_get_type(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->type : (pn_terminus_type_t) 0;
+}
+
+const char *pn_terminus_get_address(pn_terminus_t *terminus)
+{
+ assert(terminus);
+ return pn_string_get(terminus->address);
+}
+
+int pn_terminus_set_address(pn_terminus_t *terminus, const char *address)
+{
+ assert(terminus);
+ return pn_string_set(terminus->address, address);
+}
+
+pn_durability_t pn_terminus_get_durability(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->durability : (pn_durability_t) 0;
+}
+
+int pn_terminus_set_durability(pn_terminus_t *terminus, pn_durability_t durability)
+{
+ if (!terminus) return PN_ARG_ERR;
+ terminus->durability = durability;
+ return 0;
+}
+
+pn_expiry_policy_t pn_terminus_get_expiry_policy(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->expiry_policy : (pn_expiry_policy_t) 0;
+}
+
+int pn_terminus_set_expiry_policy(pn_terminus_t *terminus, pn_expiry_policy_t expiry_policy)
+{
+ if (!terminus) return PN_ARG_ERR;
+ terminus->expiry_policy = expiry_policy;
+ return 0;
+}
+
+pn_seconds_t pn_terminus_get_timeout(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->timeout : 0;
+}
+
+int pn_terminus_set_timeout(pn_terminus_t *terminus, pn_seconds_t timeout)
+{
+ if (!terminus) return PN_ARG_ERR;
+ terminus->timeout = timeout;
+ return 0;
+}
+
+bool pn_terminus_is_dynamic(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->dynamic : false;
+}
+
+int pn_terminus_set_dynamic(pn_terminus_t *terminus, bool dynamic)
+{
+ if (!terminus) return PN_ARG_ERR;
+ terminus->dynamic = dynamic;
+ return 0;
+}
+
+pn_data_t *pn_terminus_properties(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->properties : NULL;
+}
+
+pn_data_t *pn_terminus_capabilities(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->capabilities : NULL;
+}
+
+pn_data_t *pn_terminus_outcomes(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->outcomes : NULL;
+}
+
+pn_data_t *pn_terminus_filter(pn_terminus_t *terminus)
+{
+ return terminus ? terminus->filter : NULL;
+}
+
+pn_distribution_mode_t pn_terminus_get_distribution_mode(const pn_terminus_t *terminus)
+{
+ return terminus ? terminus->distribution_mode : PN_DIST_MODE_UNSPECIFIED;
+}
+
+int pn_terminus_set_distribution_mode(pn_terminus_t *terminus, pn_distribution_mode_t m)
+{
+ if (!terminus) return PN_ARG_ERR;
+ terminus->distribution_mode = m;
+ return 0;
+}
+
+int pn_terminus_copy(pn_terminus_t *terminus, pn_terminus_t *src)
+{
+ if (!terminus || !src) {
+ return PN_ARG_ERR;
+ }
+
+ terminus->type = src->type;
+ int err = pn_terminus_set_address(terminus, pn_terminus_get_address(src));
+ if (err) return err;
+ terminus->durability = src->durability;
+ terminus->expiry_policy = src->expiry_policy;
+ terminus->timeout = src->timeout;
+ terminus->dynamic = src->dynamic;
+ terminus->distribution_mode = src->distribution_mode;
+ err = pn_data_copy(terminus->properties, src->properties);
+ if (err) return err;
+ err = pn_data_copy(terminus->capabilities, src->capabilities);
+ if (err) return err;
+ err = pn_data_copy(terminus->outcomes, src->outcomes);
+ if (err) return err;
+ err = pn_data_copy(terminus->filter, src->filter);
+ if (err) return err;
+ return 0;
+}
+
+pn_link_t *pn_sender(pn_session_t *session, const char *name)
+{
+ return pn_link_new(SENDER, session, name);
+}
+
+pn_link_t *pn_receiver(pn_session_t *session, const char *name)
+{
+ return pn_link_new(RECEIVER, session, name);
+}
+
+pn_state_t pn_link_state(pn_link_t *link)
+{
+ return link->endpoint.state;
+}
+
+pn_error_t *pn_link_error(pn_link_t *link)
+{
+ return link->endpoint.error;
+}
+
+const char *pn_link_name(pn_link_t *link)
+{
+ assert(link);
+ return pn_string_get(link->name);
+}
+
+bool pn_link_is_sender(pn_link_t *link)
+{
+ return link->endpoint.type == SENDER;
+}
+
+bool pn_link_is_receiver(pn_link_t *link)
+{
+ return link->endpoint.type == RECEIVER;
+}
+
+pn_session_t *pn_link_session(pn_link_t *link)
+{
+ assert(link);
+ return link->session;
+}
+
+static void pn_disposition_finalize(pn_disposition_t *ds)
+{
+ pn_free(ds->data);
+ pn_free(ds->annotations);
+ pn_condition_tini(&ds->condition);
+}
+
+static void pn_delivery_incref(void *object)
+{
+ pn_delivery_t *delivery = (pn_delivery_t *) object;
+ if (delivery->link && !delivery->referenced) {
+ delivery->referenced = true;
+ pn_incref(delivery->link);
+ } else {
+ pn_object_incref(object);
+ }
+}
+
+static bool pni_preserve_delivery(pn_delivery_t *delivery)
+{
+ pn_connection_t *conn = delivery->link->session->connection;
+ return !delivery->local.settled || (conn->transport && (delivery->state.init || delivery->tpwork));
+}
+
+static void pn_delivery_finalize(void *object)
+{
+ pn_delivery_t *delivery = (pn_delivery_t *) object;
+ pn_link_t *link = delivery->link;
+ // assert(!delivery->state.init);
+
+ bool pooled = false;
+ bool referenced = true;
+ if (link) {
+ if (pni_link_live(link) && pni_preserve_delivery(delivery) && delivery->referenced) {
+ delivery->referenced = false;
+ pn_object_incref(delivery);
+ pn_decref(link);
+ return;
+ }
+ referenced = delivery->referenced;
+
+ pn_clear_tpwork(delivery);
+ LL_REMOVE(link, unsettled, delivery);
+ pn_delivery_map_del(pn_link_is_sender(link)
+ ? &link->session->state.outgoing
+ : &link->session->state.incoming,
+ delivery);
+ pn_buffer_clear(delivery->tag);
+ pn_buffer_clear(delivery->bytes);
+ pn_record_clear(delivery->context);
+ delivery->settled = true;
+ pn_connection_t *conn = link->session->connection;
+ assert(pn_refcount(delivery) == 0);
+ if (pni_connection_live(conn)) {
+ pn_list_t *pool = link->session->connection->delivery_pool;
+ delivery->link = NULL;
+ pn_list_add(pool, delivery);
+ pooled = true;
+ assert(pn_refcount(delivery) == 1);
+ }
+ }
+
+ if (!pooled) {
+ pn_free(delivery->context);
+ pn_buffer_free(delivery->tag);
+ pn_buffer_free(delivery->bytes);
+ pn_disposition_finalize(&delivery->local);
+ pn_disposition_finalize(&delivery->remote);
+ }
+
+ if (referenced) {
+ pn_decref(link);
+ }
+}
+
+static void pn_disposition_init(pn_disposition_t *ds)
+{
+ ds->data = pn_data(0);
+ ds->annotations = pn_data(0);
+ pn_condition_init(&ds->condition);
+}
+
+static void pn_disposition_clear(pn_disposition_t *ds)
+{
+ ds->type = 0;
+ ds->section_number = 0;
+ ds->section_offset = 0;
+ ds->failed = false;
+ ds->undeliverable = false;
+ ds->settled = false;
+ pn_data_clear(ds->data);
+ pn_data_clear(ds->annotations);
+ pn_condition_clear(&ds->condition);
+}
+
+#define pn_delivery_new pn_object_new
+#define pn_delivery_refcount pn_object_refcount
+#define pn_delivery_decref pn_object_decref
+#define pn_delivery_free pn_object_free
+#define pn_delivery_reify pn_object_reify
+#define pn_delivery_initialize NULL
+#define pn_delivery_hashcode NULL
+#define pn_delivery_compare NULL
+#define pn_delivery_inspect NULL
+
+pn_delivery_tag_t pn_dtag(const char *bytes, size_t size) {
+ pn_delivery_tag_t dtag = {size, bytes};
+ return dtag;
+}
+
+pn_delivery_t *pn_delivery(pn_link_t *link, pn_delivery_tag_t tag)
+{
+ assert(link);
+ pn_list_t *pool = link->session->connection->delivery_pool;
+ pn_delivery_t *delivery = (pn_delivery_t *) pn_list_pop(pool);
+ if (!delivery) {
+ static const pn_class_t clazz = PN_METACLASS(pn_delivery);
+ delivery = (pn_delivery_t *) pn_class_new(&clazz, sizeof(pn_delivery_t));
+ if (!delivery) return NULL;
+ delivery->tag = pn_buffer(16);
+ delivery->bytes = pn_buffer(64);
+ pn_disposition_init(&delivery->local);
+ pn_disposition_init(&delivery->remote);
+ delivery->context = pn_record();
+ } else {
+ assert(!delivery->state.init);
+ }
+ delivery->link = link;
+ pn_incref(delivery->link); // keep link until finalized
+ pn_buffer_clear(delivery->tag);
+ pn_buffer_append(delivery->tag, tag.start, tag.size);
+ pn_disposition_clear(&delivery->local);
+ pn_disposition_clear(&delivery->remote);
+ delivery->updated = false;
+ delivery->settled = false;
+ LL_ADD(link, unsettled, delivery);
+ delivery->referenced = true;
+ delivery->work_next = NULL;
+ delivery->work_prev = NULL;
+ delivery->work = false;
+ delivery->tpwork_next = NULL;
+ delivery->tpwork_prev = NULL;
+ delivery->tpwork = false;
+ pn_buffer_clear(delivery->bytes);
+ delivery->done = false;
+ pn_record_clear(delivery->context);
+
+ // begin delivery state
+ delivery->state.init = false;
+ delivery->state.sent = false;
+ // end delivery state
+
+ if (!link->current)
+ link->current = delivery;
+
+ link->unsettled_count++;
+
+ pn_work_update(link->session->connection, delivery);
+
+ // XXX: could just remove incref above
+ pn_decref(delivery);
+
+ return delivery;
+}
+
+bool pn_delivery_buffered(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ if (delivery->settled) return false;
+ if (pn_link_is_sender(delivery->link)) {
+ pn_delivery_state_t *state = &delivery->state;
+ if (state->sent) {
+ return false;
+ } else {
+ return delivery->done || (pn_buffer_size(delivery->bytes) > 0);
+ }
+ } else {
+ return false;
+ }
+}
+
+int pn_link_unsettled(pn_link_t *link)
+{
+ return link->unsettled_count;
+}
+
+pn_delivery_t *pn_unsettled_head(pn_link_t *link)
+{
+ pn_delivery_t *d = link->unsettled_head;
+ while (d && d->local.settled) {
+ d = d->unsettled_next;
+ }
+ return d;
+}
+
+pn_delivery_t *pn_unsettled_next(pn_delivery_t *delivery)
+{
+ pn_delivery_t *d = delivery->unsettled_next;
+ while (d && d->local.settled) {
+ d = d->unsettled_next;
+ }
+ return d;
+}
+
+bool pn_delivery_current(pn_delivery_t *delivery)
+{
+ pn_link_t *link = delivery->link;
+ return pn_link_current(link) == delivery;
+}
+
+void pn_delivery_dump(pn_delivery_t *d)
+{
+ char tag[1024];
+ pn_bytes_t bytes = pn_buffer_bytes(d->tag);
+ pn_quote_data(tag, 1024, bytes.start, bytes.size);
+ printf("{tag=%s, local.type=%" PRIu64 ", remote.type=%" PRIu64 ", local.settled=%u, "
+ "remote.settled=%u, updated=%u, current=%u, writable=%u, readable=%u, "
+ "work=%u}",
+ tag, d->local.type, d->remote.type, d->local.settled,
+ d->remote.settled, d->updated, pn_delivery_current(d),
+ pn_delivery_writable(d), pn_delivery_readable(d), d->work);
+}
+
+void *pn_delivery_get_context(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ return pn_record_get(delivery->context, PN_LEGCTX);
+}
+
+void pn_delivery_set_context(pn_delivery_t *delivery, void *context)
+{
+ assert(delivery);
+ pn_record_set(delivery->context, PN_LEGCTX, context);
+}
+
+pn_record_t *pn_delivery_attachments(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ return delivery->context;
+}
+
+uint64_t pn_disposition_type(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return disposition->type;
+}
+
+pn_data_t *pn_disposition_data(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return disposition->data;
+}
+
+uint32_t pn_disposition_get_section_number(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return disposition->section_number;
+}
+
+void pn_disposition_set_section_number(pn_disposition_t *disposition, uint32_t section_number)
+{
+ assert(disposition);
+ disposition->section_number = section_number;
+}
+
+uint64_t pn_disposition_get_section_offset(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return disposition->section_offset;
+}
+
+void pn_disposition_set_section_offset(pn_disposition_t *disposition, uint64_t section_offset)
+{
+ assert(disposition);
+ disposition->section_offset = section_offset;
+}
+
+bool pn_disposition_is_failed(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return disposition->failed;
+}
+
+void pn_disposition_set_failed(pn_disposition_t *disposition, bool failed)
+{
+ assert(disposition);
+ disposition->failed = failed;
+}
+
+bool pn_disposition_is_undeliverable(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return disposition->undeliverable;
+}
+
+void pn_disposition_set_undeliverable(pn_disposition_t *disposition, bool undeliverable)
+{
+ assert(disposition);
+ disposition->undeliverable = undeliverable;
+}
+
+pn_data_t *pn_disposition_annotations(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return disposition->annotations;
+}
+
+pn_condition_t *pn_disposition_condition(pn_disposition_t *disposition)
+{
+ assert(disposition);
+ return &disposition->condition;
+}
+
+pn_delivery_tag_t pn_delivery_tag(pn_delivery_t *delivery)
+{
+ if (delivery) {
+ pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
+ return pn_dtag(tag.start, tag.size);
+ } else {
+ return pn_dtag(0, 0);
+ }
+}
+
+pn_delivery_t *pn_link_current(pn_link_t *link)
+{
+ if (!link) return NULL;
+ return link->current;
+}
+
+static void pni_advance_sender(pn_link_t *link)
+{
+ link->current->done = true;
+ link->queued++;
+ link->credit--;
+ link->session->outgoing_deliveries++;
+ pni_add_tpwork(link->current);
+ link->current = link->current->unsettled_next;
+}
+
+static void pni_advance_receiver(pn_link_t *link)
+{
+ link->credit--;
+ link->queued--;
+ link->session->incoming_deliveries--;
+
+ pn_delivery_t *current = link->current;
+ link->session->incoming_bytes -= pn_buffer_size(current->bytes);
+ pn_buffer_clear(current->bytes);
+
+ if (!link->session->state.incoming_window) {
+ pni_add_tpwork(current);
+ }
+
+ link->current = link->current->unsettled_next;
+}
+
+bool pn_link_advance(pn_link_t *link)
+{
+ if (link && link->current) {
+ pn_delivery_t *prev = link->current;
+ if (link->endpoint.type == SENDER) {
+ pni_advance_sender(link);
+ } else {
+ pni_advance_receiver(link);
+ }
+ pn_delivery_t *next = link->current;
+ pn_work_update(link->session->connection, prev);
+ if (next) pn_work_update(link->session->connection, next);
+ return prev != next;
+ } else {
+ return false;
+ }
+}
+
+int pn_link_credit(pn_link_t *link)
+{
+ return link ? link->credit : 0;
+}
+
+int pn_link_available(pn_link_t *link)
+{
+ return link ? link->available : 0;
+}
+
+int pn_link_queued(pn_link_t *link)
+{
+ return link ? link->queued : 0;
+}
+
+int pn_link_remote_credit(pn_link_t *link)
+{
+ assert(link);
+ return link->credit - link->queued;
+}
+
+bool pn_link_get_drain(pn_link_t *link)
+{
+ assert(link);
+ return link->drain;
+}
+
+pn_snd_settle_mode_t pn_link_snd_settle_mode(pn_link_t *link)
+{
+ return link ? (pn_snd_settle_mode_t)link->snd_settle_mode
+ : PN_SND_MIXED;
+}
+
+pn_rcv_settle_mode_t pn_link_rcv_settle_mode(pn_link_t *link)
+{
+ return link ? (pn_rcv_settle_mode_t)link->rcv_settle_mode
+ : PN_RCV_FIRST;
+}
+
+pn_snd_settle_mode_t pn_link_remote_snd_settle_mode(pn_link_t *link)
+{
+ return link ? (pn_snd_settle_mode_t)link->remote_snd_settle_mode
+ : PN_SND_MIXED;
+}
+
+pn_rcv_settle_mode_t pn_link_remote_rcv_settle_mode(pn_link_t *link)
+{
+ return link ? (pn_rcv_settle_mode_t)link->remote_rcv_settle_mode
+ : PN_RCV_FIRST;
+}
+void pn_link_set_snd_settle_mode(pn_link_t *link, pn_snd_settle_mode_t mode)
+{
+ if (link)
+ link->snd_settle_mode = (uint8_t)mode;
+}
+void pn_link_set_rcv_settle_mode(pn_link_t *link, pn_rcv_settle_mode_t mode)
+{
+ if (link)
+ link->rcv_settle_mode = (uint8_t)mode;
+}
+
+void pn_delivery_settle(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ if (!delivery->local.settled) {
+ pn_link_t *link = delivery->link;
+ if (pn_delivery_current(delivery)) {
+ pn_link_advance(link);
+ }
+
+ link->unsettled_count--;
+ delivery->local.settled = true;
+ pni_add_tpwork(delivery);
+ pn_work_update(delivery->link->session->connection, delivery);
+ pn_incref(delivery);
+ pn_decref(delivery);
+ }
+}
+
+void pn_link_offered(pn_link_t *sender, int credit)
+{
+ sender->available = credit;
+}
+
+ssize_t pn_link_send(pn_link_t *sender, const char *bytes, size_t n)
+{
+ pn_delivery_t *current = pn_link_current(sender);
+ if (!current) return PN_EOS;
+ if (!bytes || !n) return 0;
+ pn_buffer_append(current->bytes, bytes, n);
+ sender->session->outgoing_bytes += n;
+ pni_add_tpwork(current);
+ return n;
+}
+
+int pn_link_drained(pn_link_t *link)
+{
+ assert(link);
+ int drained = 0;
+
+ if (pn_link_is_sender(link)) {
+ if (link->drain && link->credit > 0) {
+ link->drained = link->credit;
+ link->credit = 0;
+ pn_modified(link->session->connection, &link->endpoint, true);
+ drained = link->drained;
+ }
+ } else {
+ drained = link->drained;
+ link->drained = 0;
+ }
+
+ return drained;
+}
+
+ssize_t pn_link_recv(pn_link_t *receiver, char *bytes, size_t n)
+{
+ if (!receiver) return PN_ARG_ERR;
+
+ pn_delivery_t *delivery = receiver->current;
+ if (delivery) {
+ size_t size = pn_buffer_get(delivery->bytes, 0, n, bytes);
+ pn_buffer_trim(delivery->bytes, size, 0);
+ if (size) {
+ receiver->session->incoming_bytes -= size;
+ if (!receiver->session->state.incoming_window) {
+ pni_add_tpwork(delivery);
+ }
+ return size;
+ } else {
+ return delivery->done ? PN_EOS : 0;
+ }
+ } else {
+ return PN_STATE_ERR;
+ }
+}
+
+void pn_link_flow(pn_link_t *receiver, int credit)
+{
+ assert(receiver);
+ assert(pn_link_is_receiver(receiver));
+ receiver->credit += credit;
+ pn_modified(receiver->session->connection, &receiver->endpoint, true);
+ if (!receiver->drain_flag_mode) {
+ pn_link_set_drain(receiver, false);
+ receiver->drain_flag_mode = false;
+ }
+}
+
+void pn_link_drain(pn_link_t *receiver, int credit)
+{
+ assert(receiver);
+ assert(pn_link_is_receiver(receiver));
+ pn_link_set_drain(receiver, true);
+ pn_link_flow(receiver, credit);
+ receiver->drain_flag_mode = false;
+}
+
+void pn_link_set_drain(pn_link_t *receiver, bool drain)
+{
+ assert(receiver);
+ assert(pn_link_is_receiver(receiver));
+ receiver->drain = drain;
+ pn_modified(receiver->session->connection, &receiver->endpoint, true);
+ receiver->drain_flag_mode = true;
+}
+
+bool pn_link_draining(pn_link_t *receiver)
+{
+ assert(receiver);
+ assert(pn_link_is_receiver(receiver));
+ return receiver->drain && (pn_link_credit(receiver) > pn_link_queued(receiver));
+}
+
+pn_link_t *pn_delivery_link(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ return delivery->link;
+}
+
+pn_disposition_t *pn_delivery_local(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ return &delivery->local;
+}
+
+uint64_t pn_delivery_local_state(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ return delivery->local.type;
+}
+
+pn_disposition_t *pn_delivery_remote(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ return &delivery->remote;
+}
+
+uint64_t pn_delivery_remote_state(pn_delivery_t *delivery)
+{
+ assert(delivery);
+ return delivery->remote.type;
+}
+
+bool pn_delivery_settled(pn_delivery_t *delivery)
+{
+ return delivery ? delivery->remote.settled : false;
+}
+
+bool pn_delivery_updated(pn_delivery_t *delivery)
+{
+ return delivery ? delivery->updated : false;
+}
+
+void pn_delivery_clear(pn_delivery_t *delivery)
+{
+ delivery->updated = false;
+ pn_work_update(delivery->link->session->connection, delivery);
+}
+
+void pn_delivery_update(pn_delivery_t *delivery, uint64_t state)
+{
+ if (!delivery) return;
+ delivery->local.type = state;
+ pni_add_tpwork(delivery);
+}
+
+bool pn_delivery_writable(pn_delivery_t *delivery)
+{
+ if (!delivery) return false;
+
+ pn_link_t *link = delivery->link;
+ return pn_link_is_sender(link) && pn_delivery_current(delivery) && pn_link_credit(link) > 0;
+}
+
+bool pn_delivery_readable(pn_delivery_t *delivery)
+{
+ if (delivery) {
+ pn_link_t *link = delivery->link;
+ return pn_link_is_receiver(link) && pn_delivery_current(delivery);
+ } else {
+ return false;
+ }
+}
+
+size_t pn_delivery_pending(pn_delivery_t *delivery)
+{
+ return pn_buffer_size(delivery->bytes);
+}
+
+bool pn_delivery_partial(pn_delivery_t *delivery)
+{
+ return !delivery->done;
+}
+
+pn_condition_t *pn_connection_condition(pn_connection_t *connection)
+{
+ assert(connection);
+ return &connection->endpoint.condition;
+}
+
+pn_condition_t *pn_connection_remote_condition(pn_connection_t *connection)
+{
+ assert(connection);
+ pn_transport_t *transport = connection->transport;
+ return transport ? &transport->remote_condition : NULL;
+}
+
+pn_condition_t *pn_session_condition(pn_session_t *session)
+{
+ assert(session);
+ return &session->endpoint.condition;
+}
+
+pn_condition_t *pn_session_remote_condition(pn_session_t *session)
+{
+ assert(session);
+ return &session->endpoint.remote_condition;
+}
+
+pn_condition_t *pn_link_condition(pn_link_t *link)
+{
+ assert(link);
+ return &link->endpoint.condition;
+}
+
+pn_condition_t *pn_link_remote_condition(pn_link_t *link)
+{
+ assert(link);
+ return &link->endpoint.remote_condition;
+}
+
+bool pn_condition_is_set(pn_condition_t *condition)
+{
+ return condition && pn_string_get(condition->name);
+}
+
+void pn_condition_clear(pn_condition_t *condition)
+{
+ assert(condition);
+ pn_string_clear(condition->name);
+ pn_string_clear(condition->description);
+ pn_data_clear(condition->info);
+}
+
+const char *pn_condition_get_name(pn_condition_t *condition)
+{
+ assert(condition);
+ return pn_string_get(condition->name);
+}
+
+int pn_condition_set_name(pn_condition_t *condition, const char *name)
+{
+ assert(condition);
+ return pn_string_set(condition->name, name);
+}
+
+const char *pn_condition_get_description(pn_condition_t *condition)
+{
+ assert(condition);
+ return pn_string_get(condition->description);
+}
+
+int pn_condition_set_description(pn_condition_t *condition, const char *description)
+{
+ assert(condition);
+ return pn_string_set(condition->description, description);
+}
+
+int pn_condition_vformat(pn_condition_t *condition, const char *name, const char *fmt, va_list ap)
+{
+ assert(condition);
+ int err = pn_condition_set_name(condition, name);
+ if (err)
+ return err;
+
+ char text[1024];
+ size_t n = pni_vsnprintf(text, 1024, fmt, ap);
+ if (n >= sizeof(text))
+ text[sizeof(text)-1] = '\0';
+ err = pn_condition_set_description(condition, text);
+ return err;
+}
+
+int pn_condition_format(pn_condition_t *condition, const char *name, const char *fmt, ...)
+{
+ assert(condition);
+ va_list ap;
+ va_start(ap, fmt);
+ int err = pn_condition_vformat(condition, name, fmt, ap);
+ va_end(ap);
+ return err;
+}
+
+pn_data_t *pn_condition_info(pn_condition_t *condition)
+{
+ assert(condition);
+ return condition->info;
+}
+
+bool pn_condition_is_redirect(pn_condition_t *condition)
+{
+ const char *name = pn_condition_get_name(condition);
+ return name && (!strcmp(name, "amqp:connection:redirect") ||
+ !strcmp(name, "amqp:link:redirect"));
+}
+
+const char *pn_condition_redirect_host(pn_condition_t *condition)
+{
+ pn_data_t *data = pn_condition_info(condition);
+ pn_data_rewind(data);
+ pn_data_next(data);
+ pn_data_enter(data);
+ pn_data_lookup(data, "network-host");
+ pn_bytes_t host = pn_data_get_bytes(data);
+ pn_data_rewind(data);
+ return host.start;
+}
+
+int pn_condition_redirect_port(pn_condition_t *condition)
+{
+ pn_data_t *data = pn_condition_info(condition);
+ pn_data_rewind(data);
+ pn_data_next(data);
+ pn_data_enter(data);
+ pn_data_lookup(data, "port");
+ int port = pn_data_get_int(data);
+ pn_data_rewind(data);
+ return port;
+}
+
+pn_connection_t *pn_event_connection(pn_event_t *event)
+{
+ pn_session_t *ssn;
+ pn_transport_t *transport;
+
+ switch (pn_class_id(pn_event_class(event))) {
+ case CID_pn_connection:
+ return (pn_connection_t *) pn_event_context(event);
+ case CID_pn_transport:
+ transport = pn_event_transport(event);
+ if (transport)
+ return transport->connection;
+ return NULL;
+ default:
+ ssn = pn_event_session(event);
+ if (ssn)
+ return pn_session_connection(ssn);
+ }
+ return NULL;
+}
+
+pn_session_t *pn_event_session(pn_event_t *event)
+{
+ pn_link_t *link;
+ switch (pn_class_id(pn_event_class(event))) {
+ case CID_pn_session:
+ return (pn_session_t *) pn_event_context(event);
+ default:
+ link = pn_event_link(event);
+ if (link)
+ return pn_link_session(link);
+ }
+ return NULL;
+}
+
+pn_link_t *pn_event_link(pn_event_t *event)
+{
+ pn_delivery_t *dlv;
+ switch (pn_class_id(pn_event_class(event))) {
+ case CID_pn_link:
+ return (pn_link_t *) pn_event_context(event);
+ default:
+ dlv = pn_event_delivery(event);
+ if (dlv)
+ return pn_delivery_link(dlv);
+ }
+ return NULL;
+}
+
+pn_delivery_t *pn_event_delivery(pn_event_t *event)
+{
+ switch (pn_class_id(pn_event_class(event))) {
+ case CID_pn_delivery:
+ return (pn_delivery_t *) pn_event_context(event);
+ default:
+ return NULL;
+ }
+}
+
+pn_transport_t *pn_event_transport(pn_event_t *event)
+{
+ switch (pn_class_id(pn_event_class(event))) {
+ case CID_pn_transport:
+ return (pn_transport_t *) pn_event_context(event);
+ default:
+ {
+ pn_connection_t *conn = pn_event_connection(event);
+ if (conn)
+ return pn_connection_transport(conn);
+ return NULL;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/error.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/error.c b/proton-c/src/core/error.c
new file mode 100644
index 0000000..70d36fa
--- /dev/null
+++ b/proton-c/src/core/error.c
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "platform/platform.h"
+#include "util.h"
+
+#include <proton/error.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct pn_error_t {
+ char *text;
+ pn_error_t *root;
+ int code;
+};
+
+pn_error_t *pn_error()
+{
+ pn_error_t *error = (pn_error_t *) malloc(sizeof(pn_error_t));
+ if (error != NULL) {
+ error->code = 0;
+ error->text = NULL;
+ error->root = NULL;
+ }
+ return error;
+}
+
+void pn_error_free(pn_error_t *error)
+{
+ if (error) {
+ free(error->text);
+ free(error);
+ }
+}
+
+void pn_error_clear(pn_error_t *error)
+{
+ if (error) {
+ error->code = 0;
+ free(error->text);
+ error->text = NULL;
+ error->root = NULL;
+ }
+}
+
+int pn_error_set(pn_error_t *error, int code, const char *text)
+{
+ assert(error);
+ pn_error_clear(error);
+ if (code) {
+ error->code = code;
+ error->text = pn_strdup(text);
+ }
+ return code;
+}
+
+int pn_error_vformat(pn_error_t *error, int code, const char *fmt, va_list ap)
+{
+ assert(error);
+ char text[1024];
+ int n = pni_vsnprintf(text, 1024, fmt, ap);
+ if (n >= 1024) {
+ text[1023] = '\0';
+ }
+ return pn_error_set(error, code, text);
+}
+
+int pn_error_format(pn_error_t *error, int code, const char *fmt, ...)
+{
+ assert(error);
+ va_list ap;
+ va_start(ap, fmt);
+ int rcode = pn_error_vformat(error, code, fmt, ap);
+ va_end(ap);
+ return rcode;
+}
+
+int pn_error_code(pn_error_t *error)
+{
+ assert(error);
+ return error->code;
+}
+
+const char *pn_error_text(pn_error_t *error)
+{
+ assert(error);
+ return error->text;
+}
+
+int pn_error_copy(pn_error_t *error, pn_error_t *src)
+{
+ assert(error);
+ if (src) {
+ return pn_error_set(error, pn_error_code(src), pn_error_text(src));
+ } else {
+ pn_error_clear(error);
+ return 0;
+ }
+}
+
+const char *pn_code(int code)
+{
+ switch (code)
+ {
+ case 0: return "<ok>";
+ case PN_EOS: return "PN_EOS";
+ case PN_ERR: return "PN_ERR";
+ case PN_OVERFLOW: return "PN_OVERFLOW";
+ case PN_UNDERFLOW: return "PN_UNDERFLOW";
+ case PN_STATE_ERR: return "PN_STATE_ERR";
+ case PN_ARG_ERR: return "PN_ARG_ERR";
+ case PN_TIMEOUT: return "PN_TIMEOUT";
+ case PN_INTR: return "PN_INTR";
+ case PN_OUT_OF_MEMORY: return "PN_OUT_OF_MEMORY";
+ default: return "<unknown>";
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/event.c b/proton-c/src/core/event.c
new file mode 100644
index 0000000..c13f287
--- /dev/null
+++ b/proton-c/src/core/event.c
@@ -0,0 +1,377 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <stdio.h>
+#include <proton/object.h>
+#include <proton/event.h>
+#include <proton/reactor.h>
+#include <assert.h>
+
+struct pn_collector_t {
+ pn_list_t *pool;
+ pn_event_t *head;
+ pn_event_t *tail;
+ bool freed;
+};
+
+struct pn_event_t {
+ pn_list_t *pool;
+ const pn_class_t *clazz;
+ void *context; // depends on clazz
+ pn_record_t *attachments;
+ pn_event_t *next;
+ pn_event_type_t type;
+};
+
+static void pn_collector_initialize(pn_collector_t *collector)
+{
+ collector->pool = pn_list(PN_OBJECT, 0);
+ collector->head = NULL;
+ collector->tail = NULL;
+ collector->freed = false;
+}
+
+static void pn_collector_drain(pn_collector_t *collector)
+{
+ assert(collector);
+
+ while (pn_collector_peek(collector)) {
+ pn_collector_pop(collector);
+ }
+
+ assert(!collector->head);
+ assert(!collector->tail);
+}
+
+static void pn_collector_shrink(pn_collector_t *collector)
+{
+ assert(collector);
+ pn_list_clear(collector->pool);
+}
+
+static void pn_collector_finalize(pn_collector_t *collector)
+{
+ pn_collector_drain(collector);
+ pn_decref(collector->pool);
+}
+
+static int pn_collector_inspect(pn_collector_t *collector, pn_string_t *dst)
+{
+ assert(collector);
+ int err = pn_string_addf(dst, "EVENTS[");
+ if (err) return err;
+ pn_event_t *event = collector->head;
+ bool first = true;
+ while (event) {
+ if (first) {
+ first = false;
+ } else {
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ }
+ err = pn_inspect(event, dst);
+ if (err) return err;
+ event = event->next;
+ }
+ return pn_string_addf(dst, "]");
+}
+
+#define pn_collector_hashcode NULL
+#define pn_collector_compare NULL
+
+PN_CLASSDEF(pn_collector)
+
+pn_collector_t *pn_collector(void)
+{
+ return pn_collector_new();
+}
+
+void pn_collector_free(pn_collector_t *collector)
+{
+ assert(collector);
+ pn_collector_release(collector);
+ pn_decref(collector);
+}
+
+void pn_collector_release(pn_collector_t *collector)
+{
+ assert(collector);
+ if (!collector->freed) {
+ collector->freed = true;
+ pn_collector_drain(collector);
+ pn_collector_shrink(collector);
+ }
+}
+
+pn_event_t *pn_event(void);
+
+pn_event_t *pn_collector_put(pn_collector_t *collector,
+ const pn_class_t *clazz, void *context,
+ pn_event_type_t type)
+{
+ if (!collector) {
+ return NULL;
+ }
+
+ assert(context);
+
+ if (collector->freed) {
+ return NULL;
+ }
+
+ pn_event_t *tail = collector->tail;
+ if (tail && tail->type == type && tail->context == context) {
+ return NULL;
+ }
+
+ clazz = clazz->reify(context);
+
+ pn_event_t *event = (pn_event_t *) pn_list_pop(collector->pool);
+
+ if (!event) {
+ event = pn_event();
+ }
+
+ event->pool = collector->pool;
+ pn_incref(event->pool);
+
+ if (tail) {
+ tail->next = event;
+ collector->tail = event;
+ } else {
+ collector->tail = event;
+ collector->head = event;
+ }
+
+ event->clazz = clazz;
+ event->context = context;
+ event->type = type;
+ pn_class_incref(clazz, event->context);
+
+ return event;
+}
+
+pn_event_t *pn_collector_peek(pn_collector_t *collector)
+{
+ return collector->head;
+}
+
+bool pn_collector_pop(pn_collector_t *collector)
+{
+ pn_event_t *event = collector->head;
+ if (event) {
+ collector->head = event->next;
+ } else {
+ return false;
+ }
+
+ if (!collector->head) {
+ collector->tail = NULL;
+ }
+
+ pn_decref(event);
+ return true;
+}
+
+bool pn_collector_more(pn_collector_t *collector)
+{
+ assert(collector);
+ return collector->head && collector->head->next;
+}
+
+static void pn_event_initialize(pn_event_t *event)
+{
+ event->pool = NULL;
+ event->type = PN_EVENT_NONE;
+ event->clazz = NULL;
+ event->context = NULL;
+ event->next = NULL;
+ event->attachments = pn_record();
+}
+
+static void pn_event_finalize(pn_event_t *event) {
+ // decref before adding to the free list
+ if (event->clazz && event->context) {
+ pn_class_decref(event->clazz, event->context);
+ }
+
+ pn_list_t *pool = event->pool;
+
+ if (pool && pn_refcount(pool) > 1) {
+ event->pool = NULL;
+ event->type = PN_EVENT_NONE;
+ event->clazz = NULL;
+ event->context = NULL;
+ event->next = NULL;
+ pn_record_clear(event->attachments);
+ pn_list_add(pool, event);
+ } else {
+ pn_decref(event->attachments);
+ }
+
+ pn_decref(pool);
+}
+
+static int pn_event_inspect(pn_event_t *event, pn_string_t *dst)
+{
+ assert(event);
+ assert(dst);
+ const char *name = pn_event_type_name(event->type);
+ int err;
+ if (name) {
+ err = pn_string_addf(dst, "(%s", pn_event_type_name(event->type));
+ } else {
+ err = pn_string_addf(dst, "(<%u>", (unsigned int) event->type);
+ }
+ if (err) return err;
+ if (event->context) {
+ err = pn_string_addf(dst, ", ");
+ if (err) return err;
+ err = pn_class_inspect(event->clazz, event->context, dst);
+ if (err) return err;
+ }
+
+ return pn_string_addf(dst, ")");
+}
+
+#define pn_event_hashcode NULL
+#define pn_event_compare NULL
+
+PN_CLASSDEF(pn_event)
+
+pn_event_t *pn_event(void)
+{
+ return pn_event_new();
+}
+
+pn_event_type_t pn_event_type(pn_event_t *event)
+{
+ return event->type;
+}
+
+const pn_class_t *pn_event_class(pn_event_t *event)
+{
+ assert(event);
+ return event->clazz;
+}
+
+void *pn_event_context(pn_event_t *event)
+{
+ assert(event);
+ return event->context;
+}
+
+pn_record_t *pn_event_attachments(pn_event_t *event)
+{
+ assert(event);
+ return event->attachments;
+}
+
+const char *pn_event_type_name(pn_event_type_t type)
+{
+ switch (type) {
+ case PN_EVENT_NONE:
+ return "PN_EVENT_NONE";
+ case PN_REACTOR_INIT:
+ return "PN_REACTOR_INIT";
+ case PN_REACTOR_QUIESCED:
+ return "PN_REACTOR_QUIESCED";
+ case PN_REACTOR_FINAL:
+ return "PN_REACTOR_FINAL";
+ case PN_TIMER_TASK:
+ return "PN_TIMER_TASK";
+ case PN_CONNECTION_INIT:
+ return "PN_CONNECTION_INIT";
+ case PN_CONNECTION_BOUND:
+ return "PN_CONNECTION_BOUND";
+ case PN_CONNECTION_UNBOUND:
+ return "PN_CONNECTION_UNBOUND";
+ case PN_CONNECTION_REMOTE_OPEN:
+ return "PN_CONNECTION_REMOTE_OPEN";
+ case PN_CONNECTION_LOCAL_OPEN:
+ return "PN_CONNECTION_LOCAL_OPEN";
+ case PN_CONNECTION_REMOTE_CLOSE:
+ return "PN_CONNECTION_REMOTE_CLOSE";
+ case PN_CONNECTION_LOCAL_CLOSE:
+ return "PN_CONNECTION_LOCAL_CLOSE";
+ case PN_CONNECTION_FINAL:
+ return "PN_CONNECTION_FINAL";
+ case PN_SESSION_INIT:
+ return "PN_SESSION_INIT";
+ case PN_SESSION_REMOTE_OPEN:
+ return "PN_SESSION_REMOTE_OPEN";
+ case PN_SESSION_LOCAL_OPEN:
+ return "PN_SESSION_LOCAL_OPEN";
+ case PN_SESSION_REMOTE_CLOSE:
+ return "PN_SESSION_REMOTE_CLOSE";
+ case PN_SESSION_LOCAL_CLOSE:
+ return "PN_SESSION_LOCAL_CLOSE";
+ case PN_SESSION_FINAL:
+ return "PN_SESSION_FINAL";
+ case PN_LINK_INIT:
+ return "PN_LINK_INIT";
+ case PN_LINK_REMOTE_OPEN:
+ return "PN_LINK_REMOTE_OPEN";
+ case PN_LINK_LOCAL_OPEN:
+ return "PN_LINK_LOCAL_OPEN";
+ case PN_LINK_REMOTE_CLOSE:
+ return "PN_LINK_REMOTE_CLOSE";
+ case PN_LINK_LOCAL_DETACH:
+ return "PN_LINK_LOCAL_DETACH";
+ case PN_LINK_REMOTE_DETACH:
+ return "PN_LINK_REMOTE_DETACH";
+ case PN_LINK_LOCAL_CLOSE:
+ return "PN_LINK_LOCAL_CLOSE";
+ case PN_LINK_FLOW:
+ return "PN_LINK_FLOW";
+ case PN_LINK_FINAL:
+ return "PN_LINK_FINAL";
+ case PN_DELIVERY:
+ return "PN_DELIVERY";
+ case PN_TRANSPORT:
+ return "PN_TRANSPORT";
+ case PN_TRANSPORT_AUTHENTICATED:
+ return "PN_TRANSPORT_AUTHENTICATED";
+ case PN_TRANSPORT_ERROR:
+ return "PN_TRANSPORT_ERROR";
+ case PN_TRANSPORT_HEAD_CLOSED:
+ return "PN_TRANSPORT_HEAD_CLOSED";
+ case PN_TRANSPORT_TAIL_CLOSED:
+ return "PN_TRANSPORT_TAIL_CLOSED";
+ case PN_TRANSPORT_CLOSED:
+ return "PN_TRANSPORT_CLOSED";
+ case PN_SELECTABLE_INIT:
+ return "PN_SELECTABLE_INIT";
+ case PN_SELECTABLE_UPDATED:
+ return "PN_SELECTABLE_UPDATED";
+ case PN_SELECTABLE_READABLE:
+ return "PN_SELECTABLE_READABLE";
+ case PN_SELECTABLE_WRITABLE:
+ return "PN_SELECTABLE_WRITABLE";
+ case PN_SELECTABLE_ERROR:
+ return "PN_SELECTABLE_ERROR";
+ case PN_SELECTABLE_EXPIRED:
+ return "PN_SELECTABLE_EXPIRED";
+ case PN_SELECTABLE_FINAL:
+ return "PN_SELECTABLE_FINAL";
+ }
+
+ return NULL;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/framing.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/framing.c b/proton-c/src/core/framing.c
new file mode 100644
index 0000000..09bf4bb
--- /dev/null
+++ b/proton-c/src/core/framing.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "framing.h"
+
+// TODO: These are near duplicates of code in codec.c - they should be
+// deduplicated.
+static inline void pn_i_write16(char *bytes, uint16_t value)
+{
+ bytes[0] = 0xFF & (value >> 8);
+ bytes[1] = 0xFF & (value );
+}
+
+
+static inline void pn_i_write32(char *bytes, uint32_t value)
+{
+ bytes[0] = 0xFF & (value >> 24);
+ bytes[1] = 0xFF & (value >> 16);
+ bytes[2] = 0xFF & (value >> 8);
+ bytes[3] = 0xFF & (value );
+}
+
+static inline uint16_t pn_i_read16(const char *bytes)
+{
+ uint16_t a = (uint8_t) bytes[0];
+ uint16_t b = (uint8_t) bytes[1];
+ uint16_t r = a << 8
+ | b;
+ return r;
+}
+
+static inline uint32_t pn_i_read32(const char *bytes)
+{
+ uint32_t a = (uint8_t) bytes[0];
+ uint32_t b = (uint8_t) bytes[1];
+ uint32_t c = (uint8_t) bytes[2];
+ uint32_t d = (uint8_t) bytes[3];
+ uint32_t r = a << 24
+ | b << 16
+ | c << 8
+ | d;
+ return r;
+}
+
+
+ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max)
+{
+ if (available < AMQP_HEADER_SIZE) return 0;
+ uint32_t size = pn_i_read32(&bytes[0]);
+ if (max && size > max) return PN_ERR;
+ if (available < size) return 0;
+ unsigned int doff = 4 * (uint8_t)bytes[4];
+ if (doff < AMQP_HEADER_SIZE || doff > size) return PN_ERR;
+
+ frame->size = size - doff;
+ frame->ex_size = doff - AMQP_HEADER_SIZE;
+ frame->type = bytes[5];
+ frame->channel = pn_i_read16(&bytes[6]);
+ frame->extended = bytes + AMQP_HEADER_SIZE;
+ frame->payload = bytes + doff;
+
+ return size;
+}
+
+size_t pn_write_frame(char *bytes, size_t available, pn_frame_t frame)
+{
+ size_t size = AMQP_HEADER_SIZE + frame.ex_size + frame.size;
+ if (size <= available)
+ {
+ pn_i_write32(&bytes[0], size);
+ int doff = (frame.ex_size + AMQP_HEADER_SIZE - 1)/4 + 1;
+ bytes[4] = doff;
+ bytes[5] = frame.type;
+ pn_i_write16(&bytes[6], frame.channel);
+
+ memmove(bytes + AMQP_HEADER_SIZE, frame.extended, frame.ex_size);
+ memmove(bytes + 4*doff, frame.payload, frame.size);
+ return size;
+ } else {
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/framing.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/framing.h b/proton-c/src/core/framing.h
new file mode 100644
index 0000000..ecb88a4
--- /dev/null
+++ b/proton-c/src/core/framing.h
@@ -0,0 +1,44 @@
+#ifndef PROTON_FRAMING_H
+#define PROTON_FRAMING_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/import_export.h>
+#include <proton/type_compat.h>
+#include <proton/error.h>
+
+#define AMQP_HEADER_SIZE (8)
+#define AMQP_MIN_MAX_FRAME_SIZE ((uint32_t)512) // minimum allowable max-frame
+
+typedef struct {
+ uint8_t type;
+ uint16_t channel;
+ size_t ex_size;
+ const char *extended;
+ size_t size;
+ const char *payload;
+} pn_frame_t;
+
+ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max);
+size_t pn_write_frame(char *bytes, size_t size, pn_frame_t frame);
+
+#endif /* framing.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/log.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/log.c b/proton-c/src/core/log.c
new file mode 100644
index 0000000..ff96ff0
--- /dev/null
+++ b/proton-c/src/core/log.c
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/log.h>
+#include <proton/object.h>
+#include <stdio.h>
+#include "log_private.h"
+#include "util.h"
+
+
+static void stderr_logger(const char *message) {
+ fprintf(stderr, "%s\n", message);
+}
+
+static pn_logger_t logger = stderr_logger;
+static int enabled_env = -1; /* Set from environment variable. */
+static int enabled_call = -1; /* set by pn_log_enable */
+
+void pn_log_enable(bool value) {
+ enabled_call = value;
+}
+
+bool pn_log_enabled(void) {
+ if (enabled_call != -1) return enabled_call; /* Takes precedence */
+ if (enabled_env == -1)
+ enabled_env = pn_env_bool("PN_TRACE_LOG");
+ return enabled_env;
+}
+
+void pn_log_logger(pn_logger_t new_logger) {
+ logger = new_logger;
+ if (!logger) pn_log_enable(false);
+}
+
+void pn_vlogf_impl(const char *fmt, va_list ap) {
+ pn_string_t *msg = pn_string("");
+ pn_string_vformat(msg, fmt, ap);
+ fprintf(stderr, "%s\n", pn_string_get(msg));
+}
+
+/**@internal
+ *
+ * Note: We check pn_log_enabled() in the pn_logf macro *before* calling
+ * pn_logf_impl because evaluating the arguments to that call could have
+ * side-effects with performance impact (e.g. calling functions to construct
+ * complicated messages.) It is important that a disabled log statement results
+ * in nothing more than a call to pn_log_enabled().
+ */
+void pn_logf_impl(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ pn_vlogf_impl(fmt, ap);
+ va_end(ap);
+}
+
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/log_private.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/log_private.h b/proton-c/src/core/log_private.h
new file mode 100644
index 0000000..4725045
--- /dev/null
+++ b/proton-c/src/core/log_private.h
@@ -0,0 +1,54 @@
+#ifndef LOG_PRIVATE_H
+#define LOG_PRIVATE_H
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**@file
+ *
+ * Log messages that are not associated with a transport.
+ */
+
+#include <proton/log.h>
+#include <stdarg.h>
+
+/** Log a printf style message */
+#define pn_logf(...) \
+ do { \
+ if (pn_log_enabled()) \
+ pn_logf_impl(__VA_ARGS__); \
+ } while(0)
+
+/** va_list version of pn_logf */
+#define pn_vlogf(fmt, ap) \
+ do { \
+ if (pn_log_enabled()) \
+ pn_vlogf_impl(fmt, ap); \
+ } while(0)
+
+/** Return true if logging is enabled. */
+bool pn_log_enabled(void);
+
+/**@internal*/
+void pn_logf_impl(const char* fmt, ...);
+/**@internal*/
+void pn_vlogf_impl(const char *fmt, va_list ap);
+
+
+
+#endif
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[17/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/encoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encoder.c b/proton-c/src/codec/encoder.c
deleted file mode 100644
index f8145fc..0000000
--- a/proton-c/src/codec/encoder.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/error.h>
-#include <proton/object.h>
-#include <proton/codec.h>
-#include "encodings.h"
-#include "encoder.h"
-
-#include <string.h>
-
-#include "data.h"
-
-struct pn_encoder_t {
- char *output;
- size_t size;
- char *position;
- pn_error_t *error;
-};
-
-static void pn_encoder_initialize(void *obj)
-{
- pn_encoder_t *encoder = (pn_encoder_t *) obj;
- encoder->output = NULL;
- encoder->size = 0;
- encoder->position = NULL;
- encoder->error = pn_error();
-}
-
-static void pn_encoder_finalize(void *obj) {
- pn_encoder_t *encoder = (pn_encoder_t *) obj;
- pn_error_free(encoder->error);
-}
-
-#define pn_encoder_hashcode NULL
-#define pn_encoder_compare NULL
-#define pn_encoder_inspect NULL
-
-pn_encoder_t *pn_encoder()
-{
- static const pn_class_t clazz = PN_CLASS(pn_encoder);
- return (pn_encoder_t *) pn_class_new(&clazz, sizeof(pn_encoder_t));
-}
-
-static uint8_t pn_type2code(pn_encoder_t *encoder, pn_type_t type)
-{
- switch (type)
- {
- case PN_NULL: return PNE_NULL;
- case PN_BOOL: return PNE_BOOLEAN;
- case PN_UBYTE: return PNE_UBYTE;
- case PN_BYTE: return PNE_BYTE;
- case PN_USHORT: return PNE_USHORT;
- case PN_SHORT: return PNE_SHORT;
- case PN_UINT: return PNE_UINT;
- case PN_INT: return PNE_INT;
- case PN_CHAR: return PNE_UTF32;
- case PN_FLOAT: return PNE_FLOAT;
- case PN_LONG: return PNE_LONG;
- case PN_TIMESTAMP: return PNE_MS64;
- case PN_DOUBLE: return PNE_DOUBLE;
- case PN_DECIMAL32: return PNE_DECIMAL32;
- case PN_DECIMAL64: return PNE_DECIMAL64;
- case PN_DECIMAL128: return PNE_DECIMAL128;
- case PN_UUID: return PNE_UUID;
- case PN_ULONG: return PNE_ULONG;
- case PN_BINARY: return PNE_VBIN32;
- case PN_STRING: return PNE_STR32_UTF8;
- case PN_SYMBOL: return PNE_SYM32;
- case PN_LIST: return PNE_LIST32;
- case PN_ARRAY: return PNE_ARRAY32;
- case PN_MAP: return PNE_MAP32;
- case PN_DESCRIBED: return PNE_DESCRIPTOR;
- default:
- return pn_error_format(encoder->error, PN_ERR, "not a value type: %u\n", type);
- }
-}
-
-static uint8_t pn_node2code(pn_encoder_t *encoder, pni_node_t *node)
-{
- switch (node->atom.type) {
- case PN_LONG:
- if (-128 <= node->atom.u.as_long && node->atom.u.as_long <= 127) {
- return PNE_SMALLLONG;
- } else {
- return PNE_LONG;
- }
- case PN_INT:
- if (-128 <= node->atom.u.as_int && node->atom.u.as_int <= 127) {
- return PNE_SMALLINT;
- } else {
- return PNE_INT;
- }
- case PN_ULONG:
- if (node->atom.u.as_ulong < 256) {
- return PNE_SMALLULONG;
- } else {
- return PNE_ULONG;
- }
- case PN_UINT:
- if (node->atom.u.as_uint < 256) {
- return PNE_SMALLUINT;
- } else {
- return PNE_UINT;
- }
- case PN_BOOL:
- if (node->atom.u.as_bool) {
- return PNE_TRUE;
- } else {
- return PNE_FALSE;
- }
- case PN_STRING:
- if (node->atom.u.as_bytes.size < 256) {
- return PNE_STR8_UTF8;
- } else {
- return PNE_STR32_UTF8;
- }
- case PN_SYMBOL:
- if (node->atom.u.as_bytes.size < 256) {
- return PNE_SYM8;
- } else {
- return PNE_SYM32;
- }
- case PN_BINARY:
- if (node->atom.u.as_bytes.size < 256) {
- return PNE_VBIN8;
- } else {
- return PNE_VBIN32;
- }
- default:
- return pn_type2code(encoder, node->atom.type);
- }
-}
-
-static size_t pn_encoder_remaining(pn_encoder_t *encoder) {
- char * end = encoder->output + encoder->size;
- if (end > encoder->position)
- return end - encoder->position;
- else
- return 0;
-}
-
-static inline void pn_encoder_writef8(pn_encoder_t *encoder, uint8_t value)
-{
- if (pn_encoder_remaining(encoder)) {
- encoder->position[0] = value;
- }
- encoder->position++;
-}
-
-static inline void pn_encoder_writef16(pn_encoder_t *encoder, uint16_t value)
-{
- if (pn_encoder_remaining(encoder) >= 2) {
- encoder->position[0] = 0xFF & (value >> 8);
- encoder->position[1] = 0xFF & (value );
- }
- encoder->position += 2;
-}
-
-static inline void pn_encoder_writef32(pn_encoder_t *encoder, uint32_t value)
-{
- if (pn_encoder_remaining(encoder) >= 4) {
- encoder->position[0] = 0xFF & (value >> 24);
- encoder->position[1] = 0xFF & (value >> 16);
- encoder->position[2] = 0xFF & (value >> 8);
- encoder->position[3] = 0xFF & (value );
- }
- encoder->position += 4;
-}
-
-static inline void pn_encoder_writef64(pn_encoder_t *encoder, uint64_t value) {
- if (pn_encoder_remaining(encoder) >= 8) {
- encoder->position[0] = 0xFF & (value >> 56);
- encoder->position[1] = 0xFF & (value >> 48);
- encoder->position[2] = 0xFF & (value >> 40);
- encoder->position[3] = 0xFF & (value >> 32);
- encoder->position[4] = 0xFF & (value >> 24);
- encoder->position[5] = 0xFF & (value >> 16);
- encoder->position[6] = 0xFF & (value >> 8);
- encoder->position[7] = 0xFF & (value );
- }
- encoder->position += 8;
-}
-
-static inline void pn_encoder_writef128(pn_encoder_t *encoder, char *value) {
- if (pn_encoder_remaining(encoder) >= 16) {
- memmove(encoder->position, value, 16);
- }
- encoder->position += 16;
-}
-
-static inline void pn_encoder_writev8(pn_encoder_t *encoder, const pn_bytes_t *value)
-{
- pn_encoder_writef8(encoder, value->size);
- if (pn_encoder_remaining(encoder) >= value->size)
- memmove(encoder->position, value->start, value->size);
- encoder->position += value->size;
-}
-
-static inline void pn_encoder_writev32(pn_encoder_t *encoder, const pn_bytes_t *value)
-{
- pn_encoder_writef32(encoder, value->size);
- if (pn_encoder_remaining(encoder) >= value->size)
- memmove(encoder->position, value->start, value->size);
- encoder->position += value->size;
-}
-
-/* True if node is an element of an array - not the descriptor. */
-static bool pn_is_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
- return (parent && parent->atom.type == PN_ARRAY) /* In array */
- && !(parent->described && !node->prev); /* Not the descriptor */
-}
-
-/** True if node is the first element of an array, not the descriptor.
- *@pre pn_is_in_array(data, parent, node)
- */
-static bool pn_is_first_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
- if (!node->prev) return !parent->described; /* First node */
- return parent->described && (!pn_data_node(data, node->prev)->prev);
-}
-
-typedef union {
- uint32_t i;
- uint32_t a[2];
- uint64_t l;
- float f;
- double d;
-} conv_t;
-
-static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node)
-{
- pn_encoder_t *encoder = (pn_encoder_t *) ctx;
- pni_node_t *parent = pn_data_node(data, node->parent);
- pn_atom_t *atom = &node->atom;
- uint8_t code;
- conv_t c;
-
- /** In an array we don't write the code before each element, only the first. */
- if (pn_is_in_array(data, parent, node)) {
- code = pn_type2code(encoder, parent->type);
- if (pn_is_first_in_array(data, parent, node)) {
- pn_encoder_writef8(encoder, code);
- }
- } else {
- code = pn_node2code(encoder, node);
- pn_encoder_writef8(encoder, code);
- }
-
- switch (code) {
- case PNE_DESCRIPTOR:
- case PNE_NULL:
- case PNE_TRUE:
- case PNE_FALSE: return 0;
- case PNE_BOOLEAN: pn_encoder_writef8(encoder, atom->u.as_bool); return 0;
- case PNE_UBYTE: pn_encoder_writef8(encoder, atom->u.as_ubyte); return 0;
- case PNE_BYTE: pn_encoder_writef8(encoder, atom->u.as_byte); return 0;
- case PNE_USHORT: pn_encoder_writef16(encoder, atom->u.as_ushort); return 0;
- case PNE_SHORT: pn_encoder_writef16(encoder, atom->u.as_short); return 0;
- case PNE_UINT0: return 0;
- case PNE_SMALLUINT: pn_encoder_writef8(encoder, atom->u.as_uint); return 0;
- case PNE_UINT: pn_encoder_writef32(encoder, atom->u.as_uint); return 0;
- case PNE_SMALLINT: pn_encoder_writef8(encoder, atom->u.as_int); return 0;
- case PNE_INT: pn_encoder_writef32(encoder, atom->u.as_int); return 0;
- case PNE_UTF32: pn_encoder_writef32(encoder, atom->u.as_char); return 0;
- case PNE_ULONG: pn_encoder_writef64(encoder, atom->u.as_ulong); return 0;
- case PNE_SMALLULONG: pn_encoder_writef8(encoder, atom->u.as_ulong); return 0;
- case PNE_LONG: pn_encoder_writef64(encoder, atom->u.as_long); return 0;
- case PNE_SMALLLONG: pn_encoder_writef8(encoder, atom->u.as_long); return 0;
- case PNE_MS64: pn_encoder_writef64(encoder, atom->u.as_timestamp); return 0;
- case PNE_FLOAT: c.f = atom->u.as_float; pn_encoder_writef32(encoder, c.i); return 0;
- case PNE_DOUBLE: c.d = atom->u.as_double; pn_encoder_writef64(encoder, c.l); return 0;
- case PNE_DECIMAL32: pn_encoder_writef32(encoder, atom->u.as_decimal32); return 0;
- case PNE_DECIMAL64: pn_encoder_writef64(encoder, atom->u.as_decimal64); return 0;
- case PNE_DECIMAL128: pn_encoder_writef128(encoder, atom->u.as_decimal128.bytes); return 0;
- case PNE_UUID: pn_encoder_writef128(encoder, atom->u.as_uuid.bytes); return 0;
- case PNE_VBIN8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
- case PNE_VBIN32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
- case PNE_STR8_UTF8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
- case PNE_STR32_UTF8: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
- case PNE_SYM8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
- case PNE_SYM32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
- case PNE_ARRAY32:
- node->start = encoder->position;
- node->small = false;
- // we'll backfill the size on exit
- encoder->position += 4;
- pn_encoder_writef32(encoder, node->described ? node->children - 1 : node->children);
- if (node->described)
- pn_encoder_writef8(encoder, 0);
- return 0;
- case PNE_LIST32:
- case PNE_MAP32:
- node->start = encoder->position;
- node->small = false;
- // we'll backfill the size later
- encoder->position += 4;
- pn_encoder_writef32(encoder, node->children);
- return 0;
- default:
- return pn_error_format(data->error, PN_ERR, "unrecognized encoding: %u", code);
- }
-}
-
-#include <stdio.h>
-
-static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node)
-{
- pn_encoder_t *encoder = (pn_encoder_t *) ctx;
- char *pos;
-
- switch (node->atom.type) {
- case PN_ARRAY:
- if ((node->described && node->children == 1) || (!node->described && node->children == 0)) {
- pn_encoder_writef8(encoder, pn_type2code(encoder, node->type));
- }
- // Fallthrough
- case PN_LIST:
- case PN_MAP:
- pos = encoder->position;
- encoder->position = node->start;
- if (node->small) {
- // backfill size
- size_t size = pos - node->start - 1;
- pn_encoder_writef8(encoder, size);
- } else {
- // backfill size
- size_t size = pos - node->start - 4;
- pn_encoder_writef32(encoder, size);
- }
- encoder->position = pos;
- return 0;
- default:
- return 0;
- }
-}
-
-ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size)
-{
- encoder->output = dst;
- encoder->position = dst;
- encoder->size = size;
-
- int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
- if (err) return err;
- size_t encoded = encoder->position - encoder->output;
- if (encoded > size) {
- pn_error_format(pn_data_error(src), PN_OVERFLOW, "not enough space to encode");
- return PN_OVERFLOW;
- }
- return (ssize_t)encoded;
-}
-
-ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src)
-{
- encoder->output = 0;
- encoder->position = 0;
- encoder->size = 0;
-
- pn_handle_t save = pn_data_point(src);
- int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
- pn_data_restore(src, save);
-
- if (err) return err;
- return encoder->position - encoder->output;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/encoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encoder.h b/proton-c/src/codec/encoder.h
deleted file mode 100644
index 20876cb..0000000
--- a/proton-c/src/codec/encoder.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _PROTON_ENCODER_H
-#define _PROTON_ENCODER_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-typedef struct pn_encoder_t pn_encoder_t;
-
-pn_encoder_t *pn_encoder(void);
-ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size);
-ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src);
-
-#endif /* encoder.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/encodings.h.py
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encodings.h.py b/proton-c/src/codec/encodings.h.py
deleted file mode 100755
index 9f08c6c..0000000
--- a/proton-c/src/codec/encodings.h.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-from __future__ import print_function
-import mllib, optparse, os, sys
-
-xml = os.path.join(os.path.dirname(__file__), "types.xml")
-doc = mllib.xml_parse(xml)
-
-print("/* generated from %s */" % xml)
-print("#ifndef _PROTON_ENCODINGS_H")
-print("#define _PROTON_ENCODINGS_H 1")
-print()
-print("#define PNE_DESCRIPTOR (0x00)")
-
-for enc in doc.query["amqp/section/type/encoding"]:
- name = enc["@name"] or enc.parent["@name"]
- # XXX: a bit hacky
- if name == "ieee-754":
- name = enc.parent["@name"]
- cname = "PNE_" + name.replace("-", "_").upper()
- print("#define %s%s(%s)" % (cname, " "*(20-len(cname)), enc["@code"]))
-
-print()
-print("#endif /* encodings.h */")
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/types.xml
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/types.xml b/proton-c/src/codec/types.xml
deleted file mode 100644
index 4aa9c0f..0000000
--- a/proton-c/src/codec/types.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-Copyright Bank of America, N.A., Barclays Bank PLC, Cisco Systems, Credit
-Suisse, Deutsche Boerse, Envoy Technologies Inc., Goldman Sachs, HCL
-Technologies Ltd, IIT Software GmbH, iMatix Corporation, INETCO Systems Limited,
-Informatica Corporation, JPMorgan Chase & Co., Kaazing Corporation, N.A,
-Microsoft Corporation, my-Channels, Novell, Progress Software, Red Hat Inc.,
-Software AG, Solace Systems Inc., StormMQ Ltd., Tervela Inc., TWIST Process
-Innovations Ltd, VMware, Inc., and WS02 Inc. 2006-2011. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-3. The name of the author may not be used to endorse or promote products
-derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--->
-
-<amqp name="types" xmlns="http://www.amqp.org/schema/amqp.xsd">
- <section name="encodings">
- <type name="null" class="primitive">
- <encoding code="0x40" category="fixed" width="0"/>
- </type>
- <type name="boolean" class="primitive">
- <encoding code="0x56" category="fixed" width="1"/>
- <encoding name="true" code="0x41" category="fixed" width="0"/>
- <encoding name="false" code="0x42" category="fixed" width="0"/>
- </type>
- <type name="ubyte" class="primitive">
- <encoding code="0x50" category="fixed" width="1"/>
- </type>
- <type name="ushort" class="primitive">
- <encoding code="0x60" category="fixed" width="2"/>
- </type>
- <type name="uint" class="primitive">
- <encoding code="0x70" category="fixed" width="4"/>
- <encoding name="smalluint" code="0x52" category="fixed" width="1"/>
- <encoding name="uint0" code="0x43" category="fixed" width="0"/>
- </type>
- <type name="ulong" class="primitive">
- <encoding code="0x80" category="fixed" width="8"/>
- <encoding name="smallulong" code="0x53" category="fixed" width="1"/>
- <encoding name="ulong0" code="0x44" category="fixed" width="0"/>
- </type>
- <type name="byte" class="primitive">
- <encoding code="0x51" category="fixed" width="1"/>
- </type>
- <type name="short" class="primitive">
- <encoding code="0x61" category="fixed" width="2"/>
- </type>
- <type name="int" class="primitive">
- <encoding code="0x71" category="fixed" width="4"/>
- <encoding name="smallint" code="0x54" category="fixed" width="1"/>
- </type>
- <type name="long" class="primitive">
- <encoding code="0x81" category="fixed" width="8"/>
- <encoding name="smalllong" code="0x55" category="fixed" width="1"/>
- </type>
- <type name="float" class="primitive">
- <encoding name="ieee-754" code="0x72" category="fixed" width="4"/>
- </type>
- <type name="double" class="primitive">
- <encoding name="ieee-754" code="0x82" category="fixed" width="8"/>
- </type>
- <type name="decimal32" class="primitive">
- <encoding name="ieee-754" code="0x74" category="fixed" width="4"/>
- </type>
- <type name="decimal64" class="primitive">
- <encoding name="ieee-754" code="0x84" category="fixed" width="8"/>
- </type>
- <type name="decimal128" class="primitive">
- <encoding name="ieee-754" code="0x94" category="fixed" width="16"/>
- </type>
- <type name="char" class="primitive">
- <encoding name="utf32" code="0x73" category="fixed" width="4"/>
- </type>
- <type name="timestamp" class="primitive">
- <encoding name="ms64" code="0x83" category="fixed" width="8"/>
- </type>
- <type name="uuid" class="primitive">
- <encoding code="0x98" category="fixed" width="16"/>
- </type>
- <type name="binary" class="primitive">
- <encoding name="vbin8" code="0xa0" category="variable" width="1"/>
- <encoding name="vbin32" code="0xb0" category="variable" width="4"/>
- </type>
- <type name="string" class="primitive">
- <encoding name="str8-utf8" code="0xa1" category="variable" width="1"/>
- <encoding name="str32-utf8" code="0xb1" category="variable" width="4"/>
- </type>
- <type name="symbol" class="primitive">
- <encoding name="sym8" code="0xa3" category="variable" width="1"/>
- <encoding name="sym32" code="0xb3" category="variable" width="4"/>
- </type>
- <type name="list" class="primitive">
- <encoding name="list0" code="0x45" category="fixed" width="0"/>
- <encoding name="list8" code="0xc0" category="compound" width="1"/>
- <encoding name="list32" code="0xd0" category="compound" width="4"/>
- </type>
- <type name="map" class="primitive">
- <encoding name="map8" code="0xc1" category="compound" width="1"/>
- <encoding name="map32" code="0xd1" category="compound" width="4"/>
- </type>
- <type name="array" class="primitive">
- <encoding name="array8" code="0xe0" category="array" width="1"/>
- <encoding name="array32" code="0xf0" category="array" width="4"/>
- </type>
- </section>
-</amqp>
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/compiler/msvc/snprintf.c
----------------------------------------------------------------------
diff --git a/proton-c/src/compiler/msvc/snprintf.c b/proton-c/src/compiler/msvc/snprintf.c
new file mode 100644
index 0000000..f9c14eb
--- /dev/null
+++ b/proton-c/src/compiler/msvc/snprintf.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "platform/platform.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+// [v]snprintf on Windows only matches C99 when no errors or overflow.
+int pni_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap) {
+ if (fmt == NULL)
+ return -1;
+ if ((buf == NULL) && (count > 0))
+ return -1;
+ if (count > 0) {
+ int n = vsnprintf_s(buf, count, _TRUNCATE, fmt, ap);
+ if (n >= 0) // no overflow
+ return n; // same as C99
+ buf[count-1] = '\0';
+ }
+ // separate call to get needed buffer size on overflow
+ int n = _vscprintf(fmt, ap);
+ if (n >= (int) count)
+ return n;
+ return -1;
+}
+
+int pni_snprintf(char *buf, size_t count, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int n = pni_vsnprintf(buf, count, fmt, ap);
+ va_end(ap);
+ return n;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/config.h
----------------------------------------------------------------------
diff --git a/proton-c/src/config.h b/proton-c/src/config.h
deleted file mode 100644
index 5a2e7bc..0000000
--- a/proton-c/src/config.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*/
-
-#ifndef _PROTON_SRC_CONFIG_H
-#define _PROTON_SRC_CONFIG_H
-
-#ifndef PN_TRANSPORT_INITIAL_FRAME_SIZE
-# define PN_TRANSPORT_INITIAL_FRAME_SIZE (512) /* bytes */
-#endif
-
-#ifndef PN_SASL_MAX_BUFFSIZE
-# define PN_SASL_MAX_BUFFSIZE (32768) /* bytes */
-#endif
-
-#endif /* _PROTON_SRC_CONFIG_H */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/autodetect.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/autodetect.c b/proton-c/src/core/autodetect.c
new file mode 100644
index 0000000..00f6d98
--- /dev/null
+++ b/proton-c/src/core/autodetect.c
@@ -0,0 +1,135 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "autodetect.h"
+
+#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
+#define SSL_HEADER ("AMQP\x02\x01\x00\x00")
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
+
+#define SASL_HEADER_LEN 8
+
+/*
+ * SSLv2 Client Hello format
+ * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
+ *
+ * Bytes 0-1: RECORD-LENGTH
+ * Byte 2: MSG-CLIENT-HELLO (1)
+ * Byte 3: CLIENT-VERSION-MSB
+ * Byte 4: CLIENT-VERSION-LSB
+ *
+ * Allowed versions:
+ * 2.0 - SSLv2
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ *
+ * The version sent in the Client-Hello is the latest version supported by
+ * the client. NSS may send version 3.x in an SSLv2 header for
+ * maximum compatibility.
+ */
+/*
+ * SSLv3/TLS Client Hello format
+ * RFC 2246
+ *
+ * Byte 0: ContentType (handshake - 22)
+ * Bytes 1-2: ProtocolVersion {major, minor}
+ *
+ * Allowed versions:
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ */
+/*
+ * AMQP 1.0 Header
+ *
+ * Bytes 0-3: "AMQP"
+ * Byte 4: 0==AMQP, 2==SSL, 3==SASL
+ * Byte 5: 1
+ * Bytes 6-7: 0
+ */
+/*
+ * AMQP Pre 1.0 Header
+ *
+ * Bytes 0-3: 'AMQP'
+ * Byte 4: 1
+ * Byte 5: 1
+ * Byte 6: 0 (major version)
+ * Byte 7: Minor version
+ */
+pni_protocol_type_t pni_sniff_header(const char *buf, size_t len)
+{
+ if (len < 3) return PNI_PROTOCOL_INSUFFICIENT;
+ bool isSSL3Handshake = buf[0]==22 && // handshake
+ buf[1]==3 && buf[2]<=3; // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+ if (isSSL3Handshake) return PNI_PROTOCOL_SSL;
+
+ bool isFirst3AMQP = buf[0]=='A' && buf[1]=='M' && buf[2]=='Q';
+ bool isFirst3SSL2CLientHello = buf[2]==1; // Client Hello
+ if (!isFirst3AMQP && !isFirst3SSL2CLientHello) return PNI_PROTOCOL_UNKNOWN;
+
+
+ if (len < 4) return PNI_PROTOCOL_INSUFFICIENT;
+ bool isAMQP = isFirst3AMQP && buf[3]=='P';
+ bool isFirst4SSL2ClientHello = isFirst3SSL2CLientHello && (buf[3]==2 || buf[3]==3);
+ if (!isAMQP && !isFirst4SSL2ClientHello) return PNI_PROTOCOL_UNKNOWN;
+
+ if (len < 5) return PNI_PROTOCOL_INSUFFICIENT;
+ bool isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO
+ ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+ (buf[3] == 2 && buf[4] == 0)); // SSL 2
+ if (isSSL2Handshake) return PNI_PROTOCOL_SSL;
+
+ bool isFirst5OldAMQP = isAMQP && buf[4]==1;
+ bool isFirst5AMQP = isAMQP && (buf[4]==0 || buf[4]==2 || buf[4]==3);
+ if (!isFirst5AMQP && !isFirst5OldAMQP) return PNI_PROTOCOL_UNKNOWN;
+
+ if (len < 6) return PNI_PROTOCOL_INSUFFICIENT;
+
+ // Both old and new versions of AMQP have 1 in byte 5
+ if (buf[5]!=1) return PNI_PROTOCOL_UNKNOWN;
+
+ // From here on it must be some sort of AMQP
+ if (len < 8) return PNI_PROTOCOL_INSUFFICIENT;
+ if (buf[6]==0 && buf[7]==0) {
+ // AM<QP 1.0
+ if (buf[4]==0) return PNI_PROTOCOL_AMQP1;
+ if (buf[4]==2) return PNI_PROTOCOL_AMQP_SSL;
+ if (buf[4]==3) return PNI_PROTOCOL_AMQP_SASL;
+ }
+ return PNI_PROTOCOL_AMQP_OTHER;
+}
+
+const char* pni_protocol_name(pni_protocol_type_t p)
+{
+ static const char* names[] = {
+ "Insufficient data to determine protocol",
+ "Unknown protocol",
+ "SSL/TLS connection",
+ "AMQP TLS layer",
+ "AMQP SASL layer",
+ "AMQP 1.0 layer",
+ "Pre standard AMQP connection"
+ };
+ return names[p];
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/autodetect.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/autodetect.h b/proton-c/src/core/autodetect.h
new file mode 100644
index 0000000..12cb7d8
--- /dev/null
+++ b/proton-c/src/core/autodetect.h
@@ -0,0 +1,40 @@
+#ifndef PROTON_AUTODETECT_H
+#define PROTON_AUTODETECT_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/types.h"
+
+typedef enum {
+ PNI_PROTOCOL_INSUFFICIENT,
+ PNI_PROTOCOL_UNKNOWN,
+ PNI_PROTOCOL_SSL,
+ PNI_PROTOCOL_AMQP_SSL,
+ PNI_PROTOCOL_AMQP_SASL,
+ PNI_PROTOCOL_AMQP1,
+ PNI_PROTOCOL_AMQP_OTHER
+} pni_protocol_type_t;
+
+pni_protocol_type_t pni_sniff_header(const char *data, size_t len);
+const char* pni_protocol_name(pni_protocol_type_t p);
+
+#endif
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/buffer.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/buffer.c b/proton-c/src/core/buffer.c
new file mode 100644
index 0000000..c3015f4
--- /dev/null
+++ b/proton-c/src/core/buffer.c
@@ -0,0 +1,310 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/error.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "buffer.h"
+#include "util.h"
+
+struct pn_buffer_t {
+ size_t capacity;
+ size_t start;
+ size_t size;
+ char *bytes;
+};
+
+pn_buffer_t *pn_buffer(size_t capacity)
+{
+ pn_buffer_t *buf = (pn_buffer_t *) malloc(sizeof(pn_buffer_t));
+ if (buf != NULL) {
+ buf->capacity = capacity;
+ buf->start = 0;
+ buf->size = 0;
+ if (capacity > 0) {
+ buf->bytes = (char *)malloc(capacity);
+ if (buf->bytes == NULL) {
+ free(buf);
+ buf = NULL;
+ }
+ }
+ else {
+ buf->bytes = NULL;
+ }
+ }
+ return buf;
+}
+
+void pn_buffer_free(pn_buffer_t *buf)
+{
+ if (buf) {
+ free(buf->bytes);
+ free(buf);
+ }
+}
+
+size_t pn_buffer_size(pn_buffer_t *buf)
+{
+ return buf->size;
+}
+
+size_t pn_buffer_capacity(pn_buffer_t *buf)
+{
+ return buf->capacity;
+}
+
+size_t pn_buffer_available(pn_buffer_t *buf)
+{
+ return buf->capacity - buf->size;
+}
+
+static size_t pni_buffer_head(pn_buffer_t *buf)
+{
+ return buf->start;
+}
+
+static size_t pni_buffer_tail(pn_buffer_t *buf)
+{
+ size_t tail = buf->start + buf->size;
+ if (tail >= buf->capacity)
+ tail -= buf->capacity;
+ return tail;
+}
+
+static bool pni_buffer_wrapped(pn_buffer_t *buf)
+{
+ return buf->size && pni_buffer_head(buf) >= pni_buffer_tail(buf);
+}
+
+static size_t pni_buffer_tail_space(pn_buffer_t *buf)
+{
+ if (pni_buffer_wrapped(buf)) {
+ return pn_buffer_available(buf);
+ } else {
+ return buf->capacity - pni_buffer_tail(buf);
+ }
+}
+
+static size_t pni_buffer_head_space(pn_buffer_t *buf)
+{
+ if (pni_buffer_wrapped(buf)) {
+ return pn_buffer_available(buf);
+ } else {
+ return pni_buffer_head(buf);
+ }
+}
+
+static size_t pni_buffer_head_size(pn_buffer_t *buf)
+{
+ if (pni_buffer_wrapped(buf)) {
+ return buf->capacity - pni_buffer_head(buf);
+ } else {
+ return pni_buffer_tail(buf) - pni_buffer_head(buf);
+ }
+}
+
+static size_t pni_buffer_tail_size(pn_buffer_t *buf)
+{
+ if (pni_buffer_wrapped(buf)) {
+ return pni_buffer_tail(buf);
+ } else {
+ return 0;
+ }
+}
+
+int pn_buffer_ensure(pn_buffer_t *buf, size_t size)
+{
+ size_t old_capacity = buf->capacity;
+ size_t old_head = pni_buffer_head(buf);
+ bool wrapped = pni_buffer_wrapped(buf);
+
+ while (pn_buffer_available(buf) < size) {
+ buf->capacity = 2*(buf->capacity ? buf->capacity : 16);
+ }
+
+ if (buf->capacity != old_capacity) {
+ char* new_bytes = (char *)realloc(buf->bytes, buf->capacity);
+ if (new_bytes) {
+ buf->bytes = new_bytes;
+
+ if (wrapped) {
+ size_t n = old_capacity - old_head;
+ memmove(buf->bytes + buf->capacity - n, buf->bytes + old_head, n);
+ buf->start = buf->capacity - n;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size)
+{
+ int err = pn_buffer_ensure(buf, size);
+ if (err) return err;
+
+ size_t tail = pni_buffer_tail(buf);
+ size_t tail_space = pni_buffer_tail_space(buf);
+ size_t n = pn_min(tail_space, size);
+
+ memmove(buf->bytes + tail, bytes, n);
+ memmove(buf->bytes, bytes + n, size - n);
+
+ buf->size += size;
+
+ return 0;
+}
+
+int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size)
+{
+ int err = pn_buffer_ensure(buf, size);
+ if (err) return err;
+
+ size_t head = pni_buffer_head(buf);
+ size_t head_space = pni_buffer_head_space(buf);
+ size_t n = pn_min(head_space, size);
+
+ memmove(buf->bytes + head - n, bytes + size - n, n);
+ memmove(buf->bytes + buf->capacity - (size - n), bytes, size - n);
+
+ if (buf->start >= size) {
+ buf->start -= size;
+ } else {
+ buf->start = buf->capacity - (size - buf->start);
+ }
+
+ buf->size += size;
+
+ return 0;
+}
+
+static size_t pni_buffer_index(pn_buffer_t *buf, size_t index)
+{
+ size_t result = buf->start + index;
+ if (result >= buf->capacity) result -= buf->capacity;
+ return result;
+}
+
+size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst)
+{
+ size = pn_min(size, buf->size);
+ size_t start = pni_buffer_index(buf, offset);
+ size_t stop = pni_buffer_index(buf, offset + size);
+
+ if (size == 0) return 0;
+
+ size_t sz1;
+ size_t sz2;
+
+ if (start >= stop) {
+ sz1 = buf->capacity - start;
+ sz2 = stop;
+ } else {
+ sz1 = stop - start;
+ sz2 = 0;
+ }
+
+ memmove(dst, buf->bytes + start, sz1);
+ memmove(dst + sz1, buf->bytes, sz2);
+
+ return sz1 + sz2;
+}
+
+int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right)
+{
+ if (left + right > buf->size) return PN_ARG_ERR;
+
+ buf->start += left;
+ if (buf->start >= buf->capacity)
+ buf->start -= buf->capacity;
+
+ buf->size -= left + right;
+
+ return 0;
+}
+
+void pn_buffer_clear(pn_buffer_t *buf)
+{
+ buf->start = 0;
+ buf->size = 0;
+}
+
+static void pn_buffer_rotate (pn_buffer_t *buf, size_t sz) {
+ if (sz == 0) return;
+
+ unsigned c = 0, v = 0;
+ for (; c < buf->capacity; v++) {
+ unsigned t = v, tp = v + sz;
+ char tmp = buf->bytes[v];
+ c++;
+ while (tp != v) {
+ buf->bytes[t] = buf->bytes[tp];
+ t = tp;
+ tp += sz;
+ if (tp >= buf->capacity) tp -= buf->capacity;
+ c++;
+ }
+ buf->bytes[t] = tmp;
+ }
+}
+
+int pn_buffer_defrag(pn_buffer_t *buf)
+{
+ pn_buffer_rotate(buf, buf->start);
+ buf->start = 0;
+ return 0;
+}
+
+pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf)
+{
+ if (buf) {
+ pn_buffer_defrag(buf);
+ return pn_bytes(buf->size, buf->bytes);
+ } else {
+ return pn_bytes(0, NULL);
+ }
+}
+
+pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf)
+{
+ if (buf) {
+ pn_buffer_defrag(buf);
+ pn_rwbytes_t r = {buf->size, buf->bytes};
+ return r;
+ } else {
+ pn_rwbytes_t r = {0, NULL};
+ return r;
+ }
+}
+
+int pn_buffer_print(pn_buffer_t *buf)
+{
+ printf("pn_buffer(\"");
+ pn_print_data(buf->bytes + pni_buffer_head(buf), pni_buffer_head_size(buf));
+ pn_print_data(buf->bytes, pni_buffer_tail_size(buf));
+ printf("\")");
+ return 0;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/buffer.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/buffer.h b/proton-c/src/core/buffer.h
new file mode 100644
index 0000000..da557ef
--- /dev/null
+++ b/proton-c/src/core/buffer.h
@@ -0,0 +1,54 @@
+#ifndef PROTON_BUFFER_H
+#define PROTON_BUFFER_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/import_export.h>
+#include <proton/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pn_buffer_t pn_buffer_t;
+
+pn_buffer_t *pn_buffer(size_t capacity);
+void pn_buffer_free(pn_buffer_t *buf);
+size_t pn_buffer_size(pn_buffer_t *buf);
+size_t pn_buffer_capacity(pn_buffer_t *buf);
+size_t pn_buffer_available(pn_buffer_t *buf);
+int pn_buffer_ensure(pn_buffer_t *buf, size_t size);
+int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size);
+int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size);
+size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst);
+int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right);
+void pn_buffer_clear(pn_buffer_t *buf);
+int pn_buffer_defrag(pn_buffer_t *buf);
+pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf);
+pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf);
+int pn_buffer_print(pn_buffer_t *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* buffer.h */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[11/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/transport.h b/proton-c/src/core/transport.h
new file mode 100644
index 0000000..66ebc51
--- /dev/null
+++ b/proton-c/src/core/transport.h
@@ -0,0 +1,31 @@
+#ifndef _PROTON_TRANSPORT_INTERNAL_H
+#define _PROTON_TRANSPORT_INTERNAL_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next);
+void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery);
+void pn_delivery_map_free(pn_delivery_map_t *db);
+void pn_unmap_handle(pn_session_t *ssn, pn_link_t *link);
+void pn_unmap_channel(pn_transport_t *transport, pn_session_t *ssn);
+
+#endif /* transport.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/types.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/types.c b/proton-c/src/core/types.c
new file mode 100644
index 0000000..dbd18d0
--- /dev/null
+++ b/proton-c/src/core/types.c
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/types.h>
+
+pn_bytes_t pn_bytes(size_t size, const char *start)
+{
+ pn_bytes_t bytes = {size, start};
+ return bytes;
+}
+
+pn_rwbytes_t pn_rwbytes(size_t size, char *start)
+{
+ pn_rwbytes_t bytes = {size, start};
+ return bytes;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/util.c b/proton-c/src/core/util.c
new file mode 100644
index 0000000..62eec9a
--- /dev/null
+++ b/proton-c/src/core/util.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <proton/type_compat.h>
+#include <ctype.h>
+#include <string.h>
+#include <proton/error.h>
+#include <proton/types.h>
+#include "util.h"
+
+ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size)
+{
+ int idx = 0;
+ for (unsigned i = 0; i < size; i++)
+ {
+ uint8_t c = src[i];
+ if (isprint(c)) {
+ if (idx < (int) (capacity - 1)) {
+ dst[idx++] = c;
+ } else {
+ if (idx > 0) {
+ dst[idx - 1] = '\0';
+ }
+ return PN_OVERFLOW;
+ }
+ } else {
+ if (idx < (int) (capacity - 4)) {
+ idx += sprintf(dst + idx, "\\x%.2x", c);
+ } else {
+ if (idx > 0) {
+ dst[idx - 1] = '\0';
+ }
+ return PN_OVERFLOW;
+ }
+ }
+ }
+
+ dst[idx] = '\0';
+ return idx;
+}
+
+int pn_quote(pn_string_t *dst, const char *src, size_t size)
+{
+ while (true) {
+ size_t str_size = pn_string_size(dst);
+ char *str = pn_string_buffer(dst) + str_size;
+ size_t capacity = pn_string_capacity(dst) - str_size;
+ ssize_t ssize = pn_quote_data(str, capacity, src, size);
+ if (ssize == PN_OVERFLOW) {
+ int err = pn_string_grow(dst, (str_size + capacity) ? 2*(str_size + capacity) : 16);
+ if (err) return err;
+ } else if (ssize >= 0) {
+ return pn_string_resize(dst, str_size + ssize);
+ } else {
+ return ssize;
+ }
+ }
+}
+
+void pn_fprint_data(FILE *stream, const char *bytes, size_t size)
+{
+ char buf[256];
+ ssize_t n = pn_quote_data(buf, 256, bytes, size);
+ if (n >= 0) {
+ fputs(buf, stream);
+ } else {
+ if (n == PN_OVERFLOW) {
+ fputs(buf, stream);
+ fputs("... (truncated)", stream);
+ }
+ else
+ fprintf(stderr, "pn_quote_data: %s\n", pn_code(n));
+ }
+}
+
+void pn_print_data(const char *bytes, size_t size)
+{
+ pn_fprint_data(stdout, bytes, size);
+}
+
+int pn_strcasecmp(const char *a, const char *b)
+{
+ int diff;
+ while (*b) {
+ char aa = *a++, bb = *b++;
+ diff = tolower(aa)-tolower(bb);
+ if ( diff!=0 ) return diff;
+ }
+ return *a;
+}
+
+int pn_strncasecmp(const char* a, const char* b, size_t len)
+{
+ int diff = 0;
+ while (*b && len > 0) {
+ char aa = *a++, bb = *b++;
+ diff = tolower(aa)-tolower(bb);
+ if ( diff!=0 ) return diff;
+ --len;
+ };
+ return len==0 ? diff : *a;
+}
+
+bool pn_env_bool(const char *name)
+{
+ char *v = getenv(name);
+ return v && (!pn_strcasecmp(v, "true") || !pn_strcasecmp(v, "1") ||
+ !pn_strcasecmp(v, "yes") || !pn_strcasecmp(v, "on"));
+}
+
+char *pn_strdup(const char *src)
+{
+ if (!src) return NULL;
+ char *dest = (char *) malloc(strlen(src)+1);
+ if (!dest) return NULL;
+ return strcpy(dest, src);
+}
+
+char *pn_strndup(const char *src, size_t n)
+{
+ if (src) {
+ unsigned size = 0;
+ for (const char *c = src; size < n && *c; c++) {
+ size++;
+ }
+
+ char *dest = (char *) malloc(size + 1);
+ if (!dest) return NULL;
+ strncpy(dest, src, n);
+ dest[size] = '\0';
+ return dest;
+ } else {
+ return NULL;
+ }
+}
+
+// which timestamp will expire next, or zero if none set
+pn_timestamp_t pn_timestamp_min( pn_timestamp_t a, pn_timestamp_t b )
+{
+ if (a && b) return pn_min(a, b);
+ if (a) return a;
+ return b;
+}
+
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/util.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/util.h b/proton-c/src/core/util.h
new file mode 100644
index 0000000..b54f689
--- /dev/null
+++ b/proton-c/src/core/util.h
@@ -0,0 +1,123 @@
+#ifndef _PROTON_SRC_UTIL_H
+#define _PROTON_SRC_UTIL_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <errno.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <proton/types.h>
+#include <proton/object.h>
+
+ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size);
+int pn_quote(pn_string_t *dst, const char *src, size_t size);
+void pn_fprint_data(FILE *stream, const char *bytes, size_t size);
+void pn_print_data(const char *bytes, size_t size);
+bool pn_env_bool(const char *name);
+pn_timestamp_t pn_timestamp_min(pn_timestamp_t a, pn_timestamp_t b);
+
+char *pn_strdup(const char *src);
+char *pn_strndup(const char *src, size_t n);
+int pn_strcasecmp(const char* a, const char* b);
+int pn_strncasecmp(const char* a, const char* b, size_t len);
+
+#define DIE_IFR(EXPR, STRERR) \
+ do { \
+ int __code__ = (EXPR); \
+ if (__code__) { \
+ fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__, \
+ #EXPR, STRERR(__code__), __code__); \
+ exit(-1); \
+ } \
+ } while (0)
+
+#define DIE_IFE(EXPR) \
+ do { \
+ if ((EXPR) == -1) { \
+ int __code__ = errno; \
+ fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__, \
+ #EXPR, strerror(__code__), __code__); \
+ exit(-1); \
+ } \
+ } while (0)
+
+
+#define LL_HEAD(ROOT, LIST) ((ROOT)-> LIST ## _head)
+#define LL_TAIL(ROOT, LIST) ((ROOT)-> LIST ## _tail)
+#define LL_ADD(ROOT, LIST, NODE) \
+ { \
+ (NODE)-> LIST ## _next = NULL; \
+ (NODE)-> LIST ## _prev = (ROOT)-> LIST ## _tail; \
+ if (LL_TAIL(ROOT, LIST)) \
+ LL_TAIL(ROOT, LIST)-> LIST ## _next = (NODE); \
+ LL_TAIL(ROOT, LIST) = (NODE); \
+ if (!LL_HEAD(ROOT, LIST)) LL_HEAD(ROOT, LIST) = (NODE); \
+ }
+
+#define LL_POP(ROOT, LIST, TYPE) \
+ { \
+ if (LL_HEAD(ROOT, LIST)) { \
+ TYPE *_old = LL_HEAD(ROOT, LIST); \
+ LL_HEAD(ROOT, LIST) = LL_HEAD(ROOT, LIST)-> LIST ## _next; \
+ _old-> LIST ## _next = NULL; \
+ if (_old == LL_TAIL(ROOT, LIST)) { \
+ LL_TAIL(ROOT, LIST) = NULL; \
+ } else { \
+ LL_HEAD(ROOT, LIST)-> LIST ## _prev = NULL; \
+ } \
+ } \
+ }
+
+#define LL_REMOVE(ROOT, LIST, NODE) \
+ { \
+ if ((NODE)-> LIST ## _prev) \
+ (NODE)-> LIST ## _prev-> LIST ## _next = (NODE)-> LIST ## _next; \
+ if ((NODE)-> LIST ## _next) \
+ (NODE)-> LIST ## _next-> LIST ## _prev = (NODE)-> LIST ## _prev; \
+ if ((NODE) == LL_HEAD(ROOT, LIST)) \
+ LL_HEAD(ROOT, LIST) = (NODE)-> LIST ## _next; \
+ if ((NODE) == LL_TAIL(ROOT, LIST)) \
+ LL_TAIL(ROOT, LIST) = (NODE)-> LIST ## _prev; \
+ }
+
+#define pn_min(X,Y) ((X) > (Y) ? (Y) : (X))
+#define pn_max(X,Y) ((X) < (Y) ? (Y) : (X))
+
+#define PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE) \
+ while ((CAPACITY) < (COUNT)) { \
+ (CAPACITY) = (CAPACITY) ? 2 * (CAPACITY) : 16; \
+ (ARRAY) = (TYPE *) realloc((ARRAY), (CAPACITY) * sizeof (TYPE)); \
+ } \
+
+#define PN_ENSUREZ(ARRAY, CAPACITY, COUNT, TYPE) \
+ { \
+ size_t _old_capacity = (CAPACITY); \
+ PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE); \
+ memset((ARRAY) + _old_capacity, 0, \
+ sizeof(TYPE)*((CAPACITY) - _old_capacity)); \
+ }
+
+#endif /* util.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/dispatch_actions.h
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatch_actions.h b/proton-c/src/dispatch_actions.h
deleted file mode 100644
index bae8438..0000000
--- a/proton-c/src/dispatch_actions.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _PROTON_DISPATCH_ACTIONS_H
-#define _PROTON_DISPATCH_ACTIONS_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "dispatcher/dispatcher.h"
-
-#define AMQP_FRAME_TYPE (0)
-#define SASL_FRAME_TYPE (1)
-
-
-/* AMQP actions */
-int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-
-/* SASL actions */
-int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-
-#endif // _PROTON_DISPATCH_ACTIONS_H
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/dispatcher/dispatcher.c
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.c b/proton-c/src/dispatcher/dispatcher.c
deleted file mode 100644
index 0bd3f7b..0000000
--- a/proton-c/src/dispatcher/dispatcher.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "dispatcher.h"
-
-#include "framing/framing.h"
-#include "protocol.h"
-#include "engine/engine-internal.h"
-
-#include "dispatch_actions.h"
-
-int pni_bad_frame(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
- pn_transport_logf(transport, "Error dispatching frame: type: %d: Unknown performative", frame_type);
- return PN_ERR;
-}
-
-int pni_bad_frame_type(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
- pn_transport_logf(transport, "Error dispatching frame: Unknown frame type: %d", frame_type);
- return PN_ERR;
-}
-
-// We could use a table based approach here if we needed to dynamically
-// add new performatives
-static inline int pni_dispatch_action(pn_transport_t* transport, uint64_t lcode, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
- pn_action_t *action;
- switch (frame_type) {
- case AMQP_FRAME_TYPE:
- /* Regular AMQP fames */
- switch (lcode) {
- case OPEN: action = pn_do_open; break;
- case BEGIN: action = pn_do_begin; break;
- case ATTACH: action = pn_do_attach; break;
- case FLOW: action = pn_do_flow; break;
- case TRANSFER: action = pn_do_transfer; break;
- case DISPOSITION: action = pn_do_disposition; break;
- case DETACH: action = pn_do_detach; break;
- case END: action = pn_do_end; break;
- case CLOSE: action = pn_do_close; break;
- default: action = pni_bad_frame; break;
- };
- break;
- case SASL_FRAME_TYPE:
- /* SASL frames */
- switch (lcode) {
- case SASL_MECHANISMS: action = pn_do_mechanisms; break;
- case SASL_INIT: action = pn_do_init; break;
- case SASL_CHALLENGE: action = pn_do_challenge; break;
- case SASL_RESPONSE: action = pn_do_response; break;
- case SASL_OUTCOME: action = pn_do_outcome; break;
- default: action = pni_bad_frame; break;
- };
- break;
- default: action = pni_bad_frame_type; break;
- };
- return action(transport, frame_type, channel, args, payload);
-}
-
-static int pni_dispatch_frame(pn_transport_t * transport, pn_data_t *args, pn_frame_t frame)
-{
- if (frame.size == 0) { // ignore null frames
- if (transport->trace & PN_TRACE_FRM)
- pn_transport_logf(transport, "%u <- (EMPTY FRAME)", frame.channel);
- return 0;
- }
-
- ssize_t dsize = pn_data_decode(args, frame.payload, frame.size);
- if (dsize < 0) {
- pn_string_format(transport->scratch,
- "Error decoding frame: %s %s\n", pn_code(dsize),
- pn_error_text(pn_data_error(args)));
- pn_quote(transport->scratch, frame.payload, frame.size);
- pn_transport_log(transport, pn_string_get(transport->scratch));
- return dsize;
- }
-
- uint8_t frame_type = frame.type;
- uint16_t channel = frame.channel;
- // XXX: assuming numeric -
- // if we get a symbol we should map it to the numeric value and dispatch on that
- uint64_t lcode;
- bool scanned;
- int e = pn_data_scan(args, "D?L.", &scanned, &lcode);
- if (e) {
- pn_transport_log(transport, "Scan error");
- return e;
- }
- if (!scanned) {
- pn_transport_log(transport, "Error dispatching frame");
- return PN_ERR;
- }
- size_t payload_size = frame.size - dsize;
- const char *payload_mem = payload_size ? frame.payload + dsize : NULL;
- pn_bytes_t payload = {payload_size, payload_mem};
-
- pn_do_trace(transport, channel, IN, args, payload_mem, payload_size);
-
- int err = pni_dispatch_action(transport, lcode, frame_type, channel, args, &payload);
-
- pn_data_clear(args);
-
- return err;
-}
-
-ssize_t pn_dispatcher_input(pn_transport_t *transport, const char *bytes, size_t available, bool batch, bool *halt)
-{
- size_t read = 0;
-
- while (available && !*halt) {
- pn_frame_t frame;
-
- ssize_t n = pn_read_frame(&frame, bytes + read, available, transport->local_max_frame);
- if (n > 0) {
- read += n;
- available -= n;
- transport->input_frames_ct += 1;
- int e = pni_dispatch_frame(transport, transport->args, frame);
- if (e) return e;
- } else if (n < 0) {
- pn_do_error(transport, "amqp:connection:framing-error", "malformed frame");
- return n;
- } else {
- break;
- }
-
- if (!batch) break;
- }
-
- return read;
-}
-
-ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size)
-{
- int n = transport->available < size ? transport->available : size;
- memmove(bytes, transport->output, n);
- memmove(transport->output, transport->output + n, transport->available - n);
- transport->available -= n;
- // XXX: need to check for errors
- return n;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/dispatcher/dispatcher.h
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.h b/proton-c/src/dispatcher/dispatcher.h
deleted file mode 100644
index 29881b5..0000000
--- a/proton-c/src/dispatcher/dispatcher.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _PROTON_DISPATCHER_H
-#define _PROTON_DISPATCHER_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-
-#include "proton/codec.h"
-#include "proton/types.h"
-
-typedef int (pn_action_t)(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-
-ssize_t pn_dispatcher_input(pn_transport_t* transport, const char* bytes, size_t available, bool batch, bool* halt);
-ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size);
-
-#endif /* dispatcher.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/encodings.h.py
----------------------------------------------------------------------
diff --git a/proton-c/src/encodings.h.py b/proton-c/src/encodings.h.py
new file mode 100644
index 0000000..9f08c6c
--- /dev/null
+++ b/proton-c/src/encodings.h.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from __future__ import print_function
+import mllib, optparse, os, sys
+
+xml = os.path.join(os.path.dirname(__file__), "types.xml")
+doc = mllib.xml_parse(xml)
+
+print("/* generated from %s */" % xml)
+print("#ifndef _PROTON_ENCODINGS_H")
+print("#define _PROTON_ENCODINGS_H 1")
+print()
+print("#define PNE_DESCRIPTOR (0x00)")
+
+for enc in doc.query["amqp/section/type/encoding"]:
+ name = enc["@name"] or enc.parent["@name"]
+ # XXX: a bit hacky
+ if name == "ieee-754":
+ name = enc.parent["@name"]
+ cname = "PNE_" + name.replace("-", "_").upper()
+ print("#define %s%s(%s)" % (cname, " "*(20-len(cname)), enc["@code"]))
+
+print()
+print("#endif /* encodings.h */")
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/engine/connection_engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/connection_engine.c b/proton-c/src/engine/connection_engine.c
deleted file mode 100644
index 5d184a1..0000000
--- a/proton-c/src/engine/connection_engine.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-#include "engine-internal.h"
-
-#include <proton/connection.h>
-#include <proton/connection_engine.h>
-#include <proton/transport.h>
-#include <string.h>
-
-int pn_connection_engine_init(pn_connection_engine_t* e) {
- memset(e, 0, sizeof(*e));
- e->connection = pn_connection();
- e->transport = pn_transport();
- e->collector = pn_collector();
- if (!e->connection || !e->transport || !e->collector) {
- pn_connection_engine_final(e);
- return PN_OUT_OF_MEMORY;
- }
- pn_connection_collect(e->connection, e->collector);
- return PN_OK;
-}
-
-void pn_connection_engine_final(pn_connection_engine_t* e) {
- if (e->transport && e->connection) {
- pn_transport_unbind(e->transport);
- pn_decref(e->transport);
- }
- if (e->collector)
- pn_collector_free(e->collector); /* Break cycle with connection */
- if (e->connection)
- pn_decref(e->connection);
- memset(e, 0, sizeof(*e));
-}
-
-pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t* e) {
- ssize_t cap = pn_transport_capacity(e->transport);
- if (cap > 0)
- return pn_rwbytes(cap, pn_transport_tail(e->transport));
- else
- return pn_rwbytes(0, 0);
-}
-
-void pn_connection_engine_read_done(pn_connection_engine_t* e, size_t n) {
- if (n > 0)
- pn_transport_process(e->transport, n);
-}
-
-void pn_connection_engine_read_close(pn_connection_engine_t* e) {
- pn_transport_close_tail(e->transport);
-}
-
-pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t* e) {
- ssize_t pending = pn_transport_pending(e->transport);
- if (pending > 0)
- return pn_bytes(pending, pn_transport_head(e->transport));
- else
- return pn_bytes(0, 0);
-}
-
-void pn_connection_engine_write_done(pn_connection_engine_t* e, size_t n) {
- if (n > 0)
- pn_transport_pop(e->transport, n);
-}
-
-void pn_connection_engine_write_close(pn_connection_engine_t* e){
- pn_transport_close_head(e->transport);
-}
-
-void pn_connection_engine_disconnected(pn_connection_engine_t* e) {
- pn_connection_engine_read_close(e);
- pn_connection_engine_write_close(e);
-}
-
-static void log_event(pn_connection_engine_t *engine, pn_event_t* event) {
- if (event && engine->transport->trace & PN_TRACE_EVT) {
- pn_string_t *str = pn_string(NULL);
- pn_inspect(event, str);
- pn_transport_log(engine->transport, pn_string_get(str));
- pn_free(str);
- }
-}
-
-pn_event_t* pn_connection_engine_dispatch(pn_connection_engine_t* e) {
- if (e->event) { /* Already returned */
- if (pn_event_type(e->event) == PN_CONNECTION_INIT)
- pn_transport_bind(e->transport, e->connection);
- pn_collector_pop(e->collector);
- }
- e->event = pn_collector_peek(e->collector);
- log_event(e, e->event);
- return e->event;
-}
-
-bool pn_connection_engine_finished(pn_connection_engine_t* e) {
- return pn_transport_closed(e->transport) && (pn_collector_peek(e->collector) == NULL);
-}
-
-pn_connection_t* pn_connection_engine_connection(pn_connection_engine_t* e) {
- return e->connection;
-}
-
-pn_transport_t* pn_connection_engine_transport(pn_connection_engine_t* e) {
- return e->transport;
-}
-
-pn_condition_t* pn_connection_engine_condition(pn_connection_engine_t* e) {
- return pn_transport_condition(e->transport);
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
deleted file mode 100644
index 761a840..0000000
--- a/proton-c/src/engine/engine-internal.h
+++ /dev/null
@@ -1,374 +0,0 @@
-#ifndef _PROTON_ENGINE_INTERNAL_H
-#define _PROTON_ENGINE_INTERNAL_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/object.h>
-#include <proton/engine.h>
-#include <proton/types.h>
-#include "buffer.h"
-#include "dispatcher/dispatcher.h"
-#include "util.h"
-
-typedef enum pn_endpoint_type_t {CONNECTION, SESSION, SENDER, RECEIVER} pn_endpoint_type_t;
-
-typedef struct pn_endpoint_t pn_endpoint_t;
-
-struct pn_condition_t {
- pn_string_t *name;
- pn_string_t *description;
- pn_data_t *info;
-};
-
-struct pn_endpoint_t {
- pn_endpoint_type_t type;
- pn_state_t state;
- pn_error_t *error;
- pn_condition_t condition;
- pn_condition_t remote_condition;
- pn_endpoint_t *endpoint_next;
- pn_endpoint_t *endpoint_prev;
- pn_endpoint_t *transport_next;
- pn_endpoint_t *transport_prev;
- int refcount; // when this hits zero we generate a final event
- bool modified;
- bool freed;
- bool referenced;
-};
-
-typedef struct {
- pn_sequence_t id;
- bool sent;
- bool init;
-} pn_delivery_state_t;
-
-typedef struct {
- pn_sequence_t next;
- pn_hash_t *deliveries;
-} pn_delivery_map_t;
-
-typedef struct {
- // XXX: stop using negative numbers
- uint32_t local_handle;
- uint32_t remote_handle;
- pn_sequence_t delivery_count;
- pn_sequence_t link_credit;
-} pn_link_state_t;
-
-typedef struct {
- // XXX: stop using negative numbers
- uint16_t local_channel;
- uint16_t remote_channel;
- bool incoming_init;
- pn_delivery_map_t incoming;
- pn_delivery_map_t outgoing;
- pn_sequence_t incoming_transfer_count;
- pn_sequence_t incoming_window;
- pn_sequence_t remote_incoming_window;
- pn_sequence_t outgoing_transfer_count;
- pn_sequence_t outgoing_window;
- pn_hash_t *local_handles;
- pn_hash_t *remote_handles;
-
- uint64_t disp_code;
- bool disp_settled;
- bool disp_type;
- pn_sequence_t disp_first;
- pn_sequence_t disp_last;
- bool disp;
-} pn_session_state_t;
-
-typedef struct pn_io_layer_t {
- ssize_t (*process_input)(struct pn_transport_t *transport, unsigned int layer, const char *, size_t);
- ssize_t (*process_output)(struct pn_transport_t *transport, unsigned int layer, char *, size_t);
- void (*handle_error)(struct pn_transport_t* transport, unsigned int layer);
- pn_timestamp_t (*process_tick)(struct pn_transport_t *transport, unsigned int layer, pn_timestamp_t);
- size_t (*buffered_output)(struct pn_transport_t *transport); // how much output is held
-} pn_io_layer_t;
-
-extern const pn_io_layer_t pni_passthru_layer;
-extern const pn_io_layer_t ssl_layer;
-extern const pn_io_layer_t sasl_header_layer;
-extern const pn_io_layer_t sasl_write_header_layer;
-
-// Bit flag defines for the protocol layers
-typedef uint8_t pn_io_layer_flags_t;
-#define LAYER_NONE 0
-#define LAYER_AMQP1 1
-#define LAYER_AMQPSASL 2
-#define LAYER_AMQPSSL 4
-#define LAYER_SSL 8
-
-typedef struct pni_sasl_t pni_sasl_t;
-typedef struct pni_ssl_t pni_ssl_t;
-
-struct pn_transport_t {
- pn_tracer_t tracer;
- pni_sasl_t *sasl;
- pni_ssl_t *ssl;
- pn_connection_t *connection; // reference counted
- char *remote_container;
- char *remote_hostname;
- pn_data_t *remote_offered_capabilities;
- pn_data_t *remote_desired_capabilities;
- pn_data_t *remote_properties;
- pn_data_t *disp_data;
- //#define PN_DEFAULT_MAX_FRAME_SIZE (16*1024)
-#define PN_DEFAULT_MAX_FRAME_SIZE (0) /* for now, allow unlimited size */
- uint32_t local_max_frame;
- uint32_t remote_max_frame;
- pn_condition_t remote_condition;
- pn_condition_t condition;
- pn_error_t *error;
-
-#define PN_IO_LAYER_CT 3
- const pn_io_layer_t *io_layers[PN_IO_LAYER_CT];
-
- /* dead remote detection */
- pn_millis_t local_idle_timeout;
- pn_millis_t remote_idle_timeout;
- pn_timestamp_t dead_remote_deadline;
- uint64_t last_bytes_input;
-
- /* keepalive */
- pn_timestamp_t keepalive_deadline;
- uint64_t last_bytes_output;
-
- pn_hash_t *local_channels;
- pn_hash_t *remote_channels;
-
-
- /* scratch area */
- pn_string_t *scratch;
- pn_data_t *args;
- pn_data_t *output_args;
- pn_buffer_t *frame; // frame under construction
- // Temporary
- size_t capacity;
- size_t available; /* number of raw bytes pending output */
- char *output;
-
- /* statistics */
- uint64_t bytes_input;
- uint64_t bytes_output;
- uint64_t output_frames_ct;
- uint64_t input_frames_ct;
-
- /* output buffered for send */
- size_t output_size;
- size_t output_pending;
- char *output_buf;
-
- /* input from peer */
- size_t input_size;
- size_t input_pending;
- char *input_buf;
-
- pn_record_t *context;
-
- pn_trace_t trace;
-
- /*
- * The maximum channel number can be constrained in several ways:
- * 1. an unchangeable limit imposed by this library code
- * 2. a limit imposed by the remote peer when the connection is opened,
- * which this app must honor
- * 3. a limit imposed by this app, which may be raised and lowered
- * until the OPEN frame is sent.
- * These constraints are all summed up in channel_max, below.
- */
- #define PN_IMPL_CHANNEL_MAX 32767
- uint16_t local_channel_max;
- uint16_t remote_channel_max;
- uint16_t channel_max;
-
- pn_io_layer_flags_t allowed_layers;
- pn_io_layer_flags_t present_layers;
-
- bool freed;
- bool open_sent;
- bool open_rcvd;
- bool close_sent;
- bool close_rcvd;
- bool tail_closed; // input stream closed by driver
- bool head_closed;
- bool done_processing; // if true, don't call pn_process again
- bool posted_idle_timeout;
- bool server;
- bool halt;
- bool auth_required;
- bool authenticated;
- bool encryption_required;
-
- bool referenced;
-};
-
-struct pn_connection_t {
- pn_endpoint_t endpoint;
- pn_endpoint_t *endpoint_head;
- pn_endpoint_t *endpoint_tail;
- pn_endpoint_t *transport_head; // reference counted
- pn_endpoint_t *transport_tail;
- pn_list_t *sessions;
- pn_list_t *freed;
- pn_transport_t *transport;
- pn_delivery_t *work_head;
- pn_delivery_t *work_tail;
- pn_delivery_t *tpwork_head; // reference counted
- pn_delivery_t *tpwork_tail;
- pn_string_t *container;
- pn_string_t *hostname;
- pn_string_t *auth_user;
- pn_string_t *auth_password;
- pn_data_t *offered_capabilities;
- pn_data_t *desired_capabilities;
- pn_data_t *properties;
- pn_collector_t *collector;
- pn_record_t *context;
- pn_list_t *delivery_pool;
-};
-
-struct pn_session_t {
- pn_endpoint_t endpoint;
- pn_connection_t *connection; // reference counted
- pn_list_t *links;
- pn_list_t *freed;
- pn_record_t *context;
- size_t incoming_capacity;
- pn_sequence_t incoming_bytes;
- pn_sequence_t outgoing_bytes;
- pn_sequence_t incoming_deliveries;
- pn_sequence_t outgoing_deliveries;
- pn_sequence_t outgoing_window;
- pn_session_state_t state;
-};
-
-struct pn_terminus_t {
- pn_string_t *address;
- pn_data_t *properties;
- pn_data_t *capabilities;
- pn_data_t *outcomes;
- pn_data_t *filter;
- pn_durability_t durability;
- pn_expiry_policy_t expiry_policy;
- pn_seconds_t timeout;
- pn_terminus_type_t type;
- pn_distribution_mode_t distribution_mode;
- bool dynamic;
-};
-
-struct pn_link_t {
- pn_endpoint_t endpoint;
- pn_terminus_t source;
- pn_terminus_t target;
- pn_terminus_t remote_source;
- pn_terminus_t remote_target;
- pn_link_state_t state;
- pn_string_t *name;
- pn_session_t *session; // reference counted
- pn_delivery_t *unsettled_head;
- pn_delivery_t *unsettled_tail;
- pn_delivery_t *current;
- pn_record_t *context;
- size_t unsettled_count;
- pn_sequence_t available;
- pn_sequence_t credit;
- pn_sequence_t queued;
- int drained; // number of drained credits
- uint8_t snd_settle_mode;
- uint8_t rcv_settle_mode;
- uint8_t remote_snd_settle_mode;
- uint8_t remote_rcv_settle_mode;
- bool drain_flag_mode; // receiver only
- bool drain;
- bool detached;
-};
-
-struct pn_disposition_t {
- pn_condition_t condition;
- uint64_t type;
- pn_data_t *data;
- pn_data_t *annotations;
- uint64_t section_offset;
- uint32_t section_number;
- bool failed;
- bool undeliverable;
- bool settled;
-};
-
-struct pn_delivery_t {
- pn_disposition_t local;
- pn_disposition_t remote;
- pn_link_t *link; // reference counted
- pn_buffer_t *tag;
- pn_delivery_t *unsettled_next;
- pn_delivery_t *unsettled_prev;
- pn_delivery_t *work_next;
- pn_delivery_t *work_prev;
- pn_delivery_t *tpwork_next;
- pn_delivery_t *tpwork_prev;
- pn_delivery_state_t state;
- pn_buffer_t *bytes;
- pn_record_t *context;
- bool updated;
- bool settled; // tracks whether we're in the unsettled list or not
- bool work;
- bool tpwork;
- bool done;
- bool referenced;
-};
-
-#define PN_SET_LOCAL(OLD, NEW) \
- (OLD) = ((OLD) & PN_REMOTE_MASK) | (NEW)
-
-#define PN_SET_REMOTE(OLD, NEW) \
- (OLD) = ((OLD) & PN_LOCAL_MASK) | (NEW)
-
-void pn_link_dump(pn_link_t *link);
-
-void pn_dump(pn_connection_t *conn);
-void pn_transport_sasl_init(pn_transport_t *transport);
-
-void pn_condition_init(pn_condition_t *condition);
-void pn_condition_tini(pn_condition_t *condition);
-void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit);
-void pn_real_settle(pn_delivery_t *delivery); // will free delivery if link is freed
-void pn_clear_tpwork(pn_delivery_t *delivery);
-void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery);
-void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint);
-void pn_connection_bound(pn_connection_t *conn);
-void pn_connection_unbound(pn_connection_t *conn);
-int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...);
-void pn_set_error_layer(pn_transport_t *transport);
-void pn_session_unbound(pn_session_t* ssn);
-void pn_link_unbound(pn_link_t* link);
-void pn_ep_incref(pn_endpoint_t *endpoint);
-void pn_ep_decref(pn_endpoint_t *endpoint);
-
-int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...);
-
-typedef enum {IN, OUT} pn_dir_t;
-
-void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
- pn_data_t *args, const char *payload, size_t size);
-
-#endif /* engine-internal.h */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[03/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.h b/proton-c/src/transport/transport.h
deleted file mode 100644
index 66ebc51..0000000
--- a/proton-c/src/transport/transport.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _PROTON_TRANSPORT_INTERNAL_H
-#define _PROTON_TRANSPORT_INTERNAL_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next);
-void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery);
-void pn_delivery_map_free(pn_delivery_map_t *db);
-void pn_unmap_handle(pn_session_t *ssn, pn_link_t *link);
-void pn_unmap_channel(pn_transport_t *transport, pn_session_t *ssn);
-
-#endif /* transport.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/types.c
----------------------------------------------------------------------
diff --git a/proton-c/src/types.c b/proton-c/src/types.c
deleted file mode 100644
index 4f8048d..0000000
--- a/proton-c/src/types.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "platform.h"
-#include <proton/types.h>
-#include <stdlib.h>
-#include <string.h>
-
-pn_bytes_t pn_bytes(size_t size, const char *start)
-{
- pn_bytes_t bytes = {size, start};
- return bytes;
-}
-
-pn_rwbytes_t pn_rwbytes(size_t size, char *start)
-{
- pn_rwbytes_t bytes = {size, start};
- return bytes;
-}
-
-pn_timestamp_t pn_timestamp_now() {
- return pn_i_now();
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/types.xml
----------------------------------------------------------------------
diff --git a/proton-c/src/types.xml b/proton-c/src/types.xml
new file mode 100644
index 0000000..4aa9c0f
--- /dev/null
+++ b/proton-c/src/types.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+
+<!--
+Copyright Bank of America, N.A., Barclays Bank PLC, Cisco Systems, Credit
+Suisse, Deutsche Boerse, Envoy Technologies Inc., Goldman Sachs, HCL
+Technologies Ltd, IIT Software GmbH, iMatix Corporation, INETCO Systems Limited,
+Informatica Corporation, JPMorgan Chase & Co., Kaazing Corporation, N.A,
+Microsoft Corporation, my-Channels, Novell, Progress Software, Red Hat Inc.,
+Software AG, Solace Systems Inc., StormMQ Ltd., Tervela Inc., TWIST Process
+Innovations Ltd, VMware, Inc., and WS02 Inc. 2006-2011. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<amqp name="types" xmlns="http://www.amqp.org/schema/amqp.xsd">
+ <section name="encodings">
+ <type name="null" class="primitive">
+ <encoding code="0x40" category="fixed" width="0"/>
+ </type>
+ <type name="boolean" class="primitive">
+ <encoding code="0x56" category="fixed" width="1"/>
+ <encoding name="true" code="0x41" category="fixed" width="0"/>
+ <encoding name="false" code="0x42" category="fixed" width="0"/>
+ </type>
+ <type name="ubyte" class="primitive">
+ <encoding code="0x50" category="fixed" width="1"/>
+ </type>
+ <type name="ushort" class="primitive">
+ <encoding code="0x60" category="fixed" width="2"/>
+ </type>
+ <type name="uint" class="primitive">
+ <encoding code="0x70" category="fixed" width="4"/>
+ <encoding name="smalluint" code="0x52" category="fixed" width="1"/>
+ <encoding name="uint0" code="0x43" category="fixed" width="0"/>
+ </type>
+ <type name="ulong" class="primitive">
+ <encoding code="0x80" category="fixed" width="8"/>
+ <encoding name="smallulong" code="0x53" category="fixed" width="1"/>
+ <encoding name="ulong0" code="0x44" category="fixed" width="0"/>
+ </type>
+ <type name="byte" class="primitive">
+ <encoding code="0x51" category="fixed" width="1"/>
+ </type>
+ <type name="short" class="primitive">
+ <encoding code="0x61" category="fixed" width="2"/>
+ </type>
+ <type name="int" class="primitive">
+ <encoding code="0x71" category="fixed" width="4"/>
+ <encoding name="smallint" code="0x54" category="fixed" width="1"/>
+ </type>
+ <type name="long" class="primitive">
+ <encoding code="0x81" category="fixed" width="8"/>
+ <encoding name="smalllong" code="0x55" category="fixed" width="1"/>
+ </type>
+ <type name="float" class="primitive">
+ <encoding name="ieee-754" code="0x72" category="fixed" width="4"/>
+ </type>
+ <type name="double" class="primitive">
+ <encoding name="ieee-754" code="0x82" category="fixed" width="8"/>
+ </type>
+ <type name="decimal32" class="primitive">
+ <encoding name="ieee-754" code="0x74" category="fixed" width="4"/>
+ </type>
+ <type name="decimal64" class="primitive">
+ <encoding name="ieee-754" code="0x84" category="fixed" width="8"/>
+ </type>
+ <type name="decimal128" class="primitive">
+ <encoding name="ieee-754" code="0x94" category="fixed" width="16"/>
+ </type>
+ <type name="char" class="primitive">
+ <encoding name="utf32" code="0x73" category="fixed" width="4"/>
+ </type>
+ <type name="timestamp" class="primitive">
+ <encoding name="ms64" code="0x83" category="fixed" width="8"/>
+ </type>
+ <type name="uuid" class="primitive">
+ <encoding code="0x98" category="fixed" width="16"/>
+ </type>
+ <type name="binary" class="primitive">
+ <encoding name="vbin8" code="0xa0" category="variable" width="1"/>
+ <encoding name="vbin32" code="0xb0" category="variable" width="4"/>
+ </type>
+ <type name="string" class="primitive">
+ <encoding name="str8-utf8" code="0xa1" category="variable" width="1"/>
+ <encoding name="str32-utf8" code="0xb1" category="variable" width="4"/>
+ </type>
+ <type name="symbol" class="primitive">
+ <encoding name="sym8" code="0xa3" category="variable" width="1"/>
+ <encoding name="sym32" code="0xb3" category="variable" width="4"/>
+ </type>
+ <type name="list" class="primitive">
+ <encoding name="list0" code="0x45" category="fixed" width="0"/>
+ <encoding name="list8" code="0xc0" category="compound" width="1"/>
+ <encoding name="list32" code="0xd0" category="compound" width="4"/>
+ </type>
+ <type name="map" class="primitive">
+ <encoding name="map8" code="0xc1" category="compound" width="1"/>
+ <encoding name="map32" code="0xd1" category="compound" width="4"/>
+ </type>
+ <type name="array" class="primitive">
+ <encoding name="array8" code="0xe0" category="array" width="1"/>
+ <encoding name="array32" code="0xf0" category="array" width="4"/>
+ </type>
+ </section>
+</amqp>
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/url.c b/proton-c/src/url.c
deleted file mode 100644
index 566e91e..0000000
--- a/proton-c/src/url.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/url.h"
-#include "proton/object.h"
-#include "util.h"
-#include "platform.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-static char* copy(const char* str) {
- if (str == NULL) return NULL;
- char *str2 = (char*)malloc(strlen(str)+1);
- if (str2) strcpy(str2, str);
- return str2;
-}
-
-struct pn_url_t {
- char *scheme;
- char *username;
- char *password;
- char *host;
- char *port;
- char *path;
- pn_string_t *str;
-};
-
-/** Internal use only, returns the pn_string_t. Public function is pn_url_str() */
-static pn_string_t *pn_url_string(pn_url_t* url)
-{
- pn_url_str(url); /* Make sure str is up to date */
- return url->str;
-}
-
-static void pn_url_finalize(void *object)
-{
- pn_url_t *url = (pn_url_t *) object;
- pn_url_clear(url);
- pn_free(url->str);
-}
-
-static uintptr_t pn_url_hashcode(void *object)
-{
- pn_url_t *url = (pn_url_t *) object;
- return pn_hashcode(pn_url_string(url));
-}
-
-static intptr_t pn_url_compare(void *oa, void *ob)
-{
- pn_url_t *a = (pn_url_t *) oa;
- pn_url_t *b = (pn_url_t *) ob;
- return pn_compare(pn_url_string(a), pn_url_string(b));
-}
-
-
-static int pn_url_inspect(void *obj, pn_string_t *dst)
-{
- pn_url_t *url = (pn_url_t *) obj;
- int err = 0;
- err = pn_string_addf(dst, "Url("); if (err) return err;
- err = pn_inspect(pn_url_string(url), dst); if (err) return err;
- return pn_string_addf(dst, ")");
-}
-
-#define pn_url_initialize NULL
-
-
-pn_url_t *pn_url() {
- static const pn_class_t clazz = PN_CLASS(pn_url);
- pn_url_t *url = (pn_url_t*) pn_class_new(&clazz, sizeof(pn_url_t));
- if (!url) return NULL;
- memset(url, 0, sizeof(*url));
- url->str = pn_string(NULL);
- return url;
-}
-
-/** Parse a string URL as a pn_url_t.
- *@param[in] url A URL string.
- *@return The parsed pn_url_t or NULL if url is not a valid URL string.
- */
-pn_url_t *pn_url_parse(const char *str) {
- if (!str || !*str) /* Empty string or NULL is illegal. */
- return NULL;
-
- pn_url_t *url = pn_url();
- char *str2 = copy(str);
- pni_parse_url(str2, &url->scheme, &url->username, &url->password, &url->host, &url->port, &url->path);
- url->scheme = copy(url->scheme);
- url->username = copy(url->username);
- url->password = copy(url->password);
- url->host = (url->host && !*url->host) ? NULL : copy(url->host);
- url->port = copy(url->port);
- url->path = copy(url->path);
-
- free(str2);
- return url;
-}
-
-/** Free a URL */
-void pn_url_free(pn_url_t *url) { pn_free(url); }
-
-/** Clear the contents of the URL. */
-void pn_url_clear(pn_url_t *url) {
- pn_url_set_scheme(url, NULL);
- pn_url_set_username(url, NULL);
- pn_url_set_password(url, NULL);
- pn_url_set_host(url, NULL);
- pn_url_set_port(url, NULL);
- pn_url_set_path(url, NULL);
- pn_string_clear(url->str);
-}
-
-/** URL-encode src and append to dst. */
-static void pni_urlencode(pn_string_t *dst, const char* src) {
- static const char *bad = "@:/";
-
- if (!src) return;
- const char *i = src;
- const char *j = strpbrk(i, bad);
- while (j) {
- pn_string_addf(dst, "%.*s", (int)(j-i), i);
- pn_string_addf(dst, "%%%02X", (int)*j);
- i = j + 1;
- j = strpbrk(i, bad);
- }
- pn_string_addf(dst, "%s", i);
-}
-
-
-/** Return the string form of a URL. */
-const char *pn_url_str(pn_url_t *url) {
- if (pn_string_get(url->str) == NULL) {
- pn_string_set(url->str, "");
- if (url->scheme) pn_string_addf(url->str, "%s://", url->scheme);
- if (url->username) pni_urlencode(url->str, url->username);
- if (url->password) {
- pn_string_addf(url->str, ":");
- pni_urlencode(url->str, url->password);
- }
- if (url->username || url->password) pn_string_addf(url->str, "@");
- if (url->host) {
- if (strchr(url->host, ':')) pn_string_addf(url->str, "[%s]", url->host);
- else pn_string_addf(url->str, "%s", url->host);
- }
- if (url->port) pn_string_addf(url->str, ":%s", url->port);
- if (url->path) pn_string_addf(url->str, "/%s", url->path);
- }
- return pn_string_get(url->str);
-}
-
-const char *pn_url_get_scheme(pn_url_t *url) { return url->scheme; }
-const char *pn_url_get_username(pn_url_t *url) { return url->username; }
-const char *pn_url_get_password(pn_url_t *url) { return url->password; }
-const char *pn_url_get_host(pn_url_t *url) { return url->host; }
-const char *pn_url_get_port(pn_url_t *url) { return url->port; }
-const char *pn_url_get_path(pn_url_t *url) { return url->path; }
-
-#define SET(part) free(url->part); url->part = copy(part); pn_string_clear(url->str)
-void pn_url_set_scheme(pn_url_t *url, const char *scheme) { SET(scheme); }
-void pn_url_set_username(pn_url_t *url, const char *username) { SET(username); }
-void pn_url_set_password(pn_url_t *url, const char *password) { SET(password); }
-void pn_url_set_host(pn_url_t *url, const char *host) { SET(host); }
-void pn_url_set_port(pn_url_t *url, const char *port) { SET(port); }
-void pn_url_set_path(pn_url_t *url, const char *path) { SET(path); }
-
-
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/util.c b/proton-c/src/util.c
deleted file mode 100644
index 47fbc34..0000000
--- a/proton-c/src/util.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <proton/type_compat.h>
-#include <ctype.h>
-#include <string.h>
-#include <proton/error.h>
-#include <proton/types.h>
-#include "util.h"
-
-ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size)
-{
- int idx = 0;
- for (unsigned i = 0; i < size; i++)
- {
- uint8_t c = src[i];
- if (isprint(c)) {
- if (idx < (int) (capacity - 1)) {
- dst[idx++] = c;
- } else {
- if (idx > 0) {
- dst[idx - 1] = '\0';
- }
- return PN_OVERFLOW;
- }
- } else {
- if (idx < (int) (capacity - 4)) {
- idx += sprintf(dst + idx, "\\x%.2x", c);
- } else {
- if (idx > 0) {
- dst[idx - 1] = '\0';
- }
- return PN_OVERFLOW;
- }
- }
- }
-
- dst[idx] = '\0';
- return idx;
-}
-
-int pn_quote(pn_string_t *dst, const char *src, size_t size)
-{
- while (true) {
- size_t str_size = pn_string_size(dst);
- char *str = pn_string_buffer(dst) + str_size;
- size_t capacity = pn_string_capacity(dst) - str_size;
- ssize_t ssize = pn_quote_data(str, capacity, src, size);
- if (ssize == PN_OVERFLOW) {
- int err = pn_string_grow(dst, (str_size + capacity) ? 2*(str_size + capacity) : 16);
- if (err) return err;
- } else if (ssize >= 0) {
- return pn_string_resize(dst, str_size + ssize);
- } else {
- return ssize;
- }
- }
-}
-
-void pn_fprint_data(FILE *stream, const char *bytes, size_t size)
-{
- char buf[256];
- ssize_t n = pn_quote_data(buf, 256, bytes, size);
- if (n >= 0) {
- fputs(buf, stream);
- } else {
- if (n == PN_OVERFLOW) {
- fputs(buf, stream);
- fputs("... (truncated)", stream);
- }
- else
- fprintf(stderr, "pn_quote_data: %s\n", pn_code(n));
- }
-}
-
-void pn_print_data(const char *bytes, size_t size)
-{
- pn_fprint_data(stdout, bytes, size);
-}
-
-void pni_urldecode(const char *src, char *dst)
-{
- const char *in = src;
- char *out = dst;
- while (*in != '\0')
- {
- if ('%' == *in)
- {
- if ((in[1] != '\0') && (in[2] != '\0'))
- {
- char esc[3];
- esc[0] = in[1];
- esc[1] = in[2];
- esc[2] = '\0';
- unsigned long d = strtoul(esc, NULL, 16);
- *out = (char)d;
- in += 3;
- out++;
- }
- else
- {
- *out = *in;
- in++;
- out++;
- }
- }
- else
- {
- *out = *in;
- in++;
- out++;
- }
- }
- *out = '\0';
-}
-
-void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path)
-{
- if (!url) return;
-
- char *slash = strchr(url, '/');
-
- if (slash && slash>url) {
- char *scheme_end = strstr(slash-1, "://");
-
- if (scheme_end && scheme_end<slash) {
- *scheme_end = '\0';
- *scheme = url;
- url = scheme_end + 3;
- slash = strchr(url, '/');
- }
- }
-
- if (slash) {
- *slash = '\0';
- *path = slash + 1;
- }
-
- char *at = strchr(url, '@');
- if (at) {
- *at = '\0';
- char *up = url;
- *user = up;
- url = at + 1;
- char *colon = strchr(up, ':');
- if (colon) {
- *colon = '\0';
- *pass = colon + 1;
- }
- }
-
- *host = url;
- char *open = (*url == '[') ? url : 0;
- if (open) {
- char *close = strchr(open, ']');
- if (close) {
- *host = open + 1;
- *close = '\0';
- url = close + 1;
- }
- }
-
- char *colon = strchr(url, ':');
- if (colon) {
- *colon = '\0';
- *port = colon + 1;
- }
-
- if (*user) pni_urldecode(*user, *user);
- if (*pass) pni_urldecode(*pass, *pass);
-}
-
-void pni_vfatal(const char *fmt, va_list ap)
-{
- vfprintf(stderr, fmt, ap);
- abort();
-}
-
-void pni_fatal(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- pni_vfatal(fmt, ap);
- va_end(ap);
-}
-
-int pn_strcasecmp(const char *a, const char *b)
-{
- int diff;
- while (*b) {
- char aa = *a++, bb = *b++;
- diff = tolower(aa)-tolower(bb);
- if ( diff!=0 ) return diff;
- }
- return *a;
-}
-
-int pn_strncasecmp(const char* a, const char* b, size_t len)
-{
- int diff = 0;
- while (*b && len > 0) {
- char aa = *a++, bb = *b++;
- diff = tolower(aa)-tolower(bb);
- if ( diff!=0 ) return diff;
- --len;
- };
- return len==0 ? diff : *a;
-}
-
-bool pn_env_bool(const char *name)
-{
- char *v = getenv(name);
- return v && (!pn_strcasecmp(v, "true") || !pn_strcasecmp(v, "1") ||
- !pn_strcasecmp(v, "yes") || !pn_strcasecmp(v, "on"));
-}
-
-char *pn_strdup(const char *src)
-{
- if (src) {
- char *dest = (char *) malloc((strlen(src)+1)*sizeof(char));
- if (!dest) return NULL;
- return strcpy(dest, src);
- } else {
- return NULL;
- }
-}
-
-char *pn_strndup(const char *src, size_t n)
-{
- if (src) {
- unsigned size = 0;
- for (const char *c = src; size < n && *c; c++) {
- size++;
- }
-
- char *dest = (char *) malloc(size + 1);
- if (!dest) return NULL;
- strncpy(dest, src, n);
- dest[size] = '\0';
- return dest;
- } else {
- return NULL;
- }
-}
-
-// which timestamp will expire next, or zero if none set
-pn_timestamp_t pn_timestamp_min( pn_timestamp_t a, pn_timestamp_t b )
-{
- if (a && b) return pn_min(a, b);
- if (a) return a;
- return b;
-}
-
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/util.h
----------------------------------------------------------------------
diff --git a/proton-c/src/util.h b/proton-c/src/util.h
deleted file mode 100644
index ec59a07..0000000
--- a/proton-c/src/util.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef _PROTON_SRC_UTIL_H
-#define _PROTON_SRC_UTIL_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <errno.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <proton/types.h>
-#include <proton/object.h>
-
-void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path);
-void pni_fatal(const char *fmt, ...);
-void pni_vfatal(const char *fmt, va_list ap);
-ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size);
-int pn_quote(pn_string_t *dst, const char *src, size_t size);
-void pn_fprint_data(FILE *stream, const char *bytes, size_t size);
-void pn_print_data(const char *bytes, size_t size);
-bool pn_env_bool(const char *name);
-pn_timestamp_t pn_timestamp_min(pn_timestamp_t a, pn_timestamp_t b);
-
-char *pn_strdup(const char *src);
-char *pn_strndup(const char *src, size_t n);
-int pn_strcasecmp(const char* a, const char* b);
-int pn_strncasecmp(const char* a, const char* b, size_t len);
-
-#define DIE_IFR(EXPR, STRERR) \
- do { \
- int __code__ = (EXPR); \
- if (__code__) { \
- fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__, \
- #EXPR, STRERR(__code__), __code__); \
- exit(-1); \
- } \
- } while (0)
-
-#define DIE_IFE(EXPR) \
- do { \
- if ((EXPR) == -1) { \
- int __code__ = errno; \
- fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__, \
- #EXPR, strerror(__code__), __code__); \
- exit(-1); \
- } \
- } while (0)
-
-
-#define LL_HEAD(ROOT, LIST) ((ROOT)-> LIST ## _head)
-#define LL_TAIL(ROOT, LIST) ((ROOT)-> LIST ## _tail)
-#define LL_ADD(ROOT, LIST, NODE) \
- { \
- (NODE)-> LIST ## _next = NULL; \
- (NODE)-> LIST ## _prev = (ROOT)-> LIST ## _tail; \
- if (LL_TAIL(ROOT, LIST)) \
- LL_TAIL(ROOT, LIST)-> LIST ## _next = (NODE); \
- LL_TAIL(ROOT, LIST) = (NODE); \
- if (!LL_HEAD(ROOT, LIST)) LL_HEAD(ROOT, LIST) = (NODE); \
- }
-
-#define LL_POP(ROOT, LIST, TYPE) \
- { \
- if (LL_HEAD(ROOT, LIST)) { \
- TYPE *_old = LL_HEAD(ROOT, LIST); \
- LL_HEAD(ROOT, LIST) = LL_HEAD(ROOT, LIST)-> LIST ## _next; \
- _old-> LIST ## _next = NULL; \
- if (_old == LL_TAIL(ROOT, LIST)) { \
- LL_TAIL(ROOT, LIST) = NULL; \
- } else { \
- LL_HEAD(ROOT, LIST)-> LIST ## _prev = NULL; \
- } \
- } \
- }
-
-#define LL_REMOVE(ROOT, LIST, NODE) \
- { \
- if ((NODE)-> LIST ## _prev) \
- (NODE)-> LIST ## _prev-> LIST ## _next = (NODE)-> LIST ## _next; \
- if ((NODE)-> LIST ## _next) \
- (NODE)-> LIST ## _next-> LIST ## _prev = (NODE)-> LIST ## _prev; \
- if ((NODE) == LL_HEAD(ROOT, LIST)) \
- LL_HEAD(ROOT, LIST) = (NODE)-> LIST ## _next; \
- if ((NODE) == LL_TAIL(ROOT, LIST)) \
- LL_TAIL(ROOT, LIST) = (NODE)-> LIST ## _prev; \
- }
-
-#define pn_min(X,Y) ((X) > (Y) ? (Y) : (X))
-#define pn_max(X,Y) ((X) < (Y) ? (Y) : (X))
-
-#define PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE) \
- while ((CAPACITY) < (COUNT)) { \
- (CAPACITY) = (CAPACITY) ? 2 * (CAPACITY) : 16; \
- (ARRAY) = (TYPE *) realloc((ARRAY), (CAPACITY) * sizeof (TYPE)); \
- } \
-
-#define PN_ENSUREZ(ARRAY, CAPACITY, COUNT, TYPE) \
- { \
- size_t _old_capacity = (CAPACITY); \
- PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE); \
- memset((ARRAY) + _old_capacity, 0, \
- sizeof(TYPE)*((CAPACITY) - _old_capacity)); \
- }
-
-#endif /* util.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/io.c b/proton-c/src/windows/io.c
deleted file mode 100644
index 4a87fd2..0000000
--- a/proton-c/src/windows/io.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#define FD_SETSIZE 2048
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <mswsock.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/io.h>
-#include <proton/object.h>
-#include <proton/selector.h>
-#include "iocp.h"
-#include "util.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <assert.h>
-
-int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code)
-{
- // Error code can be from GetLastError or WSAGetLastError,
- char err[1024] = {0};
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL);
- return pn_error_format(error, PN_ERR, "%s: %s", msg, err);
-}
-
-static void io_log(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fflush(stderr);
-}
-
-struct pn_io_t {
- char host[NI_MAXHOST];
- char serv[NI_MAXSERV];
- pn_error_t *error;
- bool trace;
- bool wouldblock;
- iocp_t *iocp;
-};
-
-void pn_io_initialize(void *obj)
-{
- pn_io_t *io = (pn_io_t *) obj;
- io->error = pn_error();
- io->wouldblock = false;
- io->trace = pn_env_bool("PN_TRACE_DRV");
-
- /* Request WinSock 2.2 */
- WORD wsa_ver = MAKEWORD(2, 2);
- WSADATA unused;
- int err = WSAStartup(wsa_ver, &unused);
- if (err) {
- pni_win32_error(io->error, "WSAStartup", WSAGetLastError());
- fprintf(stderr, "Can't load WinSock: %s\n", pn_error_text(io->error));
- }
- io->iocp = pni_iocp();
-}
-
-void pn_io_finalize(void *obj)
-{
- pn_io_t *io = (pn_io_t *) obj;
- pn_error_free(io->error);
- pn_free(io->iocp);
- WSACleanup();
-}
-
-#define pn_io_hashcode NULL
-#define pn_io_compare NULL
-#define pn_io_inspect
-
-pn_io_t *pn_io(void)
-{
- static const pn_class_t clazz = PN_CLASS(pn_io);
- pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
- return io;
-}
-
-void pn_io_free(pn_io_t *io)
-{
- pn_free(io);
-}
-
-pn_error_t *pn_io_error(pn_io_t *io)
-{
- assert(io);
- return io->error;
-}
-
-static void ensure_unique(pn_io_t *io, pn_socket_t new_socket)
-{
- // A brand new socket can have the same HANDLE value as a previous
- // one after a socketclose. If the application closes one itself
- // (i.e. not using pn_close), we don't find out about it until here.
- iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, new_socket);
- if (iocpd) {
- if (io->trace)
- io_log("Stale external socket reference discarded\n");
- // Re-use means former socket instance was closed
- assert(iocpd->ops_in_progress == 0);
- assert(iocpd->external);
- // Clean up the straggler as best we can
- pn_socket_t sock = iocpd->socket;
- iocpd->socket = INVALID_SOCKET;
- pni_iocpdesc_map_del(io->iocp, sock); // may free the iocpdesc_t depending on refcount
- }
-}
-
-
-/*
- * This heavyweight surrogate pipe could be replaced with a normal Windows pipe
- * now that select() is no longer used. If interrupt semantics are all that is
- * needed, a simple user space counter and reserved completion status would
- * probably suffice.
- */
-static int pni_socket_pair(pn_io_t *io, SOCKET sv[2]);
-
-int pn_pipe(pn_io_t *io, pn_socket_t *dest)
-{
- int n = pni_socket_pair(io, dest);
- if (n) {
- pni_win32_error(io->error, "pipe", WSAGetLastError());
- }
- return n;
-}
-
-static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
- //
- // Disable the Nagle algorithm on TCP connections.
- //
- int flag = 1;
- if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) != 0) {
- perror("setsockopt");
- }
-
- u_long nonblock = 1;
- if (ioctlsocket(sock, FIONBIO, &nonblock)) {
- perror("ioctlsocket");
- }
-}
-
-static inline pn_socket_t pni_create_socket(int domain, int protocol);
-
-static const char *amqp_service(const char *port) {
- // Help older Windows to know about amqp[s] ports
- if (port) {
- if (!strcmp("amqp", port)) return "5672";
- if (!strcmp("amqps", port)) return "5671";
- }
- return port;
-}
-
-pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
-{
- struct addrinfo *addr;
- int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
- if (code) {
- pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
- return INVALID_SOCKET;
- }
-
- pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
- if (sock == INVALID_SOCKET) {
- pni_win32_error(io->error, "pni_create_socket", WSAGetLastError());
- return INVALID_SOCKET;
- }
- ensure_unique(io, sock);
-
- bool optval = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *) &optval,
- sizeof(optval)) == -1) {
- pni_win32_error(io->error, "setsockopt", WSAGetLastError());
- closesocket(sock);
- return INVALID_SOCKET;
- }
-
- if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
- pni_win32_error(io->error, "bind", WSAGetLastError());
- freeaddrinfo(addr);
- closesocket(sock);
- return INVALID_SOCKET;
- }
- freeaddrinfo(addr);
-
- if (listen(sock, 50) == -1) {
- pni_win32_error(io->error, "listen", WSAGetLastError());
- closesocket(sock);
- return INVALID_SOCKET;
- }
-
- if (io->iocp->selector) {
- iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
- if (!iocpd) {
- pn_i_error_from_errno(io->error, "register");
- closesocket(sock);
- return INVALID_SOCKET;
- }
- pni_iocpdesc_start(iocpd);
- }
-
- return sock;
-}
-
-pn_socket_t pn_connect(pn_io_t *io, const char *hostarg, const char *port)
-{
- // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets
- const char *host = strcmp("0.0.0.0", hostarg) ? hostarg : "127.0.0.1";
-
- struct addrinfo *addr;
- int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
- if (code) {
- pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
- return INVALID_SOCKET;
- }
-
- pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
- if (sock == INVALID_SOCKET) {
- pni_win32_error(io->error, "proton pni_create_socket", WSAGetLastError());
- freeaddrinfo(addr);
- return INVALID_SOCKET;
- }
-
- ensure_unique(io, sock);
- pn_configure_sock(io, sock);
-
- if (io->iocp->selector) {
- return pni_iocp_begin_connect(io->iocp, sock, addr, io->error);
- } else {
- if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
- pni_win32_error(io->error, "connect", WSAGetLastError());
- freeaddrinfo(addr);
- closesocket(sock);
- return INVALID_SOCKET;
- }
- }
-
- freeaddrinfo(addr);
- return sock;
- }
-}
-
-pn_socket_t pn_accept(pn_io_t *io, pn_socket_t listen_sock, char *name, size_t size)
-{
- struct sockaddr_storage addr;
- socklen_t addrlen = sizeof(addr);
- iocpdesc_t *listend = pni_iocpdesc_map_get(io->iocp, listen_sock);
- pn_socket_t accept_sock;
-
- *name = '\0';
- if (listend)
- accept_sock = pni_iocp_end_accept(listend, (struct sockaddr *) &addr, &addrlen, &io->wouldblock, io->error);
- else {
- // User supplied socket
- accept_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen);
- if (accept_sock == INVALID_SOCKET)
- pni_win32_error(io->error, "sync accept", WSAGetLastError());
- }
-
- if (accept_sock == INVALID_SOCKET)
- return accept_sock;
-
- int code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
- io->serv, NI_MAXSERV, 0);
- if (code)
- code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
- io->serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
- if (code) {
- pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
- pn_close(io, accept_sock);
- return INVALID_SOCKET;
- } else {
- pn_configure_sock(io, accept_sock);
- snprintf(name, size, "%s:%s", io->host, io->serv);
- if (listend) {
- pni_iocpdesc_start(pni_iocpdesc_map_get(io->iocp, accept_sock));
- }
- return accept_sock;
- }
-}
-
-static inline pn_socket_t pni_create_socket(int domain, int protocol) {
- return socket(domain, SOCK_STREAM, protocol);
-}
-
-ssize_t pn_send(pn_io_t *io, pn_socket_t sockfd, const void *buf, size_t len) {
- ssize_t count;
- iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, sockfd);
- if (iocpd) {
- count = pni_iocp_begin_write(iocpd, buf, len, &io->wouldblock, io->error);
- } else {
- count = send(sockfd, (const char *) buf, len, 0);
- io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
- }
- return count;
-}
-
-ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
- ssize_t count;
- iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
- if (iocpd) {
- count = pni_iocp_recv(iocpd, buf, size, &io->wouldblock, io->error);
- } else {
- count = recv(socket, (char *) buf, size, 0);
- io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
- }
- return count;
-}
-
-ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
-{
- // non-socket io is mapped to socket io for now. See pn_pipe()
- return pn_send(io, socket, buf, size);
-}
-
-ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
- return pn_recv(io, socket, buf, size);
-}
-
-void pn_close(pn_io_t *io, pn_socket_t socket)
-{
- iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
- if (iocpd)
- pni_iocp_begin_close(iocpd);
- else {
- closesocket(socket);
- }
-}
-
-bool pn_wouldblock(pn_io_t *io)
-{
- return io->wouldblock;
-}
-
-pn_selector_t *pn_io_selector(pn_io_t *io)
-{
- if (io->iocp->selector == NULL)
- io->iocp->selector = pni_selector_create(io->iocp);
- return io->iocp->selector;
-}
-
-static void configure_pipe_socket(pn_io_t *io, pn_socket_t sock)
-{
- u_long v = 1;
- ioctlsocket (sock, FIONBIO, &v);
- ensure_unique(io, sock);
- iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
- pni_iocpdesc_start(iocpd);
-}
-
-
-static int pni_socket_pair (pn_io_t *io, SOCKET sv[2]) {
- // no socketpair on windows. provide pipe() semantics using sockets
- struct protoent * pe_tcp = getprotobyname("tcp");
- if (pe_tcp == NULL) {
- perror("getprotobyname");
- return -1;
- }
-
- SOCKET sock = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto);
- if (sock == INVALID_SOCKET) {
- perror("socket");
- return -1;
- }
-
- BOOL b = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &b, sizeof(b)) == -1) {
- perror("setsockopt");
- closesocket(sock);
- return -1;
- }
- else {
- struct sockaddr_in addr = {0};
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- perror("bind");
- closesocket(sock);
- return -1;
- }
- }
-
- if (listen(sock, 50) == -1) {
- perror("listen");
- closesocket(sock);
- return -1;
- }
-
- if ((sv[1] = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto)) == INVALID_SOCKET) {
- perror("sock1");
- closesocket(sock);
- return -1;
- }
- else {
- struct sockaddr addr = {0};
- int l = sizeof(addr);
- if (getsockname(sock, &addr, &l) == -1) {
- perror("getsockname");
- closesocket(sock);
- return -1;
- }
-
- if (connect(sv[1], &addr, sizeof(addr)) == -1) {
- int err = WSAGetLastError();
- fprintf(stderr, "connect wsaerrr %d\n", err);
- closesocket(sock);
- closesocket(sv[1]);
- return -1;
- }
-
- if ((sv[0] = accept(sock, &addr, &l)) == INVALID_SOCKET) {
- perror("accept");
- closesocket(sock);
- closesocket(sv[1]);
- return -1;
- }
- }
-
- configure_pipe_socket(io, sv[0]);
- configure_pipe_socket(io, sv[1]);
- closesocket(sock);
- return 0;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/iocp.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.c b/proton-c/src/windows/iocp.c
deleted file mode 100644
index d1abc9a..0000000
--- a/proton-c/src/windows/iocp.c
+++ /dev/null
@@ -1,1176 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <mswsock.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/object.h>
-#include <proton/io.h>
-#include <proton/selector.h>
-#include <proton/error.h>
-#include <proton/transport.h>
-#include "iocp.h"
-#include "util.h"
-#include <assert.h>
-
-/*
- * Windows IO Completion Port support for Proton.
- *
- * Overlapped writes are used to avoid lengthy stalls between write
- * completion and starting a new write. Non-overlapped reads are used
- * since Windows accumulates inbound traffic without stalling and
- * managing read buffers would not avoid a memory copy at the pn_read
- * boundary.
- *
- * A socket must not get a Windows closesocket() unless the
- * application has called pn_close on the socket or a global
- * pn_io_finalize(). On error, the internal accounting for
- * write_closed or read_closed may be updated along with the external
- * event notification. A socket may be closed if it is never added to
- * the iocpdesc_map or is on its way out of the map.
- */
-
-// Max number of overlapped accepts per listener
-#define IOCP_MAX_ACCEPTS 10
-
-// AcceptEx squishes the local and remote addresses and optional data
-// all together when accepting the connection. Reserve enough for
-// IPv6 addresses, even if the socket is IPv4. The 16 bytes padding
-// per address is required by AcceptEx.
-#define IOCP_SOCKADDRMAXLEN (sizeof(sockaddr_in6) + 16)
-#define IOCP_SOCKADDRBUFLEN (2 * IOCP_SOCKADDRMAXLEN)
-
-static void iocp_log(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fflush(stderr);
-}
-
-static void set_iocp_error_status(pn_error_t *error, int code, HRESULT status)
-{
- char buf[512];
- if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
- 0, status, 0, buf, sizeof(buf), 0))
- pn_error_set(error, code, buf);
- else {
- fprintf(stderr, "pn internal Windows error: %lu\n", GetLastError());
- }
-}
-
-static void reap_check(iocpdesc_t *);
-static void bind_to_completion_port(iocpdesc_t *iocpd);
-static void iocp_shutdown(iocpdesc_t *iocpd);
-static void start_reading(iocpdesc_t *iocpd);
-static bool is_listener(iocpdesc_t *iocpd);
-static void release_sys_sendbuf(SOCKET s);
-
-static void iocpdesc_fail(iocpdesc_t *iocpd, HRESULT status, const char* text)
-{
- pni_win32_error(iocpd->error, text, status);
- if (iocpd->iocp->iocp_trace) {
- iocp_log("connection terminated: %s\n", pn_error_text(iocpd->error));
- }
- iocpd->write_closed = true;
- iocpd->read_closed = true;
- iocpd->poll_error = true;
- pni_events_update(iocpd, iocpd->events & ~(PN_READABLE | PN_WRITABLE));
-}
-
-// Helper functions to use specialized IOCP AcceptEx() and ConnectEx()
-static LPFN_ACCEPTEX lookup_accept_ex(SOCKET s)
-{
- GUID guid = WSAID_ACCEPTEX;
- DWORD bytes = 0;
- LPFN_ACCEPTEX fn;
- WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
- &fn, sizeof(fn), &bytes, NULL, NULL);
- assert(fn);
- return fn;
-}
-
-static LPFN_CONNECTEX lookup_connect_ex(SOCKET s)
-{
- GUID guid = WSAID_CONNECTEX;
- DWORD bytes = 0;
- LPFN_CONNECTEX fn;
- WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
- &fn, sizeof(fn), &bytes, NULL, NULL);
- assert(fn);
- return fn;
-}
-
-static LPFN_GETACCEPTEXSOCKADDRS lookup_get_accept_ex_sockaddrs(SOCKET s)
-{
- GUID guid = WSAID_GETACCEPTEXSOCKADDRS;
- DWORD bytes = 0;
- LPFN_GETACCEPTEXSOCKADDRS fn;
- WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
- &fn, sizeof(fn), &bytes, NULL, NULL);
- assert(fn);
- return fn;
-}
-
-// match accept socket to listener socket
-static iocpdesc_t *create_same_type_socket(iocpdesc_t *iocpd)
-{
- sockaddr_storage sa;
- socklen_t salen = sizeof(sa);
- if (getsockname(iocpd->socket, (sockaddr*)&sa, &salen) == -1)
- return NULL;
- SOCKET s = socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM
- if (s == INVALID_SOCKET)
- return NULL;
- return pni_iocpdesc_create(iocpd->iocp, s, false);
-}
-
-static bool is_listener(iocpdesc_t *iocpd)
-{
- return iocpd && iocpd->acceptor;
-}
-
-// === Async accept processing
-
-typedef struct {
- iocp_result_t base;
- iocpdesc_t *new_sock;
- char address_buffer[IOCP_SOCKADDRBUFLEN];
- DWORD unused;
-} accept_result_t;
-
-static accept_result_t *accept_result(iocpdesc_t *listen_sock) {
- accept_result_t *result = (accept_result_t *)calloc(1, sizeof(accept_result_t));
- if (result) {
- result->base.type = IOCP_ACCEPT;
- result->base.iocpd = listen_sock;
- }
- return result;
-}
-
-static void reset_accept_result(accept_result_t *result) {
- memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
- memset(&result->address_buffer, 0, IOCP_SOCKADDRBUFLEN);
-}
-
-struct pni_acceptor_t {
- int accept_queue_size;
- pn_list_t *accepts;
- iocpdesc_t *listen_sock;
- bool signalled;
- LPFN_ACCEPTEX fn_accept_ex;
- LPFN_GETACCEPTEXSOCKADDRS fn_get_accept_ex_sockaddrs;
-};
-
-#define pni_acceptor_compare NULL
-#define pni_acceptor_inspect NULL
-#define pni_acceptor_hashcode NULL
-
-static void pni_acceptor_initialize(void *object)
-{
- pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
- acceptor->accepts = pn_list(PN_VOID, IOCP_MAX_ACCEPTS);
-}
-
-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);
-}
-
-static pni_acceptor_t *pni_acceptor(iocpdesc_t *iocpd)
-{
- static const pn_cid_t CID_pni_acceptor = CID_pn_void;
- static const pn_class_t clazz = PN_CLASS(pni_acceptor);
- pni_acceptor_t *acceptor = (pni_acceptor_t *) pn_class_new(&clazz, sizeof(pni_acceptor_t));
- acceptor->listen_sock = iocpd;
- acceptor->accept_queue_size = 0;
- acceptor->signalled = false;
- pn_socket_t sock = acceptor->listen_sock->socket;
- acceptor->fn_accept_ex = lookup_accept_ex(sock);
- acceptor->fn_get_accept_ex_sockaddrs = lookup_get_accept_ex_sockaddrs(sock);
- return acceptor;
-}
-
-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");
- }
-}
-
-static void complete_accept(accept_result_t *result, HRESULT status)
-{
- result->new_sock->ops_in_progress--;
- iocpdesc_t *ld = result->base.iocpd;
- if (ld->read_closed) {
- if (!result->new_sock->closing)
- pni_iocp_begin_close(result->new_sock);
- free(result); // discard
- reap_check(ld);
- } else {
- result->base.status = status;
- pn_list_add(ld->acceptor->accepts, result);
- pni_events_update(ld, ld->events | PN_READABLE);
- }
-}
-
-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;
-}
-
-
-// === Async connect processing
-
-typedef struct {
- iocp_result_t base;
- char address_buffer[IOCP_SOCKADDRBUFLEN];
- struct addrinfo *addrinfo;
-} connect_result_t;
-
-#define connect_result_initialize NULL
-#define connect_result_compare NULL
-#define connect_result_inspect NULL
-#define connect_result_hashcode NULL
-
-static void connect_result_finalize(void *object)
-{
- connect_result_t *result = (connect_result_t *) object;
- // Do not release addrinfo until ConnectEx completes
- if (result->addrinfo)
- freeaddrinfo(result->addrinfo);
-}
-
-static connect_result_t *connect_result(iocpdesc_t *iocpd, struct addrinfo *addr) {
- static const pn_cid_t CID_connect_result = CID_pn_void;
- static const pn_class_t clazz = PN_CLASS(connect_result);
- connect_result_t *result = (connect_result_t *) pn_class_new(&clazz, sizeof(connect_result_t));
- if (result) {
- memset(result, 0, sizeof(connect_result_t));
- result->base.type = IOCP_CONNECT;
- result->base.iocpd = iocpd;
- result->addrinfo = addr;
- }
- return result;
-}
-
-pn_socket_t pni_iocp_begin_connect(iocp_t *iocp, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error)
-{
- // addr lives for the duration of the async connect. Caller has passed ownership here.
- // See connect_result_finalize().
- // Use of Windows-specific ConnectEx() requires our socket to be "loosely" pre-bound:
- sockaddr_storage sa;
- memset(&sa, 0, sizeof(sa));
- sa.ss_family = addr->ai_family;
- if (bind(sock, (SOCKADDR *) &sa, addr->ai_addrlen)) {
- pni_win32_error(error, "begin async connection", WSAGetLastError());
- if (iocp->iocp_trace)
- iocp_log("%s\n", pn_error_text(error));
- closesocket(sock);
- freeaddrinfo(addr);
- return INVALID_SOCKET;
- }
-
- iocpdesc_t *iocpd = pni_iocpdesc_create(iocp, sock, false);
- bind_to_completion_port(iocpd);
- LPFN_CONNECTEX fn_connect_ex = lookup_connect_ex(iocpd->socket);
- connect_result_t *result = connect_result(iocpd, addr);
- DWORD unused;
- bool success = fn_connect_ex(iocpd->socket, result->addrinfo->ai_addr, result->addrinfo->ai_addrlen,
- NULL, 0, &unused, (LPOVERLAPPED) result);
- if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
- pni_win32_error(error, "ConnectEx failure", WSAGetLastError());
- pn_free(result);
- iocpd->write_closed = true;
- iocpd->read_closed = true;
- if (iocp->iocp_trace)
- iocp_log("%s\n", pn_error_text(error));
- } else {
- iocpd->ops_in_progress++;
- }
- return sock;
-}
-
-static void complete_connect(connect_result_t *result, HRESULT status)
-{
- iocpdesc_t *iocpd = result->base.iocpd;
- if (iocpd->closing) {
- pn_free(result);
- reap_check(iocpd);
- return;
- }
-
- if (status) {
- iocpdesc_fail(iocpd, status, "Connect failure");
- // Posix sets selectable events as follows:
- pni_events_update(iocpd, PN_READABLE | PN_EXPIRED);
- } else {
- release_sys_sendbuf(iocpd->socket);
- if (setsockopt(iocpd->socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0)) {
- iocpdesc_fail(iocpd, WSAGetLastError(), "Internal connect failure (update context)");
- } else {
- pni_events_update(iocpd, PN_WRITABLE);
- start_reading(iocpd);
- }
- }
- pn_free(result);
- return;
-}
-
-
-// === Async writes
-
-static bool write_in_progress(iocpdesc_t *iocpd)
-{
- return pni_write_pipeline_size(iocpd->pipeline) != 0;
-}
-
-write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen)
-{
- write_result_t *result = (write_result_t *) calloc(sizeof(write_result_t), 1);
- if (result) {
- result->base.type = IOCP_WRITE;
- result->base.iocpd = iocpd;
- result->buffer.start = buf;
- result->buffer.size = buflen;
- }
- return result;
-}
-
-static int submit_write(write_result_t *result, const void *buf, size_t len)
-{
- WSABUF wsabuf;
- wsabuf.buf = (char *) buf;
- wsabuf.len = len;
- memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
- return WSASend(result->base.iocpd->socket, &wsabuf, 1, NULL, 0,
- (LPOVERLAPPED) result, 0);
-}
-
-ssize_t pni_iocp_begin_write(iocpdesc_t *iocpd, const void *buf, size_t len, bool *would_block, pn_error_t *error)
-{
- if (len == 0) return 0;
- *would_block = false;
- if (is_listener(iocpd)) {
- set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
- return INVALID_SOCKET;
- }
- if (iocpd->closing) {
- set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
- return SOCKET_ERROR;
- }
- if (iocpd->write_closed) {
- assert(pn_error_code(iocpd->error));
- pn_error_copy(error, iocpd->error);
- if (iocpd->iocp->iocp_trace)
- iocp_log("write error: %s\n", pn_error_text(error));
- return SOCKET_ERROR;
- }
- if (len == 0) return 0;
- if (!(iocpd->events & PN_WRITABLE)) {
- *would_block = true;
- return SOCKET_ERROR;
- }
-
- size_t written = 0;
- size_t requested = len;
- const char *outgoing = (const char *) buf;
- size_t available = pni_write_pipeline_reserve(iocpd->pipeline, len);
- if (!available) {
- *would_block = true;
- return SOCKET_ERROR;
- }
-
- for (size_t wr_count = 0; wr_count < available; wr_count++) {
- write_result_t *result = pni_write_pipeline_next(iocpd->pipeline);
- assert(result);
- result->base.iocpd = iocpd;
- ssize_t actual_len = pn_min(len, result->buffer.size);
- result->requested = actual_len;
- memmove((void *)result->buffer.start, outgoing, actual_len);
- outgoing += actual_len;
- written += actual_len;
- len -= actual_len;
-
- int werror = submit_write(result, result->buffer.start, actual_len);
- if (werror && WSAGetLastError() != ERROR_IO_PENDING) {
- pni_write_pipeline_return(iocpd->pipeline, result);
- iocpdesc_fail(iocpd, WSAGetLastError(), "overlapped send");
- return SOCKET_ERROR;
- }
- iocpd->ops_in_progress++;
- }
-
- if (!pni_write_pipeline_writable(iocpd->pipeline))
- pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
- return written;
-}
-
-/*
- * Note: iocp write completion is not "bytes on the wire", it is "peer
- * acked the sent bytes". Completion can be seconds on a slow
- * consuming peer.
- */
-static void complete_write(write_result_t *result, DWORD xfer_count, HRESULT status)
-{
- iocpdesc_t *iocpd = result->base.iocpd;
- if (iocpd->closing) {
- pni_write_pipeline_return(iocpd->pipeline, result);
- if (!iocpd->write_closed && !write_in_progress(iocpd))
- iocp_shutdown(iocpd);
- reap_check(iocpd);
- return;
- }
- if (status == 0 && xfer_count > 0) {
- if (xfer_count != result->requested) {
- // Is this recoverable? How to preserve order if multiple overlapped writes?
- pni_write_pipeline_return(iocpd->pipeline, result);
- iocpdesc_fail(iocpd, WSA_OPERATION_ABORTED, "Partial overlapped write on socket");
- return;
- } else {
- // Success.
- pni_write_pipeline_return(iocpd->pipeline, result);
- if (pni_write_pipeline_writable(iocpd->pipeline))
- pni_events_update(iocpd, iocpd->events | PN_WRITABLE);
- return;
- }
- }
- // Other error
- pni_write_pipeline_return(iocpd->pipeline, result);
- if (status == WSAECONNABORTED || status == WSAECONNRESET || status == WSAENOTCONN
- || status == ERROR_NETNAME_DELETED) {
- iocpd->write_closed = true;
- iocpd->poll_error = true;
- pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
- pni_win32_error(iocpd->error, "Remote close or timeout", status);
- } else {
- iocpdesc_fail(iocpd, status, "IOCP async write error");
- }
-}
-
-
-// === Async reads
-
-struct read_result_t {
- iocp_result_t base;
- size_t drain_count;
- char unused_buf[1];
-};
-
-static read_result_t *read_result(iocpdesc_t *iocpd)
-{
- read_result_t *result = (read_result_t *) calloc(sizeof(read_result_t), 1);
- if (result) {
- result->base.type = IOCP_READ;
- result->base.iocpd = iocpd;
- }
- return result;
-}
-
-static void begin_zero_byte_read(iocpdesc_t *iocpd)
-{
- if (iocpd->read_in_progress) return;
- if (iocpd->read_closed) {
- pni_events_update(iocpd, iocpd->events | PN_READABLE);
- return;
- }
-
- read_result_t *result = iocpd->read_result;
- memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
- DWORD flags = 0;
- WSABUF wsabuf;
- wsabuf.buf = result->unused_buf;
- wsabuf.len = 0;
- int rc = WSARecv(iocpd->socket, &wsabuf, 1, NULL, &flags,
- &result->base.overlapped, 0);
- if (rc && WSAGetLastError() != ERROR_IO_PENDING) {
- iocpdesc_fail(iocpd, WSAGetLastError(), "IOCP read error");
- return;
- }
- iocpd->ops_in_progress++;
- iocpd->read_in_progress = true;
-}
-
-static void drain_until_closed(iocpdesc_t *iocpd) {
- size_t max_drain = 16 * 1024;
- char buf[512];
- read_result_t *result = iocpd->read_result;
- while (result->drain_count < max_drain) {
- int rv = recv(iocpd->socket, buf, 512, 0);
- if (rv > 0)
- result->drain_count += rv;
- else if (rv == 0) {
- iocpd->read_closed = true;
- return;
- } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
- // wait a little longer
- start_reading(iocpd);
- return;
- }
- else
- break;
- }
- // Graceful close indication unlikely, force the issue
- if (iocpd->iocp->iocp_trace)
- if (result->drain_count >= max_drain)
- iocp_log("graceful close on reader abandoned (too many chars)\n");
- else
- iocp_log("graceful close on reader abandoned: %d\n", WSAGetLastError());
- iocpd->read_closed = true;
-}
-
-
-static void complete_read(read_result_t *result, DWORD xfer_count, HRESULT status)
-{
- iocpdesc_t *iocpd = result->base.iocpd;
- iocpd->read_in_progress = false;
-
- if (iocpd->closing) {
- // Application no longer reading, but we are looking for a zero length read
- if (!iocpd->read_closed)
- drain_until_closed(iocpd);
- reap_check(iocpd);
- return;
- }
-
- if (status == 0 && xfer_count == 0) {
- // Success.
- pni_events_update(iocpd, iocpd->events | PN_READABLE);
- } else {
- iocpdesc_fail(iocpd, status, "IOCP read complete error");
- }
-}
-
-ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error)
-{
- if (size == 0) return 0;
- *would_block = false;
- if (is_listener(iocpd)) {
- set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
- return SOCKET_ERROR;
- }
- if (iocpd->closing) {
- // Previous call to pn_close()
- set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
- return SOCKET_ERROR;
- }
- if (iocpd->read_closed) {
- if (pn_error_code(iocpd->error))
- pn_error_copy(error, iocpd->error);
- else
- set_iocp_error_status(error, PN_ERR, WSAENOTCONN);
- return SOCKET_ERROR;
- }
-
- int count = recv(iocpd->socket, (char *) buf, size, 0);
- if (count > 0) {
- pni_events_update(iocpd, iocpd->events & ~PN_READABLE);
- begin_zero_byte_read(iocpd);
- return (ssize_t) count;
- } else if (count == 0) {
- iocpd->read_closed = true;
- return 0;
- }
- if (WSAGetLastError() == WSAEWOULDBLOCK)
- *would_block = true;
- else {
- set_iocp_error_status(error, PN_ERR, WSAGetLastError());
- iocpd->read_closed = true;
- }
- return SOCKET_ERROR;
-}
-
-static void start_reading(iocpdesc_t *iocpd)
-{
- begin_zero_byte_read(iocpd);
-}
-
-
-// === The iocp descriptor
-
-static void pni_iocpdesc_initialize(void *object)
-{
- iocpdesc_t *iocpd = (iocpdesc_t *) object;
- memset(iocpd, 0, sizeof(iocpdesc_t));
- iocpd->socket = INVALID_SOCKET;
-}
-
-static void pni_iocpdesc_finalize(void *object)
-{
- iocpdesc_t *iocpd = (iocpdesc_t *) object;
- pn_free(iocpd->acceptor);
- pn_error_free(iocpd->error);
- if (iocpd->pipeline)
- if (write_in_progress(iocpd))
- iocp_log("iocp descriptor write leak\n");
- else
- pn_free(iocpd->pipeline);
- if (iocpd->read_in_progress)
- iocp_log("iocp descriptor read leak\n");
- else
- free(iocpd->read_result);
-}
-
-static uintptr_t pni_iocpdesc_hashcode(void *object)
-{
- iocpdesc_t *iocpd = (iocpdesc_t *) object;
- return iocpd->socket;
-}
-
-#define pni_iocpdesc_compare NULL
-#define pni_iocpdesc_inspect NULL
-
-// Reference counted in the iocpdesc map, zombie_list, selector.
-static iocpdesc_t *pni_iocpdesc(pn_socket_t s)
-{
- static const pn_cid_t CID_pni_iocpdesc = CID_pn_void;
- static pn_class_t clazz = PN_CLASS(pni_iocpdesc);
- iocpdesc_t *iocpd = (iocpdesc_t *) pn_class_new(&clazz, sizeof(iocpdesc_t));
- assert(iocpd);
- iocpd->socket = s;
- return iocpd;
-}
-
-static bool is_listener_socket(pn_socket_t s)
-{
- BOOL tval = false;
- int tvalsz = sizeof(tval);
- int code = getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&tval, &tvalsz);
- return code == 0 && tval;
-}
-
-iocpdesc_t *pni_iocpdesc_create(iocp_t *iocp, pn_socket_t s, bool external) {
- assert (s != INVALID_SOCKET);
- assert(!pni_iocpdesc_map_get(iocp, s));
- bool listening = is_listener_socket(s);
- iocpdesc_t *iocpd = pni_iocpdesc(s);
- iocpd->iocp = iocp;
- if (iocpd) {
- iocpd->external = external;
- iocpd->error = pn_error();
- if (listening) {
- iocpd->acceptor = pni_acceptor(iocpd);
- } else {
- iocpd->pipeline = pni_write_pipeline(iocpd);
- iocpd->read_result = read_result(iocpd);
- }
- pni_iocpdesc_map_push(iocpd);
- }
- return iocpd;
-}
-
-iocpdesc_t *pni_deadline_desc(iocp_t *iocp) {
- // Non IO descriptor for selector deadlines. Do not add to iocpdesc map or
- // zombie list. Selector responsible to free/decref object.
- iocpdesc_t *iocpd = pni_iocpdesc(PN_INVALID_SOCKET);
- iocpd->iocp = iocp;
- iocpd->deadline_desc = true;
- return iocpd;
-}
-
-// === Fast lookup of a socket's iocpdesc_t
-
-iocpdesc_t *pni_iocpdesc_map_get(iocp_t *iocp, pn_socket_t s) {
- iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_get(iocp->iocpdesc_map, s);
- return iocpd;
-}
-
-void pni_iocpdesc_map_push(iocpdesc_t *iocpd) {
- pn_hash_put(iocpd->iocp->iocpdesc_map, iocpd->socket, iocpd);
- pn_decref(iocpd);
- assert(pn_refcount(iocpd) == 1);
-}
-
-void pni_iocpdesc_map_del(iocp_t *iocp, pn_socket_t s) {
- pn_hash_del(iocp->iocpdesc_map, (uintptr_t) s);
-}
-
-static void bind_to_completion_port(iocpdesc_t *iocpd)
-{
- if (iocpd->bound) return;
- if (!iocpd->iocp->completion_port) {
- iocpdesc_fail(iocpd, WSAEINVAL, "Incomplete setup, no completion port.");
- return;
- }
-
- if (CreateIoCompletionPort ((HANDLE) iocpd->socket, iocpd->iocp->completion_port, 0, 0))
- iocpd->bound = true;
- else {
- iocpdesc_fail(iocpd, GetLastError(), "IOCP socket setup.");
- }
-}
-
-static void release_sys_sendbuf(SOCKET s)
-{
- // Set the socket's send buffer size to zero.
- int sz = 0;
- int status = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char *)&sz, sizeof(int));
- assert(status == 0);
-}
-
-void pni_iocpdesc_start(iocpdesc_t *iocpd)
-{
- if (iocpd->bound) return;
- bind_to_completion_port(iocpd);
- if (is_listener(iocpd)) {
- begin_accept(iocpd->acceptor, NULL);
- }
- else {
- release_sys_sendbuf(iocpd->socket);
- pni_events_update(iocpd, PN_WRITABLE);
- start_reading(iocpd);
- }
-}
-
-static void complete(iocp_result_t *result, bool success, DWORD num_transferred) {
- result->iocpd->ops_in_progress--;
- DWORD status = success ? 0 : GetLastError();
-
- switch (result->type) {
- case IOCP_ACCEPT:
- complete_accept((accept_result_t *) result, status);
- break;
- case IOCP_CONNECT:
- complete_connect((connect_result_t *) result, status);
- break;
- case IOCP_WRITE:
- complete_write((write_result_t *) result, num_transferred, status);
- break;
- case IOCP_READ:
- complete_read((read_result_t *) result, num_transferred, status);
- break;
- default:
- assert(false);
- }
-}
-
-void pni_iocp_drain_completions(iocp_t *iocp)
-{
- while (true) {
- DWORD timeout_ms = 0;
- DWORD num_transferred = 0;
- ULONG_PTR completion_key = 0;
- OVERLAPPED *overlapped = 0;
-
- bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
- &completion_key, &overlapped, timeout_ms);
- if (!overlapped)
- return; // timed out
- iocp_result_t *result = (iocp_result_t *) overlapped;
- complete(result, good_op, num_transferred);
- }
-}
-
-// returns: -1 on error, 0 on timeout, 1 successful completion
-int pni_iocp_wait_one(iocp_t *iocp, int timeout, pn_error_t *error) {
- DWORD win_timeout = (timeout < 0) ? INFINITE : (DWORD) timeout;
- DWORD num_transferred = 0;
- ULONG_PTR completion_key = 0;
- OVERLAPPED *overlapped = 0;
-
- bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
- &completion_key, &overlapped, win_timeout);
- if (!overlapped)
- if (GetLastError() == WAIT_TIMEOUT)
- return 0;
- else {
- if (error)
- pni_win32_error(error, "GetQueuedCompletionStatus", GetLastError());
- return -1;
- }
-
- iocp_result_t *result = (iocp_result_t *) overlapped;
- complete(result, good_op, num_transferred);
- return 1;
-}
-
-// === Close (graceful and otherwise)
-
-// zombie_list is for sockets transitioning out of iocp on their way to zero ops_in_progress
-// and fully closed.
-
-static void zombie_list_add(iocpdesc_t *iocpd)
-{
- assert(iocpd->closing);
- if (!iocpd->ops_in_progress) {
- // No need to make a zombie.
- if (iocpd->socket != INVALID_SOCKET) {
- closesocket(iocpd->socket);
- iocpd->socket = INVALID_SOCKET;
- iocpd->read_closed = true;
- }
- return;
- }
- // Allow 2 seconds for graceful shutdown before releasing socket resource.
- iocpd->reap_time = pn_i_now() + 2000;
- pn_list_add(iocpd->iocp->zombie_list, iocpd);
-}
-
-static void reap_check(iocpdesc_t *iocpd)
-{
- if (iocpd->closing && !iocpd->ops_in_progress) {
- if (iocpd->socket != INVALID_SOCKET) {
- closesocket(iocpd->socket);
- iocpd->socket = INVALID_SOCKET;
- }
- pn_list_remove(iocpd->iocp->zombie_list, iocpd);
- // iocpd is decref'ed and possibly released
- }
-}
-
-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;
-}
-
-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
- }
-}
-
-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");
-}
-
-static pn_list_t *iocp_map_close_all(iocp_t *iocp)
-{
- // Zombify stragglers, i.e. no pn_close() from the application.
- pn_list_t *externals = pn_list(PN_OBJECT, 0);
- for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
- entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
- iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
- // Just listeners first.
- if (is_listener(iocpd)) {
- if (iocpd->external) {
- // Owned by application, just keep a temporary reference to it.
- // iocp_result_t structs must not be free'd until completed or
- // the completion port is closed.
- if (iocpd->ops_in_progress)
- pn_list_add(externals, iocpd);
- pni_iocpdesc_map_del(iocp, iocpd->socket);
- } else {
- // Make it a zombie.
- pni_iocp_begin_close(iocpd);
- }
- }
- }
- pni_iocp_drain_completions(iocp);
-
- for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
- entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
- iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
- if (iocpd->external) {
- iocpd->read_closed = true; // Do not consume from read side
- iocpd->write_closed = true; // Do not shutdown write side
- if (iocpd->ops_in_progress)
- pn_list_add(externals, iocpd);
- pni_iocpdesc_map_del(iocp, iocpd->socket);
- } else {
- // Make it a zombie.
- pni_iocp_begin_close(iocpd);
- }
- }
- return externals;
-}
-
-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);
-}
-
-static void iocp_shutdown(iocpdesc_t *iocpd)
-{
- if (iocpd->socket == PN_INVALID_SOCKET)
- return; // Hard close in progress
- if (shutdown(iocpd->socket, SD_SEND)) {
- int err = WSAGetLastError();
- if (err != WSAECONNABORTED && err != WSAECONNRESET && err != WSAENOTCONN)
- if (iocpd->iocp->iocp_trace)
- iocp_log("socket shutdown failed %d\n", err);
- }
- iocpd->write_closed = true;
-}
-
-void pni_iocp_begin_close(iocpdesc_t *iocpd)
-{
- assert (!iocpd->closing);
- if (is_listener(iocpd)) {
- // Listening socket is easy. Close the socket which will cancel async ops.
- pn_socket_t old_sock = iocpd->socket;
- iocpd->socket = INVALID_SOCKET;
- iocpd->closing = true;
- iocpd->read_closed = true;
- iocpd->write_closed = true;
- closesocket(old_sock);
- // Pending accepts will now complete. Zombie can die when all consumed.
- zombie_list_add(iocpd);
- pni_iocpdesc_map_del(iocpd->iocp, old_sock); // may pn_free *iocpd
- } else {
- // Continue async operation looking for graceful close confirmation or timeout.
- pn_socket_t old_sock = iocpd->socket;
- iocpd->closing = true;
- if (!iocpd->write_closed && !write_in_progress(iocpd))
- iocp_shutdown(iocpd);
- zombie_list_add(iocpd);
- pni_iocpdesc_map_del(iocpd->iocp, old_sock); // may pn_free *iocpd
- }
-}
-
-
-// === iocp_t
-
-#define pni_iocp_hashcode NULL
-#define pni_iocp_compare NULL
-#define pni_iocp_inspect NULL
-
-void pni_iocp_initialize(void *obj)
-{
- iocp_t *iocp = (iocp_t *) obj;
- memset(iocp, 0, sizeof(iocp_t));
- pni_shared_pool_create(iocp);
- iocp->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
- assert(iocp->completion_port != NULL);
- iocp->iocpdesc_map = pn_hash(PN_OBJECT, 0, 0.75);
- iocp->zombie_list = pn_list(PN_OBJECT, 0);
- iocp->iocp_trace = pn_env_bool("PN_TRACE_DRV");
- iocp->selector = NULL;
-}
-
-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);
-}
-
-iocp_t *pni_iocp()
-{
- static const pn_cid_t CID_pni_iocp = CID_pn_void;
- static const pn_class_t clazz = PN_CLASS(pni_iocp);
- iocp_t *iocp = (iocp_t *) pn_class_new(&clazz, sizeof(iocp_t));
- return iocp;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/iocp.h
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.h b/proton-c/src/windows/iocp.h
deleted file mode 100644
index 0e052e5..0000000
--- a/proton-c/src/windows/iocp.h
+++ /dev/null
@@ -1,144 +0,0 @@
-#ifndef PROTON_SRC_IOCP_H
-#define PROTON_SRC_IOCP_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <proton/selectable.h>
-#include <proton/type_compat.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct pni_acceptor_t pni_acceptor_t;
-typedef struct write_result_t write_result_t;
-typedef struct read_result_t read_result_t;
-typedef struct write_pipeline_t write_pipeline_t;
-typedef struct iocpdesc_t iocpdesc_t;
-
-
-// One per pn_io_t.
-
-struct iocp_t {
- HANDLE completion_port;
- pn_hash_t *iocpdesc_map;
- pn_list_t *zombie_list;
- int shared_pool_size;
- char *shared_pool_memory;
- write_result_t **shared_results;
- write_result_t **available_results;
- size_t shared_available_count;
- size_t writer_count;
- int loopback_bufsize;
- bool iocp_trace;
- pn_selector_t *selector;
-};
-
-
-// One for each socket.
-// This iocpdesc_t structure is ref counted by the iocpdesc_map, zombie_list,
-// selector->iocp_descriptors list. It should remain ref counted in the
-// zombie_list until ops_in_progress == 0 or the completion port is closed.
-
-struct iocpdesc_t {
- pn_socket_t socket;
- iocp_t *iocp;
- pni_acceptor_t *acceptor;
- pn_error_t *error;
- int ops_in_progress;
- bool read_in_progress;
- write_pipeline_t *pipeline;
- read_result_t *read_result;
- bool external; // true if socket set up outside Proton
- bool bound; // associted with the completion port
- bool closing; // pn_close called by application
- bool read_closed; // EOF or read error
- bool write_closed; // shutdown sent or write error
- bool poll_error; // flag posix-like POLLERR/POLLHUP/POLLNVAL
- bool deadline_desc; // Socket-less deadline descriptor for selectors
- pn_selector_t *selector;
- pn_selectable_t *selectable;
- int events;
- int interests;
- pn_timestamp_t deadline;
- iocpdesc_t *triggered_list_next;
- iocpdesc_t *triggered_list_prev;
- iocpdesc_t *deadlines_next;
- iocpdesc_t *deadlines_prev;
- pn_timestamp_t reap_time;;
-};
-
-typedef enum { IOCP_ACCEPT, IOCP_CONNECT, IOCP_READ, IOCP_WRITE } iocp_type_t;
-
-typedef struct {
- OVERLAPPED overlapped;
- iocp_type_t type;
- iocpdesc_t *iocpd;
- HRESULT status;
-} iocp_result_t;
-
-struct write_result_t {
- iocp_result_t base;
- size_t requested;
- bool in_use;
- pn_bytes_t buffer;
-};
-
-iocpdesc_t *pni_iocpdesc_create(iocp_t *, pn_socket_t s, bool external);
-iocpdesc_t *pni_iocpdesc_map_get(iocp_t *, pn_socket_t s);
-iocpdesc_t *pni_deadline_desc(iocp_t *);
-void pni_iocpdesc_map_del(iocp_t *, pn_socket_t s);
-void pni_iocpdesc_map_push(iocpdesc_t *iocpd);
-void pni_iocpdesc_start(iocpdesc_t *iocpd);
-void pni_iocp_drain_completions(iocp_t *);
-int pni_iocp_wait_one(iocp_t *, int timeout, pn_error_t *);
-void pni_iocp_start_accepting(iocpdesc_t *iocpd);
-pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error);
-pn_socket_t pni_iocp_begin_connect(iocp_t *, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error);
-ssize_t pni_iocp_begin_write(iocpdesc_t *, const void *, size_t, bool *, pn_error_t *);
-ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error);
-void pni_iocp_begin_close(iocpdesc_t *iocpd);
-iocp_t *pni_iocp();
-
-void pni_events_update(iocpdesc_t *iocpd, int events);
-write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen);
-write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd);
-size_t pni_write_pipeline_size(write_pipeline_t *);
-bool pni_write_pipeline_writable(write_pipeline_t *);
-void pni_write_pipeline_return(write_pipeline_t *, write_result_t *);
-size_t pni_write_pipeline_reserve(write_pipeline_t *, size_t);
-write_result_t *pni_write_pipeline_next(write_pipeline_t *);
-void pni_shared_pool_create(iocp_t *);
-void pni_shared_pool_free(iocp_t *);
-void pni_zombie_check(iocp_t *, pn_timestamp_t);
-pn_timestamp_t pni_zombie_deadline(iocp_t *);
-
-pn_selector_t *pni_selector_create(iocp_t *iocp);
-
-int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* iocp.h */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org