blob: 647a4e05e9421a94d3762295551879fd96991c80 [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.
# ===================================================================
#
import types
import ctypes
### make this work on all platforms
def _loadlib(which):
return ctypes.cdll.LoadLibrary(which)
_serf = _loadlib('../../libserf-2.dylib')
_apr = _loadlib('libapr-1.dylib')
#_apu = _loadlib('libaprutil-1.dylib')
def _make_incomplete_ptr(name):
"Create an incomplete pointer type, referencing the given name."
cls = types.ClassType(name, (ctypes.Structure,), { })
return ctypes.POINTER(cls)
POOL_P = _make_incomplete_ptr('apr_pool_t')
CONTEXT_P = _make_incomplete_ptr('serf_context_t')
CONN_P = _make_incomplete_ptr('serf_connection_t')
REQUEST_P = _make_incomplete_ptr('serf_request_t')
BKTALLOC_P = _make_incomplete_ptr('serf_bucket_allocator_t')
STATUS = ctypes.c_int
BATON = ctypes.py_object # standard baton type: pass any Python object
class BUCKET(ctypes.Structure):
pass
BUCKET_P = ctypes.POINTER(BUCKET)
class BUCKET_TYPE(ctypes.Structure):
pass
BUCKET_TYPE_P = ctypes.POINTER(BUCKET_TYPE)
BUCKET._fields_ = [
('type', BUCKET_TYPE_P),
('data', BATON),
('allocator', BKTALLOC_P),
]
BUCKET_TYPE._fields_ = [
('name', ctypes.c_char_p),
('read', ctypes.CFUNCTYPE(STATUS, BUCKET_P, ctypes.c_int,
ctypes.POINTER(ctypes.c_char_p),
ctypes.POINTER(ctypes.c_int))),
('readline', ctypes.CFUNCTYPE(STATUS, BUCKET_P, ctypes.c_int,
ctypes.POINTER(ctypes.c_int),
ctypes.POINTER(ctypes.c_char_p),
ctypes.POINTER(ctypes.c_int))),
### needs to be fixed for Python to call/implement
('read_iovec', ctypes.CFUNCTYPE(STATUS, BUCKET_P, ctypes.c_int, ctypes.c_int,
ctypes.c_void_p, ### wrong. VECS
ctypes.POINTER(ctypes.c_int))),
### needs to be fixed for Python to call/implement
('read_for_sendfile', ctypes.CFUNCTYPE(STATUS, BUCKET_P, ctypes.c_int,
ctypes.c_void_p, ### wrong. HDTR
ctypes.c_void_p, ### wrong. FILE
ctypes.POINTER(ctypes.c_int),
ctypes.POINTER(ctypes.c_int))),
('read_bucket', ctypes.CFUNCTYPE(BUCKET_P, BUCKET_P, BUCKET_TYPE_P)),
('peek', ctypes.CFUNCTYPE(STATUS, BUCKET_P,
ctypes.POINTER(ctypes.c_char_p),
ctypes.POINTER(ctypes.c_int))),
('destroy', ctypes.CFUNCTYPE(None, BUCKET_P)),
]
class SOCKADDR(ctypes.Structure):
pass
SOCKADDR_P = ctypes.POINTER(SOCKADDR)
SOCKADDR._fields_ = [
('pool', POOL_P),
('hostname', ctypes.c_char_p),
('servname', ctypes.c_char_p),
('port', ctypes.c_int),
('family', ctypes.c_int),
('salen', ctypes.c_int),
('ipaddr_len', ctypes.c_int),
('addr_str_len', ctypes.c_int),
('ipaddr_ptr', ctypes.c_void_p), ### wrong.
('next', ctypes.POINTER(SOCKADDR)),
('sa', ctypes.c_byte * 128),
]
def _define(name, restype, *argtypes):
if name.startswith('serf_'):
f = getattr(_serf, name)
else:
f = getattr(_apr, name)
f.restype = restype
f.argtypes = argtypes
globals()[name] = f
return f
_define('apr_initialize', STATUS)
_define('apr_terminate', None)
_define('apr_pool_destroy', None, POOL_P)
ABORTFUNC_F = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
_ALLOCATOR_P = _make_incomplete_ptr('apr_allocator_t')
_NULL_ABORTFUNC = ABORTFUNC_F()
_NULL_ALLOCATOR = _ALLOCATOR_P()
apr_pool_create_ex = _define('apr_pool_create_ex', STATUS,
ctypes.POINTER(POOL_P), POOL_P,
ABORTFUNC_F, _ALLOCATOR_P)
def apr_pool_create(parent):
pool = POOL_P() # NULL pointer
status = apr_pool_create_ex(ctypes.byref(pool), parent,
_NULL_ABORTFUNC, _NULL_ALLOCATOR)
return status, pool
_apr_strerror = _define('apr_strerror', ctypes.c_char_p,
STATUS, ctypes.c_char_p, ctypes.c_int)
def apr_strerror(status):
buf = ctypes.create_string_buffer(200)
return _apr_strerror(status, buf, len(buf))
_apr_sockaddr_info_get = _define('apr_sockaddr_info_get', STATUS,
ctypes.POINTER(SOCKADDR_P),
ctypes.c_char_p,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
POOL_P)
def apr_sockaddr_info_get(hostname, family, port, flags, pool):
psa = SOCKADDR_P() # NULL pointer
status = _apr_sockaddr_info_get(ctypes.byref(psa),
hostname, family, port, flags, pool)
return status, psa
_define('serf_context_create', CONTEXT_P, POOL_P)
_define('serf_config_proxy', None, SOCKADDR_P)
_define('serf_config_authn_types', None, ctypes.c_int)
_define('serf_context_run', STATUS, CONTEXT_P, ctypes.c_int, POOL_P)
_define('serf_error_string', ctypes.c_char_p, STATUS)
_define('serf_debug__closed_conn', None, CONN_P)
_define('serf_connection_close', STATUS, CONN_P)
_define('serf_connection_set_max_outstanding_requests', None,
CONN_P, ctypes.c_uint)
_define('serf_bucket_socket_create', BUCKET_P, ctypes.c_void_p, BKTALLOC_P)
_define('serf_request_bucket_request_create', BUCKET_P,
REQUEST_P, ctypes.c_char_p, ctypes.c_char_p, BUCKET_P, BKTALLOC_P)
_define('serf_request_get_alloc', BKTALLOC_P, REQUEST_P)
_define('serf_bucket_barrier_create', BUCKET_P, BUCKET_P, BKTALLOC_P)
_define('serf_bucket_response_create', BUCKET_P, BUCKET_P, BKTALLOC_P)
_define('serf_bucket_socket_create', BUCKET_P, ctypes.c_void_p, BKTALLOC_P)
CREDENTIALS_F = ctypes.CFUNCTYPE(STATUS,
ctypes.POINTER(ctypes.c_char_p),
ctypes.POINTER(ctypes.c_char_p),
REQUEST_P, BATON,
ctypes.c_int, ctypes.c_char_p,
ctypes.c_char_p,
POOL_P)
_define('serf_config_credentials_callback', CONTEXT_P, CREDENTIALS_F)
UNFREED_FUNC_F = ctypes.CFUNCTYPE(None, BATON, ctypes.c_void_p)
_define('serf_bucket_allocator_create', BKTALLOC_P,
POOL_P, UNFREED_FUNC_F, BATON)
### serf takes an apr_uri_t struct rather than the two fields it needs :-(
class URI(ctypes.Structure):
_fields_ = [ ('scheme', ctypes.c_char_p),
('hostinfo', ctypes.c_char_p),
('user', ctypes.c_char_p),
('password', ctypes.c_char_p),
('hostname', ctypes.c_char_p),
('port_str', ctypes.c_char_p),
('path', ctypes.c_char_p),
('query', ctypes.c_char_p),
('fragment', ctypes.c_char_p),
('hostent', ctypes.c_void_p), ### wrong. struct hostent *
('port', ctypes.c_int),
('bitfield', ctypes.c_int), ### ctypes can't do bitfields.
]
CONN_SETUP_F = ctypes.CFUNCTYPE(STATUS,
ctypes.c_void_p, ### wrong. SKT.
ctypes.POINTER(BUCKET_P),
ctypes.POINTER(BUCKET_P),
BATON,
POOL_P)
CONN_CLOSED_F = ctypes.CFUNCTYPE(None, CONN_P, BATON, STATUS, POOL_P)
_define('serf_connection_create2', STATUS,
ctypes.POINTER(CONN_P),
CONTEXT_P, URI,
CONN_SETUP_F, BATON,
CONN_CLOSED_F, BATON,
POOL_P)
ACCEPTOR_F = ctypes.CFUNCTYPE(BUCKET_P, REQUEST_P, BUCKET_P, BATON, POOL_P)
HANDLER_F = ctypes.CFUNCTYPE(STATUS, REQUEST_P, BUCKET_P, BATON, POOL_P)
REQ_SETUP_F = ctypes.CFUNCTYPE(STATUS,
REQUEST_P, BATON,
ctypes.POINTER(BUCKET_P),
ctypes.POINTER(ACCEPTOR_F),
ctypes.POINTER(BATON),
ctypes.POINTER(HANDLER_F),
ctypes.POINTER(BATON),
POOL_P)
_define('serf_connection_request_create', REQUEST_P,
CONN_P, REQ_SETUP_F, BATON)