blob: f8a0f3d779e28b9f9097b916ac42f378e1d8a7eb [file] [log] [blame]
/*
* 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.
*/
%module cproton
%{
#define PN_USE_DEPRECATED_API 1
#include <proton/connection_driver.h>
#include <proton/engine.h>
#include <proton/handlers.h>
#include <proton/message.h>
#include <proton/messenger.h>
#include <proton/reactor.h>
#include <proton/sasl.h>
#include <proton/ssl.h>
#include <proton/types.h>
#include <proton/url.h>
%}
/*
NOTE: According to ccache-swig man page: "Known problems are using
preprocessor directives within %inline blocks and the use of ’#pragma SWIG’."
This includes using macros in an %inline section.
Keep preprocessor directives and macro expansions in the normal header section.
*/
%include <cstring.i>
%cstring_output_withsize(char *OUTPUT, size_t *OUTPUT_SIZE)
%cstring_output_allocate_size(char **ALLOC_OUTPUT, size_t *ALLOC_SIZE, free(*$1));
%cstring_output_maxsize(char *OUTPUT, size_t MAX_OUTPUT_SIZE)
%{
#if !defined(RSTRING_LEN)
# define RSTRING_LEN(x) (RSTRING(x)->len)
# define RSTRING_PTR(x) (RSTRING(x)->ptr)
#endif
%}
/* Treat pn_handle_t like uintptr_t - syntactically it is a C void* but really it's just an int */
%apply uintptr_t { pn_handle_t };
%typemap(in) pn_bytes_t {
if ($input == Qnil) {
$1.start = NULL;
$1.size = 0;
} else {
$1.start = RSTRING_PTR($input);
if (!$1.start) {
$1.size = 0;
}
$1.size = RSTRING_LEN($input);
}
}
%typemap(out) pn_bytes_t {
$result = rb_str_new($1.start, $1.size);
}
%typemap(in) pn_atom_t
{
if ($input == Qnil)
{
$1.type = PN_NULL;
}
else
{
switch(TYPE($input))
{
case T_TRUE:
$1.type = PN_BOOL;
$1.u.as_bool = true;
break;
case T_FALSE:
$1.type = PN_BOOL;
$1.u.as_bool = false;
break;
case T_FLOAT:
$1.type = PN_FLOAT;
$1.u.as_float = NUM2DBL($input);
break;
case T_STRING:
$1.type = PN_STRING;
$1.u.as_bytes.start = RSTRING_PTR($input);
if ($1.u.as_bytes.start)
{
$1.u.as_bytes.size = RSTRING_LEN($input);
}
else
{
$1.u.as_bytes.size = 0;
}
break;
case T_FIXNUM:
$1.type = PN_INT;
$1.u.as_int = FIX2LONG($input);
break;
case T_BIGNUM:
$1.type = PN_LONG;
$1.u.as_long = NUM2LL($input);
break;
}
}
}
%typemap(out) pn_atom_t
{
switch($1.type)
{
case PN_NULL:
$result = Qnil;
break;
case PN_BOOL:
$result = $1.u.as_bool ? Qtrue : Qfalse;
break;
case PN_BYTE:
$result = INT2NUM($1.u.as_byte);
break;
case PN_UBYTE:
$result = UINT2NUM($1.u.as_ubyte);
break;
case PN_SHORT:
$result = INT2NUM($1.u.as_short);
break;
case PN_USHORT:
$result = UINT2NUM($1.u.as_ushort);
break;
case PN_INT:
$result = INT2NUM($1.u.as_int);
break;
case PN_UINT:
$result = UINT2NUM($1.u.as_uint);
break;
case PN_LONG:
$result = LL2NUM($1.u.as_long);
break;
case PN_ULONG:
$result = ULL2NUM($1.u.as_ulong);
break;
case PN_FLOAT:
$result = rb_float_new($1.u.as_float);
break;
case PN_DOUBLE:
$result = rb_float_new($1.u.as_double);
break;
case PN_STRING:
$result = rb_str_new($1.u.as_bytes.start, $1.u.as_bytes.size);
break;
default:
break;
}
}
%typemap (in) pn_decimal32_t
{
$1 = NUM2UINT($input);
}
%typemap (out) pn_decimal32_t
{
$result = UINT2NUM($1);
}
%typemap (in) pn_decimal64_t
{
$1 = NUM2ULL($input);
}
%typemap (out) pn_decimal64_t
{
$result = ULL2NUM($1);
}
%typemap (in) pn_decimal128_t
{
int index;
for(index = 0; index < 16; index++)
{
VALUE element = rb_ary_entry($input, index);
$1.bytes[16 - (index + 1)] = FIX2INT(element);
}
}
%typemap (out) pn_decimal128_t
{
int index;
$result = rb_ary_new2(16);
for(index = 0; index < 16; index++)
{
rb_ary_store($result, 16 - (index + 1), CHR2FIX($1.bytes[index]));
}
}
%typemap (in) pn_uuid_t
{
int index;
for(index = 0; index < 16; index++)
{
VALUE element = rb_ary_entry($input, index);
$1.bytes[16 - (index + 1)] = FIX2INT(element);
}
}
%typemap (out) pn_uuid_t
{
int index;
$result = rb_ary_new2(16);
for(index = 0; index < 16; index++)
{
rb_ary_store($result, 16 - (index + 1), CHR2FIX($1.bytes[index]));
}
}
int pn_message_encode(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
%ignore pn_message_encode;
ssize_t pn_link_send(pn_link_t *transport, char *STRING, size_t LENGTH);
%ignore pn_link_send;
%rename(pn_link_recv) wrap_pn_link_recv;
%inline %{
int wrap_pn_link_recv(pn_link_t *link, char *OUTPUT, size_t *OUTPUT_SIZE) {
ssize_t sz = pn_link_recv(link, OUTPUT, *OUTPUT_SIZE);
if (sz >= 0) {
*OUTPUT_SIZE = sz;
} else {
*OUTPUT_SIZE = 0;
}
return sz;
}
%}
%ignore pn_link_recv;
ssize_t pn_transport_input(pn_transport_t *transport, char *STRING, size_t LENGTH);
%ignore pn_transport_input;
%rename(pn_transport_output) wrap_pn_transport_output;
%inline %{
int wrap_pn_transport_output(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) {
ssize_t sz = pn_transport_output(transport, OUTPUT, *OUTPUT_SIZE);
if (sz >= 0) {
*OUTPUT_SIZE = sz;
} else {
*OUTPUT_SIZE = 0;
}
return sz;
}
%}
%ignore pn_transport_output;
%rename(pn_transport_peek) wrap_pn_transport_peek;
%inline %{
int wrap_pn_transport_peek(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) {
ssize_t sz = pn_transport_peek(transport, OUTPUT, *OUTPUT_SIZE);
if(sz >= 0) {
*OUTPUT_SIZE = sz;
} else {
*OUTPUT_SIZE = 0;
}
return sz;
}
%}
%ignore pn_transport_peek;
%rename(pn_delivery) wrap_pn_delivery;
%inline %{
pn_delivery_t *wrap_pn_delivery(pn_link_t *link, char *STRING, size_t LENGTH) {
return pn_delivery(link, pn_dtag(STRING, LENGTH));
}
%}
%ignore pn_delivery;
// Suppress "Warning(451): Setting a const char * variable may leak memory." on pn_delivery_tag_t
%warnfilter(451) pn_delivery_tag_t;
%rename(pn_delivery_tag) wrap_pn_delivery_tag;
%inline %{
void wrap_pn_delivery_tag(pn_delivery_t *delivery, char **ALLOC_OUTPUT, size_t *ALLOC_SIZE) {
pn_delivery_tag_t tag = pn_delivery_tag(delivery);
*ALLOC_OUTPUT = malloc(tag.size);
*ALLOC_SIZE = tag.size;
memcpy(*ALLOC_OUTPUT, tag.start, tag.size);
}
%}
%ignore pn_delivery_tag;
bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE);
%ignore pn_ssl_get_cipher_name;
bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE);
%ignore pn_ssl_get_protocol_name;
/* TODO aconway 2018-02-14: Remove RB_BLOCKING_CALL once messenger is deprecated */
/* Don't use %inline sections for #define */
%{
#if defined(RUBY_USE_rb_thread_call_without_gvl)
#include <ruby/thread.h>
typedef void *non_blocking_return_t;
#define RB_BLOCKING_CALL (VALUE)rb_thread_call_without_gvl
#elif defined(RUBY_USE_rb_thread_blocking_region)
typedef VALUE non_blocking_return_t;
#define RB_BLOCKING_CALL rb_thread_blocking_region
#endif
%}
%rename(pn_messenger_send) wrap_pn_messenger_send;
%rename(pn_messenger_recv) wrap_pn_messenger_recv;
%rename(pn_messenger_work) wrap_pn_messenger_work;
%inline %{
#if defined(RB_BLOCKING_CALL)
static non_blocking_return_t pn_messenger_send_no_gvl(void *args) {
VALUE result = Qnil;
pn_messenger_t *messenger = (pn_messenger_t *)((void **)args)[0];
int *limit = (int *)((void **)args)[1];
int rc = pn_messenger_send(messenger, *limit);
result = INT2NUM(rc);
return (non_blocking_return_t )result;
}
static non_blocking_return_t pn_messenger_recv_no_gvl(void *args) {
VALUE result = Qnil;
pn_messenger_t *messenger = (pn_messenger_t *)((void **)args)[0];
int *limit = (int *)((void **)args)[1];
int rc = pn_messenger_recv(messenger, *limit);
result = INT2NUM(rc);
return (non_blocking_return_t )result;
}
static non_blocking_return_t pn_messenger_work_no_gvl(void *args) {
VALUE result = Qnil;
pn_messenger_t *messenger = (pn_messenger_t *)((void **)args)[0];
int *timeout = (int *)((void **)args)[1];
int rc = pn_messenger_work(messenger, *timeout);
result = INT2NUM(rc);
return (non_blocking_return_t )result;
}
#endif
int wrap_pn_messenger_send(pn_messenger_t *messenger, int limit) {
int result = 0;
#if defined(RB_BLOCKING_CALL)
// only release the gil if we're blocking
if(pn_messenger_is_blocking(messenger)) {
VALUE rc;
void* args[2];
args[0] = messenger;
args[1] = &limit;
rc = RB_BLOCKING_CALL(pn_messenger_send_no_gvl,
&args, RUBY_UBF_PROCESS, NULL);
if(RTEST(rc))
{
result = FIX2INT(rc);
}
}
#else // !defined(RB_BLOCKING_CALL)
result = pn_messenger_send(messenger, limit);
#endif // defined(RB_BLOCKING_CALL)
return result;
}
int wrap_pn_messenger_recv(pn_messenger_t *messenger, int limit) {
int result = 0;
#if defined(RB_BLOCKING_CALL)
// only release the gil if we're blocking
if(pn_messenger_is_blocking(messenger)) {
VALUE rc;
void* args[2];
args[0] = messenger;
args[1] = &limit;
rc = RB_BLOCKING_CALL(pn_messenger_recv_no_gvl,
&args, RUBY_UBF_PROCESS, NULL);
if(RTEST(rc))
{
result = FIX2INT(rc);
}
} else {
result = pn_messenger_recv(messenger, limit);
}
#else // !defined(RB_BLOCKING_CALL)
result = pn_messenger_recv(messenger, limit);
#endif // defined(RB_BLOCKING_CALL)
return result;
}
int wrap_pn_messenger_work(pn_messenger_t *messenger, int timeout) {
int result = 0;
#if defined(RB_BLOCKING_CALL)
// only release the gil if we're blocking
if(timeout) {
VALUE rc;
void* args[2];
args[0] = messenger;
args[1] = &timeout;
rc = RB_BLOCKING_CALL(pn_messenger_work_no_gvl,
&args, RUBY_UBF_PROCESS, NULL);
if(RTEST(rc))
{
result = FIX2INT(rc);
}
} else {
result = pn_messenger_work(messenger, timeout);
}
#else
result = pn_messenger_work(messenger, timeout);
#endif
return result;
}
%}
%ignore pn_messenger_send;
%ignore pn_messenger_recv;
%ignore pn_messenger_work;
%{
typedef struct Pn_rbkey_t {
void *registry;
char *method;
char *key_value;
} Pn_rbkey_t;
void Pn_rbkey_initialize(void *vp_rbkey) {
Pn_rbkey_t *rbkey = (Pn_rbkey_t*)vp_rbkey;
assert(rbkey);
rbkey->registry = NULL;
rbkey->method = NULL;
rbkey->key_value = NULL;
}
void Pn_rbkey_finalize(void *vp_rbkey) {
Pn_rbkey_t *rbkey = (Pn_rbkey_t*)vp_rbkey;
if(rbkey && rbkey->registry && rbkey->method && rbkey->key_value) {
rb_funcall((VALUE )rbkey->registry, rb_intern(rbkey->method), 1, rb_str_new2(rbkey->key_value));
}
if(rbkey->key_value) {
free(rbkey->key_value);
rbkey->key_value = NULL;
}
}
/* NOTE: no macro or preprocessor definitions in %inline sections */
#define CID_Pn_rbkey CID_pn_void
#define Pn_rbkey_inspect NULL
#define Pn_rbkey_compare NULL
#define Pn_rbkey_hashcode NULL
pn_class_t* Pn_rbkey__class(void) {
static pn_class_t clazz = PN_CLASS(Pn_rbkey);
return &clazz;
}
Pn_rbkey_t *Pn_rbkey_new(void) {
return (Pn_rbkey_t *) pn_class_new(Pn_rbkey__class(), sizeof(Pn_rbkey_t));
}
%}
pn_class_t* Pn_rbkey__class(void);
Pn_rbkey_t *Pn_rbkey_new(void);
%inline %{
Pn_rbkey_t *Pn_rbkey_new(void);
void Pn_rbkey_set_registry(Pn_rbkey_t *rbkey, void *registry) {
assert(rbkey);
rbkey->registry = registry;
}
void *Pn_rbkey_get_registry(Pn_rbkey_t *rbkey) {
assert(rbkey);
return rbkey->registry;
}
void Pn_rbkey_set_method(Pn_rbkey_t *rbkey, char *method) {
assert(rbkey);
rbkey->method = method;
}
char *Pn_rbkey_get_method(Pn_rbkey_t *rbkey) {
assert(rbkey);
return rbkey->method;
}
void Pn_rbkey_set_key_value(Pn_rbkey_t *rbkey, char *key_value) {
assert(rbkey);
rbkey->key_value = malloc(strlen(key_value) + 1);
strncpy(rbkey->key_value, key_value, strlen(key_value) + 1);
}
char *Pn_rbkey_get_key_value(Pn_rbkey_t *rbkey) {
assert(rbkey);
return rbkey->key_value;
}
Pn_rbkey_t *pni_void2rbkey(void *object) {
return (Pn_rbkey_t *)object;
}
VALUE pn_void2rb(void *object) {
return (VALUE )object;
}
void *pn_rb2void(VALUE object) {
return (void *)object;
}
VALUE pni_address_of(void *object) {
return ULL2NUM((unsigned long )object);
}
%}
int pn_ssl_get_peer_hostname(pn_ssl_t *ssl, char *OUTPUT, size_t *OUTPUT_SIZE);
%ignore pn_ssl_get_peer_hostname;
%inline %{
VALUE pni_ruby_get_proton_module() {
VALUE mQpid = rb_define_module("Qpid");
return rb_define_module_under(mQpid, "Proton");
}
void pni_ruby_add_to_registry(VALUE key, VALUE value) {
VALUE result = rb_funcall(pni_ruby_get_proton_module(), rb_intern("add_to_registry"), 2, key, value);
}
VALUE pni_ruby_get_from_registry(VALUE key) {
return rb_funcall(pni_ruby_get_proton_module(), rb_intern("get_from_registry"), 1, key);
}
void pni_ruby_delete_from_registry(VALUE stored_key) {
rb_funcall(pni_ruby_get_proton_module(), rb_intern("delete_from_registry"), 1, stored_key);
}
typedef struct {
VALUE handler_key;
} Pni_rbhandler_t;
static Pni_rbhandler_t *pni_rbhandler(pn_handler_t *handler) {
return (Pni_rbhandler_t *) pn_handler_mem(handler);
}
static void pni_rbdispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
Pni_rbhandler_t *rbh = pni_rbhandler(handler);
VALUE rbhandler = pni_ruby_get_from_registry(rbh->handler_key);
rb_funcall(rbhandler, rb_intern("dispatch"), 2, SWIG_NewPointerObj(event, SWIGTYPE_p_pn_event_t, 0), INT2FIX(type));
}
static void pni_rbhandler_finalize(pn_handler_t *handler) {
Pni_rbhandler_t *rbh = pni_rbhandler(handler);
pni_ruby_delete_from_registry(rbh->handler_key);
}
pn_handler_t *pn_rbhandler(VALUE handler) {
pn_handler_t *chandler = pn_handler_new(pni_rbdispatch, sizeof(Pni_rbhandler_t), pni_rbhandler_finalize);
Pni_rbhandler_t *rhy = pni_rbhandler(chandler);
VALUE ruby_key = rb_class_new_instance(0, NULL, rb_cObject);
pni_ruby_add_to_registry(ruby_key, handler);
rhy->handler_key = ruby_key;
return chandler;
}
/* Helpers for working with pn_connection_driver_t */
size_t pni_connection_driver_read_size(pn_connection_driver_t* d) {
return pn_connection_driver_read_buffer(d).size;
}
size_t pni_connection_driver_write_size(pn_connection_driver_t* d) {
return pn_connection_driver_write_buffer(d).size;
}
pn_connection_t *pni_connection_driver_connection(pn_connection_driver_t* d) {
return d->connection;
}
pn_transport_t *pni_connection_driver_transport(pn_connection_driver_t* d) {
return d->transport;
}
size_t pni_connection_driver_read_copy(pn_connection_driver_t* d, char *STRING, size_t LENGTH ) {
pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(d);
size_t n = LENGTH < rbuf.size ? LENGTH : rbuf.size;
memcpy(rbuf.start, STRING, n);
pn_connection_driver_read_done(d, n);
return n;
}
pn_connection_driver_t *pni_connection_driver() {
pn_connection_driver_t *d = (pn_connection_driver_t*)malloc(sizeof(*d));
if (pn_connection_driver_init(d, NULL, NULL) != 0) {
free(d);
return NULL;
}
return d;
}
%}
%include "proton/cproton.i"
%include "proton/url.h"