mirror of https://github.com/grpc/grpc.git
Because some cpp code ends up leaking into cython, we change the cython generator to generate cpp code.pull/14561/head
parent
0bb2fe946e
commit
1bfff8eec0
20 changed files with 881 additions and 80 deletions
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed 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 GRPC_CORE_LIB_IOMGR_GEVENT_UTIL_H |
||||
#define GRPC_CORE_LIB_IOMGR_GEVENT_UTIL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/impl/codegen/slice.h> |
||||
#include <grpc/status.h> |
||||
#include "src/core/lib/iomgr/error.h" |
||||
|
||||
// These are only used by the gRPC Python extension for gevent
|
||||
// support. They are easier to define here (rather than in Cython)
|
||||
// because Cython doesn't handle #defines well.
|
||||
|
||||
grpc_error* grpc_socket_error(char* error) { |
||||
return grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error), |
||||
GRPC_ERROR_INT_GRPC_STATUS, |
||||
GRPC_STATUS_UNAVAILABLE); |
||||
} |
||||
|
||||
char* grpc_slice_buffer_start(grpc_slice_buffer* buffer, int i) { |
||||
return (char*)GRPC_SLICE_START_PTR(buffer->slices[i]); |
||||
} |
||||
|
||||
int grpc_slice_buffer_length(grpc_slice_buffer* buffer, int i) { |
||||
return GRPC_SLICE_LENGTH(buffer->slices[i]); |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,154 @@ |
||||
# Copyright 2017 gRPC authors. |
||||
# |
||||
# Licensed 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. |
||||
# distutils: language=c++ |
||||
|
||||
from libc.stdint cimport uint32_t |
||||
|
||||
cdef extern from "grpc/impl/codegen/slice.h": |
||||
struct grpc_slice_buffer: |
||||
int count |
||||
|
||||
cdef extern from "src/core/lib/iomgr/error.h": |
||||
struct grpc_error: |
||||
pass |
||||
|
||||
cdef extern from "src/core/lib/iomgr/gevent_util.h": |
||||
grpc_error* grpc_socket_error(char* error) |
||||
char* grpc_slice_buffer_start(grpc_slice_buffer* buffer, int i) |
||||
int grpc_slice_buffer_length(grpc_slice_buffer* buffer, int i) |
||||
|
||||
cdef extern from "src/core/lib/iomgr/sockaddr.h": |
||||
ctypedef struct grpc_sockaddr: |
||||
pass |
||||
|
||||
cdef extern from "src/core/lib/iomgr/resolve_address.h": |
||||
ctypedef struct grpc_resolved_addresses: |
||||
size_t naddrs |
||||
grpc_resolved_address* addrs |
||||
|
||||
ctypedef struct grpc_resolved_address: |
||||
char[128] addr |
||||
size_t len |
||||
|
||||
cdef extern from "src/core/lib/iomgr/resolve_address_custom.h": |
||||
struct grpc_custom_resolver: |
||||
pass |
||||
|
||||
struct grpc_custom_resolver_vtable: |
||||
grpc_error* (*resolve)(char* host, char* port, grpc_resolved_addresses** res); |
||||
void (*resolve_async)(grpc_custom_resolver* resolver, char* host, char* port); |
||||
|
||||
void grpc_custom_resolve_callback(grpc_custom_resolver* resolver, |
||||
grpc_resolved_addresses* result, |
||||
grpc_error* error); |
||||
|
||||
cdef extern from "src/core/lib/iomgr/tcp_custom.h": |
||||
struct grpc_custom_socket: |
||||
void* impl |
||||
# We don't care about the rest of the fields |
||||
ctypedef void (*grpc_custom_connect_callback)(grpc_custom_socket* socket, |
||||
grpc_error* error) |
||||
ctypedef void (*grpc_custom_write_callback)(grpc_custom_socket* socket, |
||||
grpc_error* error) |
||||
ctypedef void (*grpc_custom_read_callback)(grpc_custom_socket* socket, |
||||
size_t nread, grpc_error* error) |
||||
ctypedef void (*grpc_custom_accept_callback)(grpc_custom_socket* socket, |
||||
grpc_custom_socket* client, |
||||
grpc_error* error) |
||||
ctypedef void (*grpc_custom_close_callback)(grpc_custom_socket* socket) |
||||
|
||||
struct grpc_socket_vtable: |
||||
grpc_error* (*init)(grpc_custom_socket* socket, int domain); |
||||
void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr, |
||||
size_t len, grpc_custom_connect_callback cb); |
||||
void (*destroy)(grpc_custom_socket* socket); |
||||
void (*shutdown)(grpc_custom_socket* socket); |
||||
void (*close)(grpc_custom_socket* socket, grpc_custom_close_callback cb); |
||||
void (*write)(grpc_custom_socket* socket, grpc_slice_buffer* slices, |
||||
grpc_custom_write_callback cb); |
||||
void (*read)(grpc_custom_socket* socket, char* buffer, size_t length, |
||||
grpc_custom_read_callback cb); |
||||
grpc_error* (*getpeername)(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, int* len); |
||||
grpc_error* (*getsockname)(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, int* len); |
||||
grpc_error* (*setsockopt)(grpc_custom_socket* socket, int level, int optname, |
||||
const void* optval, uint32_t len); |
||||
grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr, |
||||
size_t len, int flags); |
||||
grpc_error* (*listen)(grpc_custom_socket* socket); |
||||
void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client, |
||||
grpc_custom_accept_callback cb); |
||||
|
||||
cdef extern from "src/core/lib/iomgr/timer_custom.h": |
||||
struct grpc_custom_timer: |
||||
void* timer |
||||
int timeout_ms |
||||
# We don't care about the rest of the fields |
||||
|
||||
struct grpc_custom_timer_vtable: |
||||
void (*start)(grpc_custom_timer* t); |
||||
void (*stop)(grpc_custom_timer* t); |
||||
|
||||
void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error); |
||||
|
||||
cdef extern from "src/core/lib/iomgr/pollset_custom.h": |
||||
struct grpc_custom_poller_vtable: |
||||
void (*init)() |
||||
void (*poll)(size_t timeout_ms) |
||||
void (*kick)() |
||||
void (*shutdown)() |
||||
|
||||
cdef extern from "src/core/lib/iomgr/iomgr_custom.h": |
||||
void grpc_custom_iomgr_init(grpc_socket_vtable* socket, |
||||
grpc_custom_resolver_vtable* resolver, |
||||
grpc_custom_timer_vtable* timer, |
||||
grpc_custom_poller_vtable* poller); |
||||
|
||||
cdef extern from "src/core/lib/iomgr/sockaddr_utils.h": |
||||
int grpc_sockaddr_get_port(const grpc_resolved_address *addr); |
||||
int grpc_sockaddr_to_string(char **out, const grpc_resolved_address *addr, |
||||
int normalize); |
||||
void grpc_string_to_sockaddr(grpc_resolved_address *out, char* addr, int port); |
||||
int grpc_sockaddr_set_port(const grpc_resolved_address *resolved_addr, |
||||
int port) |
||||
const char* grpc_sockaddr_get_uri_scheme(const grpc_resolved_address* resolved_addr) |
||||
|
||||
|
||||
cdef class TimerWrapper: |
||||
|
||||
cdef grpc_custom_timer *c_timer |
||||
cdef object timer |
||||
cdef object event |
||||
|
||||
cdef class SocketWrapper: |
||||
cdef object sockopts |
||||
cdef object socket |
||||
cdef object closed |
||||
cdef grpc_custom_socket *c_socket |
||||
cdef char* c_buffer |
||||
cdef size_t len |
||||
cdef grpc_custom_socket *accepting_socket |
||||
|
||||
cdef grpc_custom_connect_callback connect_cb |
||||
cdef grpc_custom_write_callback write_cb |
||||
cdef grpc_custom_read_callback read_cb |
||||
cdef grpc_custom_accept_callback accept_cb |
||||
cdef grpc_custom_close_callback close_cb |
||||
|
||||
|
||||
cdef class ResolveWrapper: |
||||
cdef grpc_custom_resolver *c_resolver |
||||
cdef char* c_host |
||||
cdef char* c_port |
@ -0,0 +1,454 @@ |
||||
# Copyright 2018 gRPC authors. |
||||
# |
||||
# Licensed 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. |
||||
# distutils: language=c++ |
||||
|
||||
cimport cpython |
||||
from libc cimport string |
||||
from libc.stdlib cimport malloc, free |
||||
import errno |
||||
gevent_g = None |
||||
gevent_socket = None |
||||
gevent_hub = None |
||||
gevent_event = None |
||||
g_event = None |
||||
g_pool = None |
||||
|
||||
cdef grpc_error* grpc_error_none(): |
||||
return <grpc_error*>0 |
||||
|
||||
cdef grpc_error* socket_error(str syscall, str err): |
||||
error_str = "{} failed: {}".format(syscall, err) |
||||
error_bytes = str_to_bytes(error_str) |
||||
return grpc_socket_error(error_bytes) |
||||
|
||||
cdef resolved_addr_to_tuple(grpc_resolved_address* address): |
||||
cdef char* res_str |
||||
port = grpc_sockaddr_get_port(address) |
||||
str_len = grpc_sockaddr_to_string(&res_str, address, 0) |
||||
byte_str = _decode(<bytes>res_str[:str_len]) |
||||
if byte_str.endswith(':' + str(port)): |
||||
byte_str = byte_str[:(0 - len(str(port)) - 1)] |
||||
byte_str = byte_str.lstrip('[') |
||||
byte_str = byte_str.rstrip(']') |
||||
byte_str = '{}'.format(byte_str) |
||||
return byte_str, port |
||||
|
||||
cdef sockaddr_to_tuple(const grpc_sockaddr* address, size_t length): |
||||
cdef grpc_resolved_address c_addr |
||||
string.memcpy(<void*>c_addr.addr, <void*> address, length) |
||||
c_addr.len = length |
||||
return resolved_addr_to_tuple(&c_addr) |
||||
|
||||
cdef sockaddr_is_ipv4(const grpc_sockaddr* address, size_t length): |
||||
cdef grpc_resolved_address c_addr |
||||
string.memcpy(<void*>c_addr.addr, <void*> address, length) |
||||
c_addr.len = length |
||||
return grpc_sockaddr_get_uri_scheme(&c_addr) == b'ipv4' |
||||
|
||||
cdef grpc_resolved_addresses* tuples_to_resolvaddr(tups): |
||||
cdef grpc_resolved_addresses* addresses |
||||
tups_set = set((tup[4][0], tup[4][1]) for tup in tups) |
||||
addresses = <grpc_resolved_addresses*> malloc(sizeof(grpc_resolved_addresses)) |
||||
addresses.naddrs = len(tups_set) |
||||
addresses.addrs = <grpc_resolved_address*> malloc(sizeof(grpc_resolved_address) * len(tups_set)) |
||||
i = 0 |
||||
for tup in set(tups_set): |
||||
hostname = str_to_bytes(tup[0]) |
||||
grpc_string_to_sockaddr(&addresses.addrs[i], hostname, tup[1]) |
||||
i += 1 |
||||
return addresses |
||||
|
||||
def _spawn_greenlet(*args): |
||||
greenlet = g_pool.spawn(*args) |
||||
|
||||
############################### |
||||
### socket implementation ### |
||||
############################### |
||||
|
||||
cdef class SocketWrapper: |
||||
def __cinit__(self): |
||||
self.sockopts = [] |
||||
self.socket = None |
||||
self.c_socket = NULL |
||||
self.c_buffer = NULL |
||||
self.len = 0 |
||||
|
||||
cdef grpc_error* socket_init(grpc_custom_socket* socket, int domain) with gil: |
||||
sw = SocketWrapper() |
||||
sw.c_socket = socket |
||||
sw.sockopts = [] |
||||
cpython.Py_INCREF(sw) |
||||
# Python doesn't support AF_UNSPEC sockets, so we defer creation until |
||||
# bind/connect when we know what type of socket we need |
||||
sw.socket = None |
||||
sw.closed = False |
||||
sw.accepting_socket = NULL |
||||
socket.impl = <void*>sw |
||||
return grpc_error_none() |
||||
|
||||
cdef socket_connect_async_cython(SocketWrapper socket_wrapper, addr_tuple): |
||||
try: |
||||
socket_wrapper.socket.connect(addr_tuple) |
||||
socket_wrapper.connect_cb(<grpc_custom_socket*>socket_wrapper.c_socket, |
||||
grpc_error_none()) |
||||
except IOError as io_error: |
||||
socket_wrapper.connect_cb(<grpc_custom_socket*>socket_wrapper.c_socket, |
||||
socket_error("connect", str(io_error))) |
||||
g_event.set() |
||||
|
||||
def socket_connect_async(socket_wrapper, addr_tuple): |
||||
socket_connect_async_cython(socket_wrapper, addr_tuple) |
||||
|
||||
cdef void socket_connect(grpc_custom_socket* socket, const grpc_sockaddr* addr, |
||||
size_t addr_len, |
||||
grpc_custom_connect_callback cb) with gil: |
||||
py_socket = None |
||||
socket_wrapper = <SocketWrapper>socket.impl |
||||
socket_wrapper.connect_cb = cb |
||||
addr_tuple = sockaddr_to_tuple(addr, addr_len) |
||||
if sockaddr_is_ipv4(addr, addr_len): |
||||
py_socket = gevent_socket.socket(gevent_socket.AF_INET) |
||||
else: |
||||
py_socket = gevent_socket.socket(gevent_socket.AF_INET6) |
||||
applysockopts(py_socket) |
||||
socket_wrapper.socket = py_socket |
||||
_spawn_greenlet(socket_connect_async, socket_wrapper, addr_tuple) |
||||
|
||||
cdef void socket_destroy(grpc_custom_socket* socket) with gil: |
||||
cpython.Py_DECREF(<SocketWrapper>socket.impl) |
||||
|
||||
cdef void socket_shutdown(grpc_custom_socket* socket) with gil: |
||||
try: |
||||
(<SocketWrapper>socket.impl).socket.shutdown(gevent_socket.SHUT_RDWR) |
||||
except IOError as io_error: |
||||
if io_error.errno != errno.ENOTCONN: |
||||
raise io_error |
||||
|
||||
cdef void socket_close(grpc_custom_socket* socket, |
||||
grpc_custom_close_callback cb) with gil: |
||||
socket_wrapper = (<SocketWrapper>socket.impl) |
||||
if socket_wrapper.socket is not None: |
||||
socket_wrapper.socket.close() |
||||
socket_wrapper.closed = True |
||||
socket_wrapper.close_cb = cb |
||||
# Delay the close callback until the accept() call has picked it up |
||||
if socket_wrapper.accepting_socket != NULL: |
||||
return |
||||
socket_wrapper.close_cb(socket) |
||||
|
||||
def socket_sendmsg(socket, write_bytes): |
||||
try: |
||||
return socket.sendmsg(write_bytes) |
||||
except AttributeError: |
||||
# sendmsg not available on all Pythons/Platforms |
||||
return socket.send(b''.join(write_bytes)) |
||||
|
||||
cdef socket_write_async_cython(SocketWrapper socket_wrapper, write_bytes): |
||||
try: |
||||
while write_bytes: |
||||
sent_byte_count = socket_sendmsg(socket_wrapper.socket, write_bytes) |
||||
while sent_byte_count > 0: |
||||
if sent_byte_count < len(write_bytes[0]): |
||||
write_bytes[0] = write_bytes[0][sent_byte_count:] |
||||
sent_byte_count = 0 |
||||
else: |
||||
sent_byte_count -= len(write_bytes[0]) |
||||
write_bytes = write_bytes[1:] |
||||
socket_wrapper.write_cb(<grpc_custom_socket*>socket_wrapper.c_socket, |
||||
grpc_error_none()) |
||||
except IOError as io_error: |
||||
socket_wrapper.write_cb(<grpc_custom_socket*>socket_wrapper.c_socket, |
||||
socket_error("send", str(io_error))) |
||||
g_event.set() |
||||
|
||||
def socket_write_async(socket_wrapper, write_bytes): |
||||
socket_write_async_cython(socket_wrapper, write_bytes) |
||||
|
||||
cdef void socket_write(grpc_custom_socket* socket, grpc_slice_buffer* buffer, |
||||
grpc_custom_write_callback cb) with gil: |
||||
cdef char* start |
||||
sw = <SocketWrapper>socket.impl |
||||
sw.write_cb = cb |
||||
write_bytes = [] |
||||
for i in range(buffer.count): |
||||
start = grpc_slice_buffer_start(buffer, i) |
||||
length = grpc_slice_buffer_length(buffer, i) |
||||
write_bytes.append(<bytes>start[:length]) |
||||
_spawn_greenlet(socket_write_async, <SocketWrapper>socket.impl, write_bytes) |
||||
|
||||
cdef socket_read_async_cython(SocketWrapper socket_wrapper): |
||||
cdef char* buff_char_arr |
||||
try: |
||||
buff_str = socket_wrapper.socket.recv(socket_wrapper.len) |
||||
buff_char_arr = buff_str |
||||
string.memcpy(<void*>socket_wrapper.c_buffer, buff_char_arr, len(buff_str)) |
||||
socket_wrapper.read_cb(<grpc_custom_socket*>socket_wrapper.c_socket, |
||||
len(buff_str), grpc_error_none()) |
||||
except IOError as io_error: |
||||
socket_wrapper.read_cb(<grpc_custom_socket*>socket_wrapper.c_socket, |
||||
-1, socket_error("recv", str(io_error))) |
||||
g_event.set() |
||||
|
||||
def socket_read_async(socket_wrapper): |
||||
socket_read_async_cython(socket_wrapper) |
||||
|
||||
cdef void socket_read(grpc_custom_socket* socket, char* buffer, |
||||
size_t length, grpc_custom_read_callback cb) with gil: |
||||
sw = <SocketWrapper>socket.impl |
||||
sw.read_cb = cb |
||||
sw.c_buffer = buffer |
||||
sw.len = length |
||||
_spawn_greenlet(socket_read_async, sw) |
||||
|
||||
cdef grpc_error* socket_getpeername(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, |
||||
int* length) with gil: |
||||
cdef char* src_buf |
||||
peer = (<SocketWrapper>socket.impl).socket.getpeername() |
||||
|
||||
cdef grpc_resolved_address c_addr |
||||
hostname = str_to_bytes(peer[0]) |
||||
grpc_string_to_sockaddr(&c_addr, hostname, peer[1]) |
||||
string.memcpy(<void*>addr, <void*>c_addr.addr, c_addr.len) |
||||
length[0] = c_addr.len |
||||
return grpc_error_none() |
||||
|
||||
cdef grpc_error* socket_getsockname(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, |
||||
int* length) with gil: |
||||
cdef char* src_buf |
||||
cdef grpc_resolved_address c_addr |
||||
if (<SocketWrapper>socket.impl).socket is None: |
||||
peer = ('0.0.0.0', 0) |
||||
else: |
||||
peer = (<SocketWrapper>socket.impl).socket.getsockname() |
||||
hostname = str_to_bytes(peer[0]) |
||||
grpc_string_to_sockaddr(&c_addr, hostname, peer[1]) |
||||
string.memcpy(<void*>addr, <void*>c_addr.addr, c_addr.len) |
||||
length[0] = c_addr.len |
||||
return grpc_error_none() |
||||
|
||||
cdef grpc_error* socket_setsockopt(grpc_custom_socket* socket, int level, int optname, |
||||
const void *optval, uint32_t optlen) with gil: |
||||
# No-op; we provide a default set of options |
||||
return grpc_error_none() |
||||
|
||||
def applysockopts(s): |
||||
s.setsockopt(gevent_socket.SOL_SOCKET, gevent_socket.SO_REUSEADDR, 1) |
||||
s.setsockopt(gevent_socket.IPPROTO_TCP, gevent_socket.TCP_NODELAY, True) |
||||
|
||||
cdef grpc_error* socket_bind(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, |
||||
size_t len, int flags) with gil: |
||||
addr_tuple = sockaddr_to_tuple(addr, len) |
||||
try: |
||||
try: |
||||
py_socket = gevent_socket.socket(gevent_socket.AF_INET) |
||||
applysockopts(py_socket) |
||||
py_socket.bind(addr_tuple) |
||||
except gevent_socket.gaierror as e: |
||||
py_socket = gevent_socket.socket(gevent_socket.AF_INET6) |
||||
applysockopts(py_socket) |
||||
py_socket.bind(addr_tuple) |
||||
(<SocketWrapper>socket.impl).socket = py_socket |
||||
except IOError as io_error: |
||||
return socket_error("bind", str(io_error)) |
||||
else: |
||||
return grpc_error_none() |
||||
|
||||
cdef grpc_error* socket_listen(grpc_custom_socket* socket) with gil: |
||||
(<SocketWrapper>socket.impl).socket.listen(50) |
||||
return grpc_error_none() |
||||
|
||||
cdef void accept_callback_cython(SocketWrapper s): |
||||
try: |
||||
conn, address = s.socket.accept() |
||||
sw = SocketWrapper() |
||||
sw.closed = False |
||||
sw.c_socket = s.accepting_socket |
||||
sw.sockopts = [] |
||||
sw.socket = conn |
||||
sw.c_socket.impl = <void*>sw |
||||
sw.accepting_socket = NULL |
||||
cpython.Py_INCREF(sw) |
||||
s.accepting_socket = NULL |
||||
s.accept_cb(<grpc_custom_socket*>s.c_socket, sw.c_socket, grpc_error_none()) |
||||
except IOError as io_error: |
||||
#TODO actual error |
||||
s.accepting_socket = NULL |
||||
s.accept_cb(<grpc_custom_socket*>s.c_socket, s.accepting_socket, |
||||
socket_error("accept", str(io_error))) |
||||
if s.closed: |
||||
s.close_cb(<grpc_custom_socket*>s.c_socket) |
||||
g_event.set() |
||||
|
||||
def socket_accept_async(s): |
||||
accept_callback_cython(s) |
||||
|
||||
cdef void socket_accept(grpc_custom_socket* socket, grpc_custom_socket* client, |
||||
grpc_custom_accept_callback cb) with gil: |
||||
sw = <SocketWrapper>socket.impl |
||||
sw.accepting_socket = client |
||||
sw.accept_cb = cb |
||||
_spawn_greenlet(socket_accept_async, sw) |
||||
|
||||
##################################### |
||||
######Resolver implementation ####### |
||||
##################################### |
||||
|
||||
cdef class ResolveWrapper: |
||||
def __cinit__(self): |
||||
self.c_resolver = NULL |
||||
self.c_host = NULL |
||||
self.c_port = NULL |
||||
|
||||
cdef socket_resolve_async_cython(ResolveWrapper resolve_wrapper): |
||||
try: |
||||
res = gevent_socket.getaddrinfo(resolve_wrapper.c_host, resolve_wrapper.c_port) |
||||
grpc_custom_resolve_callback(<grpc_custom_resolver*>resolve_wrapper.c_resolver, |
||||
tuples_to_resolvaddr(res), grpc_error_none()) |
||||
except IOError as io_error: |
||||
grpc_custom_resolve_callback(<grpc_custom_resolver*>resolve_wrapper.c_resolver, |
||||
<grpc_resolved_addresses*>0, |
||||
socket_error("getaddrinfo", str(io_error))) |
||||
g_event.set() |
||||
|
||||
def socket_resolve_async_python(resolve_wrapper): |
||||
socket_resolve_async_cython(resolve_wrapper) |
||||
|
||||
cdef void socket_resolve_async(grpc_custom_resolver* r, char* host, char* port) with gil: |
||||
rw = ResolveWrapper() |
||||
rw.c_resolver = r |
||||
rw.c_host = host |
||||
rw.c_port = port |
||||
_spawn_greenlet(socket_resolve_async_python, rw) |
||||
|
||||
cdef grpc_error* socket_resolve(char* host, char* port, |
||||
grpc_resolved_addresses** res) with gil: |
||||
try: |
||||
result = gevent_socket.getaddrinfo(host, port) |
||||
res[0] = tuples_to_resolvaddr(result) |
||||
return grpc_error_none() |
||||
except IOError as io_error: |
||||
return socket_error("getaddrinfo", str(io_error)) |
||||
|
||||
############################### |
||||
### timer implementation ###### |
||||
############################### |
||||
|
||||
cdef class TimerWrapper: |
||||
def __cinit__(self, deadline): |
||||
self.timer = gevent_hub.get_hub().loop.timer(deadline) |
||||
self.event = None |
||||
|
||||
def start(self): |
||||
self.event = gevent_event.Event() |
||||
self.timer.start(self.on_finish) |
||||
|
||||
def on_finish(self): |
||||
grpc_custom_timer_callback(self.c_timer, grpc_error_none()) |
||||
self.timer.stop() |
||||
g_event.set() |
||||
|
||||
def stop(self): |
||||
self.event.set() |
||||
self.timer.stop() |
||||
|
||||
cdef void timer_start(grpc_custom_timer* t) with gil: |
||||
timer = TimerWrapper(t.timeout_ms / 1000.0) |
||||
timer.c_timer = t |
||||
t.timer = <void*>timer |
||||
timer.start() |
||||
|
||||
cdef void timer_stop(grpc_custom_timer* t) with gil: |
||||
time_wrapper = <object>t.timer |
||||
time_wrapper.stop() |
||||
|
||||
############################### |
||||
### pollset implementation ### |
||||
############################### |
||||
|
||||
cdef void init_loop() with gil: |
||||
pass |
||||
|
||||
cdef void destroy_loop() with gil: |
||||
g_pool.join() |
||||
|
||||
cdef void kick_loop() with gil: |
||||
g_event.set() |
||||
|
||||
cdef void run_loop(size_t timeout_ms) with gil: |
||||
timeout = timeout_ms / 1000.0 |
||||
if timeout_ms > 0: |
||||
g_event.wait(timeout) |
||||
g_event.clear() |
||||
|
||||
############################### |
||||
### Initializer ############### |
||||
############################### |
||||
|
||||
cdef grpc_socket_vtable gevent_socket_vtable |
||||
cdef grpc_custom_resolver_vtable gevent_resolver_vtable |
||||
cdef grpc_custom_timer_vtable gevent_timer_vtable |
||||
cdef grpc_custom_poller_vtable gevent_pollset_vtable |
||||
|
||||
def init_grpc_gevent(): |
||||
# Lazily import gevent |
||||
global gevent_socket |
||||
global gevent_g |
||||
global gevent_hub |
||||
global gevent_event |
||||
global g_event |
||||
global g_pool |
||||
import gevent |
||||
gevent_g = gevent |
||||
import gevent.socket |
||||
gevent_socket = gevent.socket |
||||
import gevent.hub |
||||
gevent_hub = gevent.hub |
||||
import gevent.event |
||||
gevent_event = gevent.event |
||||
import gevent.pool |
||||
|
||||
g_event = gevent.event.Event() |
||||
g_pool = gevent.pool.Group() |
||||
gevent_resolver_vtable.resolve = socket_resolve |
||||
gevent_resolver_vtable.resolve_async = socket_resolve_async |
||||
|
||||
gevent_socket_vtable.init = socket_init |
||||
gevent_socket_vtable.connect = socket_connect |
||||
gevent_socket_vtable.destroy = socket_destroy |
||||
gevent_socket_vtable.shutdown = socket_shutdown |
||||
gevent_socket_vtable.close = socket_close |
||||
gevent_socket_vtable.write = socket_write |
||||
gevent_socket_vtable.read = socket_read |
||||
gevent_socket_vtable.getpeername = socket_getpeername |
||||
gevent_socket_vtable.getsockname = socket_getsockname |
||||
gevent_socket_vtable.setsockopt = socket_setsockopt |
||||
gevent_socket_vtable.bind = socket_bind |
||||
gevent_socket_vtable.listen = socket_listen |
||||
gevent_socket_vtable.accept = socket_accept |
||||
|
||||
gevent_timer_vtable.start = timer_start |
||||
gevent_timer_vtable.stop = timer_stop |
||||
|
||||
gevent_pollset_vtable.init = init_loop |
||||
gevent_pollset_vtable.poll = run_loop |
||||
gevent_pollset_vtable.kick = kick_loop |
||||
gevent_pollset_vtable.shutdown = destroy_loop |
||||
|
||||
grpc_custom_iomgr_init(&gevent_socket_vtable, |
||||
&gevent_resolver_vtable, |
||||
&gevent_timer_vtable, |
||||
&gevent_pollset_vtable) |
@ -0,0 +1,17 @@ |
||||
# Copyright 2018 gRPC authors. |
||||
# |
||||
# Licensed 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. |
||||
"""gRPC's experimental APIs. |
||||
|
||||
These APIs are subject to be removed during any minor version release. |
||||
""" |
@ -0,0 +1,27 @@ |
||||
# Copyright 2018 gRPC authors. |
||||
# |
||||
# Licensed 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. |
||||
"""gRPC's Python gEvent APIs.""" |
||||
|
||||
from grpc._cython import cygrpc as _cygrpc |
||||
|
||||
|
||||
def init_gevent(): |
||||
"""Patches gRPC's libraries to be compatible with gevent. |
||||
|
||||
This must be called AFTER the python standard lib has been patched, |
||||
but BEFORE creating and gRPC objects. |
||||
|
||||
In order for progress to be made, the application must drive the event loop. |
||||
""" |
||||
_cygrpc.init_grpc_gevent() |
Loading…
Reference in new issue