return;
}
- struct session2 *s;
- int res = io_create(master->loop, &s, SOCK_STREAM, AF_UNSPEC, grp,
+ union session_or_handle out = { 0 };
+ int res = io_create(master->loop, &out, SOCK_STREAM, AF_UNSPEC, grp,
NULL, 0, false);
if (res) {
if (res == UV_EMFILE) {
the_worker->too_many_open = true;
the_worker->rconcurrent_highwatermark = the_worker->stats.rconcurrent;
}
- /* Since res isn't OK struct session wasn't allocated \ borrowed.
- * We must release client handle only.
- */
+ if (out.handle != NULL) {
+ /* Since res isn't OK struct session wasn't
+ * allocated \ borrowed. We must release client handle
+ * only. But first accept the connection, as it has
+ * already been established by the kernel and
+ * it is required for proper termination.
+ */
+ if (uv_accept(master, (uv_stream_t *)out.handle) == 0) {
+ uv_close(out.handle, (uv_close_cb)free);
+ }
+ }
return;
}
+ struct session2 *s = out.session;
kr_require(s->outgoing == false);
uv_tcp_t *client = (uv_tcp_t *)session2_get_handle(s);
}
#endif
-int io_create(uv_loop_t *loop, struct session2 **out_session, int type,
- unsigned family, enum kr_proto grp,
+int io_create(uv_loop_t *loop, union session_or_handle *out,
+ int type, unsigned family, enum kr_proto grp,
struct protolayer_data_param *layer_param,
size_t layer_param_count, bool outgoing)
{
- *out_session = NULL;
+ out->session = NULL;
int ret = -1;
uv_handle_t *handle;
if (type == SOCK_DGRAM) {
}
struct session2 *s = session2_new_io(handle, grp, layer_param,
layer_param_count, outgoing);
- if (s == NULL) {
- ret = -1;
+ if (unlikely(s == NULL)) {
+ out->handle = handle;
+ return -1;
}
- *out_session = s;
+ out->session = s;
return ret;
}
struct tls_ctx;
struct tls_client_ctx;
struct io_stream_data;
+/* union used for io_create. handle will be used only if session init fails,
+ * allowing us to terminated the uv_handle gracefully */
+union session_or_handle {
+ struct session2 *session;
+ uv_handle_t *handle;
+};
/** Bind address into a file-descriptor (only, no libuv). type is e.g. SOCK_DGRAM */
int io_bind(const struct sockaddr *addr, int type, const endpoint_flags_t *flags);
* \param type = SOCK_*
* \param family = AF_*
* \param has_tls has meanings only when type is SOCK_STREAM */
-int io_create(uv_loop_t *loop, struct session2 **out_session, int type,
+int io_create(uv_loop_t *loop, union session_or_handle *out, int type,
unsigned family, enum kr_proto grp,
struct protolayer_data_param *layer_param,
size_t layer_param_count, bool outgoing);
session2_inc_refs(s); /* Session owns the timer */
/* Initialize the layer's session data */
- for (size_t i = 0; i < grp->num_layers; i++) {
+ size_t i;
+ for (i = 0; i < grp->num_layers; i++) {
struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
struct protolayer_data *sess_data = protolayer_sess_data_get(s, i);
if (sess_data) {
}
void *param = get_init_param(grp->layers[i], layer_param, layer_param_count);
- if (globals->sess_init)
- globals->sess_init(s, sess_data, param);
+ if (globals->sess_init && globals->sess_init(s, sess_data, param) != 0) {
+ /* Init failed, terminate session */
+ goto failed_init;
+ }
}
session2_touch(s);
return s;
+
+failed_init:
+ while (i --> 0) {
+ struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
+ struct protolayer_data *sess_data = protolayer_sess_data_get(s, i);
+ if (globals->sess_deinit) {
+ globals->sess_deinit(s, sess_data);
+ }
+
+ if (sess_data) {
+ memset(sess_data, 0, globals->sess_size);
+ sess_data->session = NULL;
+ }
+ }
+
+ return NULL;
}
/** De-allocates the session. Must only be called once the underlying IO handle
{
struct session2 *s = session2_new(SESSION2_TRANSPORT_IO, layer_grp,
layer_param, layer_param_count, outgoing);
- s->transport.io.handle = handle;
- handle->data = s;
- session2_inc_refs(s); /* Session owns the handle */
+ if (likely(s != NULL)) {
+ s->transport.io.handle = handle;
+ handle->data = s;
+ session2_inc_refs(s); /* Session owns the handle */
+ }
return s;
}
{
struct session2 *s = session2_new(SESSION2_TRANSPORT_PARENT, layer_grp,
layer_param, layer_param_count, outgoing);
- s->transport.parent = parent;
+ if (likely(s != NULL)) {
+ s->transport.parent = parent;
+ }
return s;
}
}
/* Create connection for iterative query */
- struct session2 *s;
- int ret = io_create(the_worker->loop, &s, socktype, family, grp,
+ union session_or_handle out;
+ int ret = io_create(the_worker->loop, &out, socktype, family, grp,
layer_param, layer_param_count, true);
if (ret) {
if (ret == UV_EMFILE) {
}
return NULL;
}
+ struct session2 *s = out.session;
/* Bind to outgoing address, according to IP v4/v6. */
union kr_sockaddr *addr;