Skip to content

Commit 215f96f

Browse files
committed
add TLS Upgrade, DNS, Error Handling API
1 parent a2a2bbe commit 215f96f

File tree

2 files changed

+229
-18
lines changed

2 files changed

+229
-18
lines changed

Diff for: include/boost/python/eventloop.hpp

+41
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ class event_loop
2121
event_loop(boost::asio::io_context& ctx):
2222
_strand{ctx}, _created_time{std::chrono::steady_clock::now()}
2323
{
24+
try
25+
{
26+
_pymod_ssl = import("ssl");
27+
}
28+
catch (const error_already_set& e)
29+
{
30+
if (PyErr_ExceptionMatches(PyExc_ImportError))
31+
{
32+
PyErr_Clear();
33+
}
34+
}
2435
}
2536

2637
// TODO: An instance of asyncio.Handle is returned, which can be used later to cancel the callback.
@@ -79,9 +90,39 @@ class event_loop
7990

8091
void sock_sendfile(object sock, object file, int offset = 0, int count = 0, bool fallback = true);
8192

93+
void start_tls(object transport, object protocol, object sslcontext,
94+
bool server_side = false,
95+
object server_hostname = object(),
96+
object ssl_handshake_timeout = object());
97+
98+
object getaddrinfo(object host, int port, int family = 0, int type = 0, int proto = 0, int flags = 0);
99+
100+
object getnameinfo(object sockaddr, int flags = 0);
101+
102+
void set_exception_handler(object handler)
103+
{
104+
if (handler != object() && !PyObject_HasAttrString(handler.ptr(), "__call__")) {
105+
PyErr_SetString(PyExc_TypeError, "A callable object or None is expected");
106+
}
107+
_exception_handler = handler;
108+
}
109+
110+
object get_exception_handler()
111+
{
112+
return _exception_handler;
113+
}
114+
115+
void default_exception_handler(object context);
116+
117+
void call_exception_handler(object context);
118+
82119
private:
83120
int64_t _timer_id = 0;
121+
object _pymod_ssl = object();
84122
object _pymod_socket = import("socket");
123+
object _pymod_traceback = import("traceback");
124+
object _pymod_logger = import("asyncio.log").attr("logger");
125+
object _exception_handler = object();
85126
boost::asio::io_context::strand _strand;
86127
std::unordered_map<int, std::unique_ptr<boost::asio::steady_timer>> _id_to_timer_map;
87128
// read: key = fd * 2 + 0, write: key = fd * 2 + 1

Diff for: src/eventloop.cpp

+188-18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// 3. _ensure_fd_no_transport
1010
// 4. _ensure_resolve
1111

12+
#include <iostream>
1213
#include <boost/asio.hpp>
1314
#include <boost/bind.hpp>
1415
#include <boost/python.hpp>
@@ -53,6 +54,7 @@ void _sock_connect_cb(object pymod_socket, std::promise<void>& prom, std::future
5354
// TODO: print the address
5455
PyErr_SetString(PyExc_OSError, "Connect call failed {address}");
5556
}
57+
prom.set_value();
5658
}
5759
catch (const error_already_set& e)
5860
{
@@ -67,15 +69,10 @@ void _sock_connect_cb(object pymod_socket, std::promise<void>& prom, std::future
6769
{
6870
// raise
6971
}
70-
else if (PyErr_ExceptionMatches(PyExc_BaseException))
71-
{
72-
PyErr_Clear();
73-
prom.set_exception(std::current_exception());
74-
}
7572
else
7673
{
7774
PyErr_Clear();
78-
prom.set_value();
75+
prom.set_exception(std::current_exception());
7976
}
8077
}
8178
}
@@ -91,6 +88,7 @@ void _sock_accept(event_loop& loop, std::promise<object>& prom, std::future<obje
9188
conn = ret[0];
9289
address = ret[1];
9390
conn.attr("setblocking")(object(false));
91+
prom.set_value(make_tuple(conn, address));
9492
}
9593
catch (const error_already_set& e)
9694
{
@@ -107,19 +105,27 @@ void _sock_accept(event_loop& loop, std::promise<object>& prom, std::future<obje
107105
{
108106
// raise
109107
}
110-
else if (PyErr_ExceptionMatches(PyExc_BaseException))
111-
{
112-
PyErr_Clear();
113-
prom.set_exception(std::current_exception());
114-
}
115108
else
116109
{
117110
PyErr_Clear();
118-
prom.set_value(make_tuple(conn, address));
111+
prom.set_exception(std::current_exception());
119112
}
120113
}
121114
}
122115

