SSL *ssl; /* owns one reference */
unsigned int registered : 1; /* in LHASH? */
unsigned int active : 1; /* tick? */
+ CRYPTO_MUTEX *mx;
} RADIX_OBJ;
DEFINE_LHASH_OF_EX(RADIX_OBJ);
DEFINE_STACK_OF(RADIX_THREAD)
/* ssl reference is transferred. name is copied and is required. */
-static RADIX_OBJ *RADIX_OBJ_new(const char *name, SSL *ssl)
+static RADIX_OBJ *RADIX_OBJ_new_empty(const char *name)
{
RADIX_OBJ *obj;
- if (!TEST_ptr(name) || !TEST_ptr(ssl))
+ if (!TEST_ptr(name))
return NULL;
if (!TEST_ptr(obj = OPENSSL_zalloc(sizeof(*obj))))
return NULL;
}
+ obj->mx = ossl_crypto_mutex_new();
+#if !defined(OPENSSL_THREADS_NONE)
+ if (obj->mx == NULL) {
+ OPENSSL_free(obj->name);
+ OPENSSL_free(obj);
+ return NULL;
+ }
+#endif
+
+ return obj;
+}
+
+static RADIX_OBJ *RADIX_OBJ_new(const char *name, SSL *ssl)
+{
+ RADIX_OBJ *obj;
+
+ if (!TEST_ptr(ssl))
+ return NULL;
+
+ obj = RADIX_OBJ_new_empty(name);
+ if (!TEST_ptr(obj))
+ return NULL;
+
obj->ssl = ssl;
+
return obj;
}
SSL_free(obj->ssl);
OPENSSL_free(obj->name);
+ ossl_crypto_mutex_free(&obj->mx);
OPENSSL_free(obj);
}
const char *name, RADIX_OBJ *obj)
{
RADIX_OBJ *existing;
+ SSL *existing_ssl = NULL;
+ RADIX_THREAD *rt;
+ int i, j;
if (obj != NULL && !TEST_false(obj->registered))
return 0;
lh_RADIX_OBJ_delete(rp->objs, existing);
existing->registered = 0;
+ existing_ssl = existing->ssl;
RADIX_OBJ_free(existing);
+ } else {
+ existing = NULL;
}
if (obj != NULL) {
obj->registered = 1;
}
+ if (existing != NULL) {
+ for (i = 0; i < sk_RADIX_THREAD_num(rp->threads); i++) {
+ rt = (RADIX_THREAD *)sk_RADIX_THREAD_value(rp->threads, i);
+ for (j = 0; j < NUM_SLOTS; j++) {
+ if (rt->slot[j] == existing)
+ rt->slot[j] = obj;
+ if (rt->ssl[j] == existing_ssl)
+ rt->ssl[j] = (obj == NULL) ? NULL : obj->ssl;
+ }
+ }
+ }
+
return 1;
}
static void per_op_tick_obj(RADIX_OBJ *obj)
{
- if (obj->active)
+ ossl_crypto_mutex_lock(obj->mx);
+ if (obj->active && obj->ssl)
SSL_handle_events(obj->ssl);
+ ossl_crypto_mutex_unlock(obj->mx);
}
static int do_per_op(TERP *terp, void *arg)
return ok;
}
+DEF_FUNC(hf_bind)
+{
+ const char *name;
+ RADIX_OBJ *empty_obj;
+
+ F_POP(name);
+
+ empty_obj = RADIX_OBJ_new_empty(name);
+ if (empty_obj == NULL)
+ return 0;
+
+ RADIX_PROCESS_set_obj(RP(), name, empty_obj);
+
+ return 1;
+err:
+ return 0;
+}
+
static int ssl_ctx_select_alpn(SSL *ssl,
const unsigned char **out, unsigned char *out_len,
const unsigned char *in, unsigned int in_len,
return ok;
}
+#define OP_F_REPLACE_STREAM 0x8000000000000000
+#define OP_F_MASK 0x7fffffffffffffff
+
DEF_FUNC(hf_new_stream)
{
int ok = 0;
+ int replace;
+ RADIX_OBJ *stream_obj;
const char *stream_name;
- SSL *conn, *stream;
+ SSL *conn, *stream, *old;
uint64_t flags, do_accept;
F_POP2(flags, do_accept);
F_POP(stream_name);
REQUIRE_SSL(conn);
+ replace = ((OP_F_REPLACE_STREAM & flags) != 0);
- if (!TEST_ptr_null(RADIX_PROCESS_get_obj(RP(), stream_name)))
+ stream_obj = RADIX_PROCESS_get_obj(RP(), stream_name);
+ if (replace == 0) {
+ if (!TEST_ptr_null(stream_obj))
+ goto err;
+ } else if (TEST_ptr_null(stream_obj))
goto err;
if (do_accept) {
- stream = SSL_accept_stream(conn, flags);
+ stream = SSL_accept_stream(conn, flags & OP_F_MASK);
if (stream == NULL)
F_SPIN_AGAIN();
} else {
- stream = SSL_new_stream(conn, flags);
+ stream = SSL_new_stream(conn, flags & OP_F_MASK);
}
if (!TEST_ptr(stream))
/* TODO(QUIC RADIX): Implement wait behaviour */
- if (stream != NULL
- && !TEST_true(RADIX_PROCESS_set_ssl(RP(), stream_name, stream))) {
+ if (stream_obj != NULL) {
+ ossl_crypto_mutex_lock(stream_obj->mx);
+ old = stream_obj->ssl;
+ stream_obj->ssl = stream;
+ stream = NULL;
+ ossl_crypto_mutex_unlock(stream_obj->mx);
+ SSL_free(old);
+ } else if (!TEST_true(RADIX_PROCESS_set_ssl(RP(), stream_name, stream))) {
SSL_free(stream);
goto err;
}
(OP_PUSH_PZ(#name), \
OP_FUNC(hf_unbind))
+#define OP_BIND(name) \
+ (OP_PUSH_PZ(#name), \
+ OP_FUNC(hf_bind))
+
#define OP_SELECT_SSL(slot, name) \
(OP_PUSH_U64(slot), \
OP_PUSH_PZ(#name), \
DEF_SCRIPT(script_11_child_0,
"child: accept stream from C, read, sleep, expect FIN")
{
- OP_ACCEPT_STREAM_WAIT(C, C0, 0 /* bidirectional */);
+ OP_ACCEPT_STREAM_WAIT(C, C0, OP_F_REPLACE_STREAM /* bidirectional */);
OP_READ_EXPECT_B(C0, "foo");
OP_SLEEP(10);
OP_EXPECT_FIN(C0);
DEF_SCRIPT(script_11_child_1,
"child: accept stream from C, read, sleep, expect FIN")
{
- OP_ACCEPT_STREAM_WAIT(C, C1, 0 /* bidirectional */);
+ OP_ACCEPT_STREAM_WAIT(C, C1, OP_F_REPLACE_STREAM /* bidirectional */);
OP_READ_EXPECT_B(C1, "foo");
OP_SLEEP(10);
OP_EXPECT_FIN(C1);
DEF_SCRIPT(script_11_child_2,
"child: accept stream from C, read, sleep, expect FIN")
{
- OP_ACCEPT_STREAM_WAIT(C, C2, 0 /* bidirectional */);
+ OP_ACCEPT_STREAM_WAIT(C, C2, OP_F_REPLACE_STREAM /* bidirectional */);
OP_READ_EXPECT_B(C2, "foo");
OP_SLEEP(10);
OP_EXPECT_FIN(C2);
DEF_SCRIPT(script_11_child_3,
"child: accept stream from C, read, sleep, expect FIN")
{
- OP_ACCEPT_STREAM_WAIT(C, C3, 0 /* bidirectional */);
+ OP_ACCEPT_STREAM_WAIT(C, C3, OP_F_REPLACE_STREAM /* bidirectional */);
OP_READ_EXPECT_B(C3, "foo");
OP_SLEEP(10);
OP_EXPECT_FIN(C3);
DEF_SCRIPT(script_11_child_4,
"child: accept stream from C, read, sleep, expect FIN")
{
- OP_ACCEPT_STREAM_WAIT(C, C4, 0 /* bidirectional */);
+ OP_ACCEPT_STREAM_WAIT(C, C4, OP_F_REPLACE_STREAM /* bidirectional */);
OP_READ_EXPECT_B(C4, "foo");
OP_SLEEP(10);
OP_EXPECT_FIN(C4);
OP_SIMPLE_PAIR_CONN_ND();
OP_ACCEPT_CONN_WAIT(L, S, 0);
+ OP_BIND(C0);
+ OP_BIND(C1);
+ OP_BIND(C2);
+ OP_BIND(C3);
+ OP_BIND(C4);
+ OP_BIND(Sa);
+ OP_BIND(Sb);
+ OP_BIND(Sc);
+ OP_BIND(Sd);
+ OP_BIND(Se);
+
OP_SPAWN_THREAD(script_11_child_0);
OP_SPAWN_THREAD(script_11_child_1);
OP_SPAWN_THREAD(script_11_child_2);
OP_SPAWN_THREAD(script_11_child_3);
OP_SPAWN_THREAD(script_11_child_4);
- OP_NEW_STREAM(S, Sa, 0 /* bidirectional */);
+ OP_NEW_STREAM(S, Sa, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(Sa, "foo");
OP_CONCLUDE(Sa);
- OP_NEW_STREAM(S, Sb, 0 /* bidirectional */);
+ OP_NEW_STREAM(S, Sb, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(Sb, "foo");
OP_CONCLUDE(Sb);
- OP_NEW_STREAM(S, Sc, 0 /* bidirectional */);
+ OP_NEW_STREAM(S, Sc, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(Sc, "foo");
OP_CONCLUDE(Sc);
- OP_NEW_STREAM(S, Sd, 0 /* bidirectional */);
+ OP_NEW_STREAM(S, Sd, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(Sd, "foo");
OP_CONCLUDE(Sd);
- OP_NEW_STREAM(S, Se, 0 /* bidirectional */);
+ OP_NEW_STREAM(S, Se, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(Se, "foo");
OP_CONCLUDE(Se);
OP_SLEEP(10);
DEF_SCRIPT(script_12_child_0,
"child: create stream on C, write, conclude")
{
- OP_NEW_STREAM(C, C0, 0 /* bidirectional */);
+ OP_NEW_STREAM(C, C0, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(C0, "foo");
OP_CONCLUDE(C0);
}
DEF_SCRIPT(script_12_child_1,
"child: create stream on C, write, conclude")
{
- OP_NEW_STREAM(C, C1, 0 /* bidirectional */);
+ OP_NEW_STREAM(C, C1, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(C1, "foo");
OP_CONCLUDE(C1);
}
DEF_SCRIPT(script_12_child_2,
"child: create stream on C, write, conclude")
{
- OP_NEW_STREAM(C, C2, 0 /* bidirectional */);
+ OP_NEW_STREAM(C, C2, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(C2, "foo");
OP_CONCLUDE(C2);
}
DEF_SCRIPT(script_12_child_3,
"child: create stream on C, write, conclude")
{
- OP_NEW_STREAM(C, C3, 0 /* bidirectional */);
+ OP_NEW_STREAM(C, C3, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(C3, "foo");
OP_CONCLUDE(C3);
}
DEF_SCRIPT(script_12_child_4,
"child: create stream on C, write, conclude")
{
- OP_NEW_STREAM(C, C4, 0 /* bidirectional */);
+ OP_NEW_STREAM(C, C4, OP_F_REPLACE_STREAM /* bidirectional */);
OP_WRITE_B(C4, "foo");
OP_CONCLUDE(C4);
}
OP_SIMPLE_PAIR_CONN_ND();
OP_ACCEPT_CONN_WAIT_ND(L, S, 0);
+ OP_BIND(C0);
+ OP_BIND(C1);
+ OP_BIND(C2);
+ OP_BIND(C3);
+ OP_BIND(C4);
+ OP_BIND(Sa);
+ OP_BIND(Sb);
+ OP_BIND(Sc);
+ OP_BIND(Sd);
+ OP_BIND(Se);
+
OP_SPAWN_THREAD(script_12_child_0);
OP_SPAWN_THREAD(script_12_child_1);
OP_SPAWN_THREAD(script_12_child_2);
OP_SPAWN_THREAD(script_12_child_3);
OP_SPAWN_THREAD(script_12_child_4);
- OP_ACCEPT_STREAM_WAIT(S, Sa, 0);
+ OP_ACCEPT_STREAM_WAIT(S, Sa, OP_F_REPLACE_STREAM);
OP_READ_EXPECT_B(Sa, "foo");
OP_EXPECT_FIN(Sa);
- OP_ACCEPT_STREAM_WAIT(S, Sb, 0);
+ OP_ACCEPT_STREAM_WAIT(S, Sb, OP_F_REPLACE_STREAM);
OP_READ_EXPECT_B(Sb, "foo");
OP_EXPECT_FIN(Sb);
- OP_ACCEPT_STREAM_WAIT(S, Sc, 0);
+ OP_ACCEPT_STREAM_WAIT(S, Sc, OP_F_REPLACE_STREAM);
OP_READ_EXPECT_B(Sc, "foo");
OP_EXPECT_FIN(Sc);
- OP_ACCEPT_STREAM_WAIT(S, Sd, 0);
+ OP_ACCEPT_STREAM_WAIT(S, Sd, OP_F_REPLACE_STREAM);
OP_READ_EXPECT_B(Sd, "foo");
OP_EXPECT_FIN(Sd);
- OP_ACCEPT_STREAM_WAIT(S, Se, 0);
+ OP_ACCEPT_STREAM_WAIT(S, Se, OP_F_REPLACE_STREAM);
OP_READ_EXPECT_B(Se, "foo");
OP_EXPECT_FIN(Se);
OP_SLEEP(10);