mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-28 11:40:11 +03:00
first-line work on SSLifying the HTTP client
doesn't work at all, because the encrypted buffer never gets written to the net
This commit is contained in:
parent
0d0d6e468a
commit
65aba238a8
6
Makefile
6
Makefile
@ -43,14 +43,14 @@ ifeq ($(OS),osx)
|
|||||||
OSLIBS=-framework CoreServices -framework CoreFoundation
|
OSLIBS=-framework CoreServices -framework CoreFoundation
|
||||||
endif
|
endif
|
||||||
ifeq ($(OS),linux)
|
ifeq ($(OS),linux)
|
||||||
OSLIBS=-lcrypto -lpthread -lrt -lcurses
|
OSLIBS=-lpthread -lrt -lcurses
|
||||||
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
|
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
|
||||||
endif
|
endif
|
||||||
ifeq ($(OS),bsd)
|
ifeq ($(OS),bsd)
|
||||||
OSLIBS=-lcrypto -lpthread -lncurses -lkvm
|
OSLIBS=-lpthread -lncurses -lkvm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBS=-lgmp -lncurses -lsigsegv $(OSLIBS)
|
LIBS=-lssl -lcrypto -lgmp -lncurses -lsigsegv $(OSLIBS)
|
||||||
|
|
||||||
INCLUDE=include
|
INCLUDE=include
|
||||||
GENERATED=generated
|
GENERATED=generated
|
||||||
|
@ -44,7 +44,9 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
u2_csat_dead = 0, // connection dead
|
u2_csat_dead = 0, // connection dead
|
||||||
u2_csat_addr = 1, // connection addressed
|
u2_csat_addr = 1, // connection addressed
|
||||||
u2_csat_live = 2, // connection open
|
u2_csat_clyr = 2, // connection open in cleartext
|
||||||
|
u2_csat_shak = 3, // connection handshaking ssl
|
||||||
|
u2_csat_cryp = 4, // connection open and crypted
|
||||||
} u2_csat;
|
} u2_csat;
|
||||||
|
|
||||||
/* u2_hmet: http method. Matches jhttp encoding.
|
/* u2_hmet: http method. Matches jhttp encoding.
|
||||||
@ -139,12 +141,21 @@
|
|||||||
struct _u2_creq* nex_u; // next in queue
|
struct _u2_creq* nex_u; // next in queue
|
||||||
} u2_creq;
|
} u2_creq;
|
||||||
|
|
||||||
|
/* u2_sslx: per-connection ssl context.
|
||||||
|
*/
|
||||||
|
typedef struct _u2_sslx {
|
||||||
|
void* ssl_u; // struct SSL*
|
||||||
|
void* rio_u; // struct BIO* for read
|
||||||
|
void* wio_u; // struct BIO* for write
|
||||||
|
} u2_sslx;
|
||||||
|
|
||||||
/* u2_ccon: outgoing http connection.
|
/* u2_ccon: outgoing http connection.
|
||||||
*/
|
*/
|
||||||
typedef struct _u2_ccon { // client connection
|
typedef struct _u2_ccon { // client connection
|
||||||
uv_tcp_t wax_u; // i/o handler state
|
uv_tcp_t wax_u; // i/o handler state
|
||||||
uv_connect_t cot_u; // connection handler state
|
uv_connect_t cot_u; // connection handler state
|
||||||
uv_getaddrinfo_t adr_u; // resolver state
|
uv_getaddrinfo_t adr_u; // resolver state
|
||||||
|
u2_sslx ssl; // ssl state
|
||||||
u2_csat sat_e; // connection state
|
u2_csat sat_e; // connection state
|
||||||
c3_c* hot_c; // hostname
|
c3_c* hot_c; // hostname
|
||||||
c3_s por_s; // port
|
c3_s por_s; // port
|
||||||
@ -532,12 +543,14 @@
|
|||||||
u2_unix unx_u; // sync and clay
|
u2_unix unx_u; // sync and clay
|
||||||
u2_batz beh_u; // batz timer
|
u2_batz beh_u; // batz timer
|
||||||
u2_bean liv; // if u2_no, shut down
|
u2_bean liv; // if u2_no, shut down
|
||||||
|
void* ssl_u; // struct SSL_CTX*
|
||||||
|
|
||||||
u2_reck* arv_u; // runtime
|
u2_reck* arv_u; // runtime
|
||||||
} u2_host; // host == computer == process
|
} u2_host; // host == computer == process
|
||||||
|
|
||||||
# define u2L u2_Host.lup_u // global event loop
|
# define u2L u2_Host.lup_u // global event loop
|
||||||
# define u2R (&(u2_Raft))
|
# define u2R (&(u2_Raft))
|
||||||
|
# define u2S u2_Host.ssl_u
|
||||||
|
|
||||||
/* u2_funk: standard system function.
|
/* u2_funk: standard system function.
|
||||||
*/
|
*/
|
||||||
|
208
v/cttp.c
208
v/cttp.c
@ -19,10 +19,19 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <term.h>
|
#include <term.h>
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
#include "../outside/jhttp/http_parser.h" // Joyent HTTP
|
#include "../outside/jhttp/http_parser.h" // Joyent HTTP
|
||||||
#include "all.h"
|
#include "all.h"
|
||||||
#include "v/vere.h"
|
#include "v/vere.h"
|
||||||
|
|
||||||
|
#ifdef U2_OS_osx
|
||||||
|
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Forward declarations.
|
/* Forward declarations.
|
||||||
*/
|
*/
|
||||||
static void _cttp_ccon_kick(u2_ccon* coc_u);
|
static void _cttp_ccon_kick(u2_ccon* coc_u);
|
||||||
@ -720,6 +729,9 @@ _cttp_ccon_waste(u2_ccon* coc_u, c3_c* msg_c)
|
|||||||
if ( coc_u->nex_u ) {
|
if ( coc_u->nex_u ) {
|
||||||
coc_u->nex_u->pre_u = coc_u->pre_u;
|
coc_u->nex_u->pre_u = coc_u->pre_u;
|
||||||
}
|
}
|
||||||
|
if ( coc_u->ssl.ssl_u ) {
|
||||||
|
SSL_free(coc_u->ssl.ssl_u);
|
||||||
|
}
|
||||||
free(coc_u);
|
free(coc_u);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,7 +774,13 @@ _cttp_ccon_reboot(u2_ccon* coc_u)
|
|||||||
_cttp_ccon_waste(coc_u, "connection failed");
|
_cttp_ccon_waste(coc_u, "connection failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case u2_csat_live: {
|
case u2_csat_shak: {
|
||||||
|
/* Got a connection, but SSL failed. Waste it.
|
||||||
|
*/
|
||||||
|
_cttp_ccon_waste(coc_u, "ssl handshake failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case u2_csat_clyr: {
|
||||||
/* We had a connection but it broke. Either there are no
|
/* We had a connection but it broke. Either there are no
|
||||||
** living requests, in which case waste; otherwise reset.
|
** living requests, in which case waste; otherwise reset.
|
||||||
*/
|
*/
|
||||||
@ -803,7 +821,7 @@ _cttp_ccon_fail(u2_ccon* coc_u, u2_bean say)
|
|||||||
uL(fprintf(uH, "cttp: %s\n", uv_strerror(uv_last_error(u2L))));
|
uL(fprintf(uH, "cttp: %s\n", uv_strerror(uv_last_error(u2L))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( coc_u->sat_e != u2_csat_live ) {
|
if ( coc_u->sat_e < u2_csat_shak ) {
|
||||||
_cttp_ccon_reboot(coc_u);
|
_cttp_ccon_reboot(coc_u);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -872,7 +890,9 @@ _cttp_ccon_kick_connect_cb(uv_connect_t* cot_u,
|
|||||||
_cttp_ccon_fail(coc_u, u2_yes);
|
_cttp_ccon_fail(coc_u, u2_yes);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
coc_u->sat_e = u2_csat_live;
|
coc_u->sat_e = (u2_yes == coc_u->sec) ?
|
||||||
|
u2_csat_shak :
|
||||||
|
u2_csat_clyr;
|
||||||
_cttp_ccon_kick(coc_u);
|
_cttp_ccon_kick(coc_u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -911,10 +931,10 @@ _cttp_ccon_kick_connect(u2_ccon* coc_u)
|
|||||||
c3_y* buf_y;
|
c3_y* buf_y;
|
||||||
} _u2_write_t;
|
} _u2_write_t;
|
||||||
|
|
||||||
/* _cttp_ccon_kick_write_cb(): general write callback.
|
/* _cttp_ccon_kick_write_clyr_cb(): general write callback for cleartext conn
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
_cttp_ccon_kick_write_cb(uv_write_t* wri_u, c3_i sas_i)
|
_cttp_ccon_kick_write_clyr_cb(uv_write_t* wri_u, c3_i sas_i)
|
||||||
{
|
{
|
||||||
u2_lo_open();
|
u2_lo_open();
|
||||||
{
|
{
|
||||||
@ -942,7 +962,7 @@ _cttp_ccon_kick_write_buf(u2_ccon* coc_u, uv_buf_t buf_u)
|
|||||||
if ( 0 != uv_write(&ruq_u->wri_u,
|
if ( 0 != uv_write(&ruq_u->wri_u,
|
||||||
(uv_stream_t*)&(coc_u->wax_u),
|
(uv_stream_t*)&(coc_u->wax_u),
|
||||||
&buf_u, 1,
|
&buf_u, 1,
|
||||||
_cttp_ccon_kick_write_cb) )
|
_cttp_ccon_kick_write_clyr_cb) )
|
||||||
{
|
{
|
||||||
_cttp_ccon_fail(coc_u, u2_yes);
|
_cttp_ccon_fail(coc_u, u2_yes);
|
||||||
}
|
}
|
||||||
@ -986,13 +1006,68 @@ _cttp_ccon_kick_write(u2_ccon* coc_u)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _cttp_ccon_read_cb()
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
_cttp_ccon_kick_read_cb(uv_stream_t* tcp_u,
|
_cttp_ccon_kick_cryp_hurr(SSL* ssl, int rev)
|
||||||
ssize_t siz_i,
|
|
||||||
uv_buf_t buf_u)
|
|
||||||
{
|
{
|
||||||
|
c3_i err = SSL_get_error(ssl, rev);
|
||||||
|
if ( SSL_ERROR_WANT_READ == err ) {
|
||||||
|
uL(fprintf(uH, ("ssl-hurr want read\n")));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uL(fprintf(uH, ("ssl-hurr fucked\n")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
_cttp_ccon_pars_shov(u2_ccon* coc_u, void* buf_u, ssize_t siz_i)
|
||||||
|
{
|
||||||
|
|
||||||
|
u2_creq* ceq_u = coc_u->ceq_u;
|
||||||
|
|
||||||
|
if ( !ceq_u ) { // spurious input
|
||||||
|
uL(fprintf(uH, "http: response to no request\n"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( !ceq_u->res_u ) {
|
||||||
|
_cttp_cres_start(ceq_u);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( siz_i != http_parser_execute(ceq_u->res_u->par_u,
|
||||||
|
&_cttp_settings,
|
||||||
|
(c3_c*)buf_u,
|
||||||
|
siz_i) )
|
||||||
|
{
|
||||||
|
uL(fprintf(uH, "http: parse error\n"));
|
||||||
|
_cttp_ccon_fail(coc_u, u2_no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cttp_ccon_kick_cryp_pull(u2_ccon* coc_u)
|
||||||
|
{
|
||||||
|
uL(fprintf(uH, "cttp-cryp-pull\n"));
|
||||||
|
if ( SSL_is_init_finished(coc_u->ssl.ssl_u) ) {
|
||||||
|
static c3_c buf[1<<14];
|
||||||
|
c3_i ruf;
|
||||||
|
while ( 0 < (ruf = SSL_read(coc_u->ssl.ssl_u, &buf, sizeof(buf))) ) {
|
||||||
|
_cttp_ccon_pars_shov(coc_u, &buf, ruf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// not connected
|
||||||
|
c3_i r = SSL_connect(coc_u->ssl.ssl_u);
|
||||||
|
if ( 0 > r ) {
|
||||||
|
_cttp_ccon_kick_cryp_hurr(coc_u->ssl.ssl_u, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cttp_ccon_kick_read_cryp_cb(uv_stream_t* tcp_u,
|
||||||
|
ssize_t siz_i,
|
||||||
|
uv_buf_t buf_u)
|
||||||
|
{
|
||||||
|
uL(fprintf(uH, "cttp-cryp-read\n"));
|
||||||
u2_ccon *coc_u = _cttp_ccon_wax((uv_tcp_t*)tcp_u);
|
u2_ccon *coc_u = _cttp_ccon_wax((uv_tcp_t*)tcp_u);
|
||||||
|
|
||||||
u2_lo_open();
|
u2_lo_open();
|
||||||
@ -1009,18 +1084,8 @@ _cttp_ccon_kick_read_cb(uv_stream_t* tcp_u,
|
|||||||
uL(fprintf(uH, "http: response to no request\n"));
|
uL(fprintf(uH, "http: response to no request\n"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( !ceq_u->res_u ) {
|
BIO_write(coc_u->ssl.rio_u, (c3_c*)buf_u.base, siz_i);
|
||||||
_cttp_cres_start(ceq_u);
|
_cttp_ccon_kick_cryp_pull(coc_u);
|
||||||
}
|
|
||||||
|
|
||||||
if ( siz_i != http_parser_execute(ceq_u->res_u->par_u,
|
|
||||||
&_cttp_settings,
|
|
||||||
(c3_c*)buf_u.base,
|
|
||||||
siz_i) )
|
|
||||||
{
|
|
||||||
uL(fprintf(uH, "http: parse error\n"));
|
|
||||||
_cttp_ccon_fail(coc_u, u2_no);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( buf_u.base ) {
|
if ( buf_u.base ) {
|
||||||
@ -1030,14 +1095,73 @@ _cttp_ccon_kick_read_cb(uv_stream_t* tcp_u,
|
|||||||
u2_lo_shut(u2_yes);
|
u2_lo_shut(u2_yes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _cttp_ccon_kick_read(): start reading.
|
/* _cttp_ccon_read_clyr_cb()
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
_cttp_ccon_kick_read(u2_ccon* coc_u)
|
_cttp_ccon_kick_read_clyr_cb(uv_stream_t* tcp_u,
|
||||||
|
ssize_t siz_i,
|
||||||
|
uv_buf_t buf_u)
|
||||||
|
{
|
||||||
|
u2_ccon *coc_u = _cttp_ccon_wax((uv_tcp_t*)tcp_u);
|
||||||
|
|
||||||
|
u2_lo_open();
|
||||||
|
{
|
||||||
|
if ( siz_i < 0 ) {
|
||||||
|
uv_err_t las_u = uv_last_error(u2L);
|
||||||
|
|
||||||
|
_cttp_ccon_fail(coc_u, (UV_EOF == las_u.code) ? u2_no : u2_yes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_cttp_ccon_pars_shov(coc_u, buf_u.base, siz_i);
|
||||||
|
}
|
||||||
|
if ( buf_u.base ) {
|
||||||
|
free(buf_u.base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u2_lo_shut(u2_yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _cttp_ccon_kick_read_clyr(): start reading on insecure socket.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_cttp_ccon_kick_read_clyr(u2_ccon* coc_u)
|
||||||
{
|
{
|
||||||
uv_read_start((uv_stream_t*)&coc_u->wax_u,
|
uv_read_start((uv_stream_t*)&coc_u->wax_u,
|
||||||
_cttp_alloc,
|
_cttp_alloc,
|
||||||
_cttp_ccon_kick_read_cb);
|
_cttp_ccon_kick_read_clyr_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _cttp_ccon_kick_handshake(): start ssl handshake.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_cttp_ccon_kick_handshake(u2_ccon* coc_u)
|
||||||
|
{
|
||||||
|
uL(fprintf(uH, "cttp: shak\n"));
|
||||||
|
|
||||||
|
coc_u->ssl.ssl_u = SSL_new(u2S);
|
||||||
|
c3_assert(coc_u->ssl.ssl_u);
|
||||||
|
|
||||||
|
coc_u->ssl.rio_u = BIO_new(BIO_s_mem());
|
||||||
|
c3_assert(coc_u->ssl.rio_u);
|
||||||
|
|
||||||
|
coc_u->ssl.wio_u = BIO_new(BIO_s_mem());
|
||||||
|
c3_assert(coc_u->ssl.wio_u);
|
||||||
|
|
||||||
|
BIO_set_nbio(coc_u->ssl.rio_u, 1);
|
||||||
|
BIO_set_nbio(coc_u->ssl.wio_u, 1);
|
||||||
|
|
||||||
|
SSL_set_bio(coc_u->ssl.ssl_u,
|
||||||
|
coc_u->ssl.rio_u,
|
||||||
|
coc_u->ssl.wio_u);
|
||||||
|
|
||||||
|
SSL_set_connect_state(coc_u->ssl.ssl_u);
|
||||||
|
SSL_do_handshake(coc_u->ssl.ssl_u);
|
||||||
|
|
||||||
|
coc_u->sat_e = u2_csat_cryp;
|
||||||
|
uv_read_start((uv_stream_t*)&coc_u->wax_u,
|
||||||
|
_cttp_alloc,
|
||||||
|
_cttp_ccon_kick_read_cryp_cb);
|
||||||
|
_cttp_ccon_kick_cryp_pull(coc_u);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _cttp_ccon_kick(): start appropriate I/O on client connection.
|
/* _cttp_ccon_kick(): start appropriate I/O on client connection.
|
||||||
@ -1059,13 +1183,17 @@ _cttp_ccon_kick(u2_ccon* coc_u)
|
|||||||
_cttp_ccon_kick_connect(coc_u);
|
_cttp_ccon_kick_connect(coc_u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case u2_csat_live: {
|
case u2_csat_shak: {
|
||||||
|
_cttp_ccon_kick_handshake(coc_u);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case u2_csat_clyr: {
|
||||||
_cttp_ccon_fill(coc_u);
|
_cttp_ccon_fill(coc_u);
|
||||||
|
|
||||||
if ( coc_u->rub_u ) {
|
if ( coc_u->rub_u ) {
|
||||||
_cttp_ccon_kick_write(coc_u);
|
_cttp_ccon_kick_write(coc_u);
|
||||||
}
|
}
|
||||||
_cttp_ccon_kick_read(coc_u);
|
_cttp_ccon_kick_read_clyr(coc_u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1320,12 +1448,33 @@ u2_cttp_ef_thus(c3_l num_l,
|
|||||||
u2z(cuq);
|
u2z(cuq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* u2_cttp_io_init(): initialize http I/O.
|
/* u2_cttp_io_init(): initialize http client I/O.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
u2_cttp_io_init()
|
u2_cttp_io_init()
|
||||||
{
|
{
|
||||||
|
c3_i rad;
|
||||||
|
c3_y buf[4096];
|
||||||
|
|
||||||
u2_Host.ctp_u.coc_u = 0;
|
u2_Host.ctp_u.coc_u = 0;
|
||||||
|
|
||||||
|
SSL_library_init();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
|
||||||
|
u2_Host.ssl_u = SSL_CTX_new(TLSv1_client_method());
|
||||||
|
SSL_CTX_set_options(u2S, SSL_OP_NO_SSLv2);
|
||||||
|
SSL_CTX_set_verify(u2S, SSL_VERIFY_PEER, NULL);
|
||||||
|
SSL_CTX_set_session_cache_mode(u2S, SSL_SESS_CACHE_OFF);
|
||||||
|
|
||||||
|
// RAND_status, at least on OS X, never returns true.
|
||||||
|
// 4096 bytes should be enough entropy for anyone, right?
|
||||||
|
rad = open("/dev/urandom", O_RDONLY);
|
||||||
|
if ( 4096 != read(rad, &buf, 4096) ) {
|
||||||
|
perror("rand-seed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
RAND_seed(buf, 4096);
|
||||||
|
close(rad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* u2_cttp_io_poll(): poll kernel for cttp I/O.
|
/* u2_cttp_io_poll(): poll kernel for cttp I/O.
|
||||||
@ -1340,4 +1489,5 @@ u2_cttp_io_poll(void)
|
|||||||
void
|
void
|
||||||
u2_cttp_io_exit(void)
|
u2_cttp_io_exit(void)
|
||||||
{
|
{
|
||||||
|
SSL_CTX_free(u2S);
|
||||||
}
|
}
|
||||||
|
2
v/loop.c
2
v/loop.c
@ -163,6 +163,7 @@ _lo_init()
|
|||||||
u2_ames_io_init();
|
u2_ames_io_init();
|
||||||
u2_term_io_init();
|
u2_term_io_init();
|
||||||
u2_http_io_init();
|
u2_http_io_init();
|
||||||
|
u2_cttp_io_init();
|
||||||
u2_save_io_init();
|
u2_save_io_init();
|
||||||
u2_batz_io_init();
|
u2_batz_io_init();
|
||||||
}
|
}
|
||||||
@ -186,6 +187,7 @@ u2_lo_exit(void)
|
|||||||
u2_ames_io_exit();
|
u2_ames_io_exit();
|
||||||
u2_term_io_exit();
|
u2_term_io_exit();
|
||||||
u2_http_io_exit();
|
u2_http_io_exit();
|
||||||
|
u2_cttp_io_exit();
|
||||||
u2_save_io_exit();
|
u2_save_io_exit();
|
||||||
u2_batz_io_exit();
|
u2_batz_io_exit();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user