116+
void _getaddrinfo_handler(object pymod_socket, std::promise<object>& prom,
117+
object host, int port, int family, int type, int proto, int flags)
118+
{
119+
object res = pymod_socket.attr("getaddrinfo")(host, port, family, type, proto, flags);
120+
prom.set_value(res);
121+
}
122+
123+
void _getnameinfo_handler(object pymod_socket, std::promise<object>& prom, object sockaddr, int flags)
124+
{
125+
object res = pymod_socket.attr("getnameinfo")(sockaddr, flags);
126+
prom.set_value(res);
127+
}
128+
123129
}
124130

125131
void event_loop::_add_reader_or_writer(int fd, object f, int key)
@@ -237,6 +243,7 @@ void event_loop::sock_connect(object sock, object address)
237243
try
238244
{
239245
sock.attr("connect")(address);
246+
prom.set_value();
240247
}
241248
catch (const error_already_set& e)
242249
{
@@ -253,15 +260,10 @@ void event_loop::sock_connect(object sock, object address)
253260
{
254261
// raise
255262
}
256-
else if (PyErr_ExceptionMatches(PyExc_BaseException))
257-
{
258-
PyErr_Clear();
259-
prom.set_exception(std::current_exception());
260-
}
261263
else
262264
{
263265
PyErr_Clear();
264-
prom.set_value();
266+
prom.set_exception(std::current_exception());
265267
}
266268
}
267269
fut.wait();
@@ -281,4 +283,172 @@ void event_loop::sock_sendfile(object sock, object file, int offset, int count,
281283
PyErr_SetString(PyExc_NotImplementedError, "Not implemented!");
282284
}
283285

