From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladislav Shpilevoy Subject: [PATCH 4/5] session: introduce session_owner Date: Mon, 19 Mar 2018 16:34:51 +0300 Message-Id: <3009c98123cc3be6c5d0b0a0db064757b71faf16.1521466428.git.v.shpilevoy@tarantool.org> In-Reply-To: References: In-Reply-To: References: To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com, Vladislav Shpilevoy List-ID: Session owner stores a session type specific data. For example, IProto session has authentication salt, console session has file descriptor. For #2677 session owner of IProto and console will have push() virtual function to do box.session.push, which implementation depends on a session type. Needed for #2677 Signed-off-by: Vladislav Shpilevoy --- src/box/applier.cc | 4 ++- src/box/authentication.cc | 4 +-- src/box/authentication.h | 3 +- src/box/box.cc | 4 +-- src/box/box.h | 2 +- src/box/iproto.cc | 86 +++++++++++++++++++++++++++++++++++++++------ src/box/lua/session.c | 73 +++++++++++++++++++++++++++++++++----- src/box/session.cc | 72 +++++++++++++++++++++++++++++++++----- src/box/session.h | 89 ++++++++++++++++++++++++++++++++++++++++------- src/box/vinyl.c | 3 +- 10 files changed, 293 insertions(+), 47 deletions(-) diff --git a/src/box/applier.cc b/src/box/applier.cc index 6bfe5a99a..581139509 100644 --- a/src/box/applier.cc +++ b/src/box/applier.cc @@ -533,7 +533,9 @@ applier_f(va_list ap) * Set correct session type for use in on_replace() * triggers. */ - current_session()->type = SESSION_TYPE_APPLIER; + struct session_owner applier_owner; + session_owner_create(&applier_owner, SESSION_TYPE_APPLIER); + session_set_owner(current_session(), &applier_owner); /* Re-connect loop */ while (!fiber_is_cancelled()) { diff --git a/src/box/authentication.cc b/src/box/authentication.cc index fef549c55..811974cb9 100644 --- a/src/box/authentication.cc +++ b/src/box/authentication.cc @@ -37,7 +37,7 @@ static char zero_hash[SCRAMBLE_SIZE]; void -authenticate(const char *user_name, uint32_t len, +authenticate(const char *user_name, uint32_t len, const char *salt, const char *tuple) { struct user *user = user_find_by_name_xc(user_name, len); @@ -84,7 +84,7 @@ authenticate(const char *user_name, uint32_t len, "invalid scramble size"); } - if (scramble_check(scramble, session->salt, user->def->hash2)) { + if (scramble_check(scramble, salt, user->def->hash2)) { auth_res.is_authenticated = false; if (session_run_on_auth_triggers(&auth_res) != 0) diag_raise(); diff --git a/src/box/authentication.h b/src/box/authentication.h index e91fe0a0e..9935e3548 100644 --- a/src/box/authentication.h +++ b/src/box/authentication.h @@ -45,6 +45,7 @@ struct on_auth_trigger_ctx { void -authenticate(const char *user_name, uint32_t len, const char *tuple); +authenticate(const char *user_name, uint32_t len, const char *salt, + const char *tuple); #endif /* INCLUDES_TARANTOOL_BOX_AUTHENTICATION_H */ diff --git a/src/box/box.cc b/src/box/box.cc index cb3199624..9fb85c04f 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -1233,7 +1233,7 @@ box_on_join(const tt_uuid *instance_uuid) } void -box_process_auth(struct auth_request *request) +box_process_auth(struct auth_request *request, const char *salt) { rmean_collect(rmean_box, IPROTO_AUTH, 1); @@ -1243,7 +1243,7 @@ box_process_auth(struct auth_request *request) const char *user = request->user_name; uint32_t len = mp_decode_strl(&user); - authenticate(user, len, request->scramble); + authenticate(user, len, salt, request->scramble); } void diff --git a/src/box/box.h b/src/box/box.h index c9b5aad01..84899cc13 100644 --- a/src/box/box.h +++ b/src/box/box.h @@ -150,7 +150,7 @@ box_reset_stat(void); } /* extern "C" */ void -box_process_auth(struct auth_request *request); +box_process_auth(struct auth_request *request, const char *salt); void box_process_join(struct ev_io *io, struct xrow_header *header); diff --git a/src/box/iproto.cc b/src/box/iproto.cc index a75127a90..ad4b1a757 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -59,6 +59,63 @@ #include "replication.h" /* instance_uuid */ #include "iproto_constants.h" #include "rmean.h" +#include "random.h" + +enum { IPROTO_SALT_SIZE = 32 }; + +/** Owner of binary IProto sessions. */ +struct iproto_session_owner { + struct session_owner base; + /** Authentication salt. */ + char salt[IPROTO_SALT_SIZE]; + /** IProto connection. */ + struct iproto_connection *connection; +}; + +static struct session_owner * +iproto_session_owner_dup(struct session_owner *owner); + +static int +iproto_session_owner_fd(const struct session_owner *owner); + +static const struct session_owner_vtab iproto_session_owner_vtab = { + /* .dup = */ iproto_session_owner_dup, + /* .delete = */ (void (*)(struct session_owner *)) free, + /* .fd = */ iproto_session_owner_fd, +}; + +static struct session_owner * +iproto_session_owner_dup(struct session_owner *owner) +{ + assert(owner->vtab == &iproto_session_owner_vtab); + size_t size = sizeof(struct iproto_session_owner); + struct session_owner *dup = (struct session_owner *) malloc(size); + if (dup == NULL) { + diag_set(OutOfMemory, size, "malloc", "iproto_session_owner"); + return NULL; + } + memcpy(dup, owner, size); + return dup; +} + +static inline void +iproto_session_owner_create(struct iproto_session_owner *owner, + struct iproto_connection *connection) +{ + owner->base.type = SESSION_TYPE_BINARY; + owner->base.vtab = &iproto_session_owner_vtab; + owner->connection = connection; + random_bytes(owner->salt, IPROTO_SALT_SIZE); +} + +static inline char * +iproto_session_salt(struct session *session) +{ + struct iproto_session_owner *session_owner = + (struct iproto_session_owner *) session->owner; + assert(session_owner->base.vtab == &iproto_session_owner_vtab); + return session_owner->salt; +} /* The number of iproto messages in flight */ enum { IPROTO_MSG_MAX = 768 }; @@ -368,6 +425,15 @@ struct iproto_connection static struct mempool iproto_connection_pool; static RLIST_HEAD(stopped_connections); +static int +iproto_session_owner_fd(const struct session_owner *owner) +{ + assert(owner->vtab == &iproto_session_owner_vtab); + const struct iproto_session_owner *session_owner = + ((const struct iproto_session_owner *) owner); + return session_owner->connection->input.fd; +} + /** * Return true if we have not enough spare messages * in the message pool. Disconnect messages are @@ -1033,11 +1099,6 @@ tx_process_disconnect(struct cmsg *m) struct iproto_connection *con = msg->connection; if (con->session) { tx_fiber_init(con->session, 0); - /* - * The socket is already closed in iproto thread, - * prevent box.session.peer() from using it. - */ - con->session->fd = -1; if (! rlist_empty(&session_on_disconnect)) session_run_on_disconnect_triggers(con->session); session_destroy(con->session); @@ -1328,8 +1389,9 @@ tx_process_misc(struct cmsg *m) { struct iproto_msg *msg = tx_accept_msg(m); struct obuf *out = msg->connection->tx.p_obuf; + struct session *session = msg->connection->session; - tx_fiber_init(msg->connection->session, msg->header.sync); + tx_fiber_init(session, msg->header.sync); if (tx_check_schema(msg->header.schema_version)) goto error; @@ -1337,7 +1399,8 @@ tx_process_misc(struct cmsg *m) try { switch (msg->header.type) { case IPROTO_AUTH: - box_process_auth(&msg->auth); + box_process_auth(&msg->auth, + iproto_session_salt(session)); iproto_reply_ok_xc(out, msg->header.sync, ::schema_version); break; @@ -1481,15 +1544,18 @@ tx_process_connect(struct cmsg *m) struct iproto_connection *con = msg->connection; struct obuf *out = msg->connection->tx.p_obuf; try { /* connect. */ - con->session = session_create(con->input.fd, SESSION_TYPE_BINARY); + struct iproto_session_owner owner; + iproto_session_owner_create(&owner, con); + con->session = session_create((struct session_owner *) &owner); if (con->session == NULL) diag_raise(); tx_fiber_init(con->session, 0); static __thread char greeting[IPROTO_GREETING_SIZE]; /* TODO: dirty read from tx thread */ struct tt_uuid uuid = INSTANCE_UUID; - greeting_encode(greeting, tarantool_version_id(), - &uuid, con->session->salt, SESSION_SEED_SIZE); + greeting_encode(greeting, tarantool_version_id(), &uuid, + iproto_session_salt(con->session), + IPROTO_SALT_SIZE); obuf_dup_xc(out, greeting, IPROTO_GREETING_SIZE); if (! rlist_empty(&session_on_connect)) { if (session_run_on_connect_triggers(con->session) != 0) diff --git a/src/box/lua/session.c b/src/box/lua/session.c index d8e91bf1f..af8411068 100644 --- a/src/box/lua/session.c +++ b/src/box/lua/session.c @@ -42,6 +42,54 @@ #include "box/user.h" #include "box/schema.h" +/** Owner of a console session. */ +struct console_session_owner { + struct session_owner base; + /** Console socket descriptor. Expects text data. */ + int fd; +}; + +static struct session_owner * +console_session_owner_dup(struct session_owner *owner); + +static int +console_session_owner_fd(const struct session_owner *owner); + +static const struct session_owner_vtab console_session_owner_vtab = { + /* .dup = */ console_session_owner_dup, + /* .delete = */ (void (*)(struct session_owner *)) free, + /* .fd = */ console_session_owner_fd, +}; + +static struct session_owner * +console_session_owner_dup(struct session_owner *owner) +{ + assert(owner->vtab == &console_session_owner_vtab); + size_t size = sizeof(struct console_session_owner); + struct session_owner *dup = (struct session_owner *) malloc(size); + if (dup == NULL) { + diag_set(OutOfMemory, size, "malloc", "console_session_owner"); + return NULL; + } + memcpy(dup, owner, size); + return dup; +} + +static int +console_session_owner_fd(const struct session_owner *owner) +{ + assert(owner->vtab == &console_session_owner_vtab); + return ((const struct console_session_owner *) owner)->fd; +} + +static inline void +console_session_owner_create(struct console_session_owner *owner, int fd) +{ + owner->base.type = SESSION_TYPE_CONSOLE; + owner->base.vtab = &console_session_owner_vtab; + owner->fd = fd; +} + static const char *sessionlib_name = "box.session"; /* Create session and pin it to fiber */ @@ -56,14 +104,24 @@ lbox_session_create(struct lua_State *L) "session from Lua"); } struct session *session = fiber_get_session(fiber()); + int fd = luaL_optinteger(L, 1, -1); if (session == NULL) { - int fd = luaL_optinteger(L, 1, -1); - session = session_create_on_demand(fd); + struct session_owner owner; + session_owner_create(&owner, type); + session = session_create_on_demand(&owner); if (session == NULL) return luaT_error(L); } - /* If a session already exists, simply reset its type */ - session->type = type; + /* If a session already exists, simply reset its owner. */ + if (type == SESSION_TYPE_CONSOLE) { + struct console_session_owner owner; + console_session_owner_create(&owner, fd); + session_set_owner(session, (struct session_owner *) &owner); + } else { + struct session_owner owner; + session_owner_create(&owner, type); + session_set_owner(session, &owner); + } lua_pushnumber(L, session->id); return 1; } @@ -90,7 +148,7 @@ lbox_session_id(struct lua_State *L) static int lbox_session_type(struct lua_State *L) { - lua_pushstring(L, session_type_strs[current_session()->type]); + lua_pushstring(L, session_type_strs[session_type(current_session())]); return 1; } @@ -237,7 +295,7 @@ lbox_session_fd(struct lua_State *L) struct session *session = session_find(sid); if (session == NULL) luaL_error(L, "session.fd(): session does not exist"); - lua_pushinteger(L, session->fd); + lua_pushinteger(L, session_fd(session)); return 1; } @@ -251,7 +309,6 @@ lbox_session_peer(struct lua_State *L) if (lua_gettop(L) > 1) luaL_error(L, "session.peer(sid): bad arguments"); - int fd; struct session *session; if (lua_gettop(L) == 1) session = session_find(luaL_checkint(L, 1)); @@ -259,7 +316,7 @@ lbox_session_peer(struct lua_State *L) session = current_session(); if (session == NULL) luaL_error(L, "session.peer(): session does not exist"); - fd = session->fd; + int fd = session_fd(session); if (fd < 0) { lua_pushnil(L); /* no associated peer */ return 1; diff --git a/src/box/session.cc b/src/box/session.cc index 0b0c5ae44..908ec9c4e 100644 --- a/src/box/session.cc +++ b/src/box/session.cc @@ -33,7 +33,6 @@ #include "memory.h" #include "assoc.h" #include "trigger.h" -#include "random.h" #include "user.h" #include "error.h" @@ -54,6 +53,48 @@ RLIST_HEAD(session_on_connect); RLIST_HEAD(session_on_disconnect); RLIST_HEAD(session_on_auth); +static struct session_owner * +generic_session_owner_dup(struct session_owner *owner); + +static int +generic_session_owner_fd(const struct session_owner *owner); + +static const struct session_owner_vtab generic_session_owner_vtab = { + /* .dup = */ generic_session_owner_dup, + /* .delete = */ (void (*)(struct session_owner *)) free, + /* .fd = */ generic_session_owner_fd, +}; + +static struct session_owner * +generic_session_owner_dup(struct session_owner *owner) +{ + assert(owner->vtab == &generic_session_owner_vtab); + struct session_owner *dup = + (struct session_owner *) malloc(sizeof(*dup)); + if (dup == NULL) { + diag_set(OutOfMemory, sizeof(*dup), "malloc", + "default_session_owner"); + return NULL; + } + memcpy(dup, owner, sizeof(*dup)); + return dup; +} + +static int +generic_session_owner_fd(const struct session_owner *owner) +{ + assert(owner->vtab == &generic_session_owner_vtab); + (void) owner; + return -1; +} + +void +session_owner_create(struct session_owner *owner, enum session_type type) +{ + owner->type = type; + owner->vtab = &generic_session_owner_vtab; +} + static inline uint64_t sid_max() { @@ -80,7 +121,7 @@ session_on_stop(struct trigger *trigger, void * /* event */) } struct session * -session_create(int fd, enum session_type type) +session_create(struct session_owner *owner) { struct session *session = (struct session *) mempool_alloc(&session_pool); @@ -90,14 +131,15 @@ session_create(int fd, enum session_type type) return NULL; } session->id = sid_max(); - session->fd = fd; + session->owner = session_owner_dup(owner); + if (session->owner == NULL) { + mempool_free(&session_pool, session); + return NULL; + } session->sync = 0; - session->type = type; /* For on_connect triggers. */ credentials_init(&session->credentials, guest_user->auth_token, guest_user->def->uid); - if (fd >= 0) - random_bytes(session->salt, SESSION_SEED_SIZE); struct mh_i64ptr_node_t node; node.key = session->id; node.val = session; @@ -105,6 +147,7 @@ session_create(int fd, enum session_type type) mh_int_t k = mh_i64ptr_put(session_registry, &node, NULL, NULL); if (k == mh_end(session_registry)) { + session_owner_delete(owner); mempool_free(&session_pool, session); diag_set(OutOfMemory, 0, "session hash", "new session"); return NULL; @@ -112,13 +155,25 @@ session_create(int fd, enum session_type type) return session; } +int +session_set_owner(struct session *session, struct session_owner *new_owner) +{ + struct session_owner *dup = session_owner_dup(new_owner); + if (dup == NULL) + return -1; + if (session->owner != NULL) + session_owner_delete(session->owner); + session->owner = dup; + return 0; +} + struct session * -session_create_on_demand(int fd) +session_create_on_demand(struct session_owner *owner) { assert(fiber_get_session(fiber()) == NULL); /* Create session on demand */ - struct session *s = session_create(fd, SESSION_TYPE_BACKGROUND); + struct session *s = session_create(owner); if (s == NULL) return NULL; s->fiber_on_stop = { @@ -186,6 +241,7 @@ session_destroy(struct session *session) { struct mh_i64ptr_node_t node = { session->id, NULL }; mh_i64ptr_remove(session_registry, &node, NULL); + session_owner_delete(session->owner); mempool_free(&session_pool, session); } diff --git a/src/box/session.h b/src/box/session.h index 4f9235ea8..105dcab17 100644 --- a/src/box/session.h +++ b/src/box/session.h @@ -47,8 +47,6 @@ session_init(); void session_free(); -enum { SESSION_SEED_SIZE = 32, SESSION_DELIM_SIZE = 16 }; - enum session_type { SESSION_TYPE_BACKGROUND = 0, SESSION_TYPE_BINARY, @@ -60,6 +58,49 @@ enum session_type { extern const char *session_type_strs[]; +struct session_owner_vtab; + +/** + * Object to store session type specific data. For example, IProto + * stores iproto_connection, console stores file descriptor. + */ +struct session_owner { + /** Session type. */ + enum session_type type; + /** Virtual session owner methods. */ + const struct session_owner_vtab *vtab; +}; + +struct session_owner_vtab { + /** Allocate a duplicate of an owner. */ + struct session_owner *(*dup)(struct session_owner *); + /** Destroy an owner, and free its memory. */ + void (*free)(struct session_owner *); + /** Get the descriptor of an owner, if has. Else -1. */ + int (*fd)(const struct session_owner *); +}; + +static inline struct session_owner * +session_owner_dup(struct session_owner *owner) +{ + return owner->vtab->dup(owner); +} + +static inline void +session_owner_delete(struct session_owner *owner) +{ + owner->vtab->free(owner); +} + +/** + * Initialize a session owner with @a type and with default + * virtual methods. + * @param owner Session owner to initialize. Is copied inside. + * @param type Session type. + */ +void +session_owner_create(struct session_owner *owner, enum session_type type); + /** * Abstraction of a single user session: * for now, only provides accounting of established @@ -72,10 +113,8 @@ extern const char *session_type_strs[]; struct session { /** Session id. */ uint64_t id; - /** File descriptor - socket of the connected peer. - * Only if the session has a peer. - */ - int fd; + /** Session owner with type specific data. */ + struct session_owner *owner; /** * For iproto requests, we set this field * to the value of packet sync. Since the @@ -85,15 +124,24 @@ struct session { * the first yield. */ uint64_t sync; - enum session_type type; - /** Authentication salt. */ - char salt[SESSION_SEED_SIZE]; /** Session user id and global grants */ struct credentials credentials; /** Trigger for fiber on_stop to cleanup created on-demand session */ struct trigger fiber_on_stop; }; +static inline enum session_type +session_type(const struct session *session) +{ + return session->owner->type; +} + +static inline int +session_fd(const struct session *session) +{ + return session->owner->vtab->fd(session->owner); +} + /** * Find a session by id. */ @@ -154,7 +202,7 @@ extern struct credentials admin_credentials; * trigger to destroy it when this fiber ends. */ struct session * -session_create_on_demand(int fd); +session_create_on_demand(struct session_owner *owner); /* * When creating a new fiber, the database (box) @@ -171,7 +219,9 @@ current_session() { struct session *session = fiber_get_session(fiber()); if (session == NULL) { - session = session_create_on_demand(-1); + struct session_owner owner; + session_owner_create(&owner, SESSION_TYPE_BACKGROUND); + session = session_create_on_demand(&owner); if (session == NULL) diag_raise(); } @@ -191,7 +241,9 @@ effective_user() (struct credentials *) fiber_get_key(fiber(), FIBER_KEY_USER); if (u == NULL) { - session_create_on_demand(-1); + struct session_owner owner; + session_owner_create(&owner, SESSION_TYPE_BACKGROUND); + session_create_on_demand(&owner); u = (struct credentials *) fiber_get_key(fiber(), FIBER_KEY_USER); } @@ -216,7 +268,18 @@ session_storage_cleanup(int sid); * trigger fails or runs out of resources. */ struct session * -session_create(int fd, enum session_type type); +session_create(struct session_owner *owner); + +/** + * Set new owner of a session. + * @param session Session to change owner. + * @param new_owner New session owner. Is duplicated inside. + * + * @retval -1 Memory error. + * @retval 0 Success. + */ +int +session_set_owner(struct session *session, struct session_owner *new_owner); /** * Destroy a session. diff --git a/src/box/vinyl.c b/src/box/vinyl.c index e0c30757c..7ae12f597 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -2453,7 +2453,8 @@ vinyl_engine_prepare(struct engine *engine, struct txn *txn) * available for the admin to track the lag so let the applier * wait as long as necessary for memory dump to complete. */ - double timeout = (current_session()->type != SESSION_TYPE_APPLIER ? + double timeout = (session_type(current_session()) != + SESSION_TYPE_APPLIER ? env->timeout : TIMEOUT_INFINITY); /* * Reserve quota needed by the transaction before allocating -- 2.14.3 (Apple Git-98)