286+
// TODO: implement this
287+
void event_loop::start_tls(object transport, object protocol, object sslcontext,
288+
bool server_side, object server_hostname, object ssl_handshake_timeout)
289+
{
290+
PyErr_SetString(PyExc_NotImplementedError, "Not implemented!");
291+
}
292+
293+
object event_loop::getaddrinfo(object host, int port, int family, int type, int proto, int flags)
294+
{
295+
std::promise<object> prom;
296+
std::future<object> fut = prom.get_future();
297+
call_soon(make_function(
298+
bind(_getaddrinfo_handler, _pymod_socket, boost::ref(prom), host, port, family, type, proto, flags),
299+
default_call_policies(),
300+
boost::mpl::vector<void, object>()));
301+
return fut.get();
302+
}
303+
304+
object event_loop::getnameinfo(object sockaddr, int flags)
305+
{
306+
std::promise<object> prom;
307+
std::future<object> fut = prom.get_future();
308+
call_soon(make_function(
309+
bind(_getnameinfo_handler, _pymod_socket, boost::ref(prom), sockaddr, flags),
310+
default_call_policies(),
311+
boost::mpl::vector<void, object>()));
312+
return fut.get();
313+
}
314+
315+
void event_loop::default_exception_handler(object context)
316+
{
317+
object message = context.attr("get")(str("message"));
318+
if (message == object())
319+
{
320+
message = str("Unhandled exception in event loop");
321+
}
322+
323+
object exception = context.attr("get")(str("exception"));
324+
object exc_info;
325+
if (exception != object())
326+
{
327+
exc_info = make_tuple(exception.attr("__class__"), exception, exception.attr("__traceback__"));
328+
}
329+
else
330+
{
331+
exc_info = object(false);
332+
}
333+
if (!PyObject_IsTrue(context.attr("__contains__")(str("source_traceback")).ptr()) &&
334+
_exception_handler != object() &&
335+
_exception_handler.attr("_source_traceback") != object())
336+
{
337+
context["handle_traceback"] = _exception_handler.attr("_source_traceback");
338+
}
339+
340+
list log_lines;
341+
log_lines.append(message);
342+
list context_keys(context.attr("keys"));
343+
context_keys.sort();
344+
for (int i = 0; i < len(context_keys); i++)
345+
{
346+
std::string key = extract<std::string>(context_keys[i]);
347+
if (key == "message" || key == "exception")
348+
continue;
349+
str value(context[key]);
350+
if (key == "source_traceback")
351+
{
352+
str tb = str("").join(_pymod_traceback.attr("format_list")(value));
353+
value = str("Object created at (most recent call last):\n");
354+
value += tb.rstrip();
355+
}
356+
else if (key == "handle_traceback")
357+
{
358+
str tb = str("").join(_pymod_traceback.attr("format_list")(value));
359+
value = str("Handle created at (most recent call last):\n");
360+
value += tb.rstrip();
361+
}
362+
else
363+
{
364+
value = str(value.attr("__str__")());
365+
}
366+
std::ostringstream stringStream;
367+
stringStream << key << ": " << value;
368+
log_lines.append(str(stringStream.str()));
369+
}
370+
list args;
371+
dict kwargs;
372+
args.append(str("\n").join(log_lines));
373+
kwargs["exc_info"] = exc_info;
374+
_pymod_logger.attr("error")(tuple(args), **kwargs);
375+
}
376+
377+
void event_loop::call_exception_handler(object context)
378+
{
379+
if (_exception_handler == object())
380+
{
381+
try
382+
{
383+
default_exception_handler(context);
384+
}
385+
catch (const error_already_set& e)
386+
{
387+
if (PyErr_ExceptionMatches(PyExc_SystemExit)
388+
|| PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
389+
{
390+
// raise
391+
}
392+
else
393+
{
394+
PyErr_Clear();
395+
list args;
396+
dict kwargs;
397+
args.append(str("Exception in default exception handler"));
398+
kwargs["exc_info"] = true;
399+
_pymod_logger.attr("error")(tuple(args), **kwargs);
400+
}
401+
}
402+
}
403+
else
404+
{
405+
try
406+
{
407+
_exception_handler(context);
408+
}
409+
catch (const error_already_set& e)
410+
{
411+
if (PyErr_ExceptionMatches(PyExc_SystemExit)
412+
|| PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
413+
{
414+
// raise
415+
}
416+
else
417+
{
418+
PyObject *ptype, *pvalue, *ptraceback;
419+
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
420+
PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
421+
object type(handle<>(ptype));
422+
object value(handle<>(pvalue));
423+
object traceback(handle<>(ptraceback));
424+
try
425+
{
426+
dict tmp_dict;
427+
tmp_dict["message"] = str("Unhandled error in exception handler");
428+
tmp_dict["exception"] = value;
429+
tmp_dict["context"] = context;
430+
default_exception_handler(tmp_dict);
431+
}
432+
catch (const error_already_set& e)
433+
{
434+
if (PyErr_ExceptionMatches(PyExc_SystemExit)
435+
|| PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
436+
{
437+
// raise
438+
}
439+
else
440+
{
441+
boost::python::list args;
442+
boost::python::dict kwargs;
443+
args.append(str("Exception in default exception handler"));
444+
kwargs["exc_info"] = true;
445+
_pymod_logger.attr("error")(tuple(args), **kwargs);
446+
}
447+
}
448+
}
449+
}
450+
}
451+
}
452+
453+
284454
}}}

0 commit comments

Comments
 (0)