1 /*  Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2 
3     This program is free software; you can redistribute it and/or modify
4     it under the terms of the GNU General Public License, version 2.0,
5     as published by the Free Software Foundation.
6 
7     This program is also distributed with certain software (including
8     but not limited to OpenSSL) that is licensed under separate terms,
9     as designated in a particular file or component or in included license
10     documentation.  The authors of MySQL hereby grant you an additional
11     permission to link the program and your derivative works with the
12     separately licensed software that they have included with MySQL.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License, version 2.0, for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22 
23 /**
24   @file
25   Server session service implementation. For more information please check
26   the function comments.
27 */
28 #include "srv_session.h"
29 /*
30  service_srv_session.h should not be first to be included as it will include
31  - include/mysql/service_srv_session.h
32  - include/mysql/plugin.h
33  - include/mysql/services.h
34  - include/mysql/service_command.h
35  which in turn will need MYSQL_SESSION but won't see it, as it will be
36  declared after the includes.
37  */
38 #include "mysql/service_srv_session.h"
39 #include "sql_class.h"
40 #include "conn_handler/connection_handler_manager.h"
41 
42 extern "C"
43 {
44 
45 /**
46   Initializes physical thread to use with session service.
47 
48   @return
49     0  success
50     1  failure
51 */
srv_session_init_thread(const void * plugin)52 int srv_session_init_thread(const void *plugin)
53 {
54   return Srv_session::init_thread(plugin);
55 }
56 
57 
58 /**
59   Deinitializes physical thread to use with session service
60 */
srv_session_deinit_thread()61 void srv_session_deinit_thread()
62 {
63   Srv_session::deinit_thread();
64 }
65 
66 
67 /**
68   Opens server session
69 
70   @param error_cb              Default completion callback
71   @param plugin_ctx            Plugin's context, opaque pointer that would
72                                be provided to callbacks. Might be NULL.
73   @return
74     handler of session   on success
75     NULL                 on failure
76 */
srv_session_open(srv_session_error_cb error_cb,void * plugin_ctx)77 Srv_session* srv_session_open(srv_session_error_cb error_cb, void *plugin_ctx)
78 {
79   DBUG_ENTER("srv_session_open");
80 
81   if (!srv_session_server_is_available())
82   {
83     if (error_cb)
84       error_cb(plugin_ctx, ER_SERVER_ISNT_AVAILABLE,
85                ER_DEFAULT(ER_SERVER_ISNT_AVAILABLE));
86     DBUG_RETURN(NULL);
87   }
88 
89   bool simulate_reach_max_connections= false;
90   DBUG_EXECUTE_IF("simulate_reach_max_connections",
91                   simulate_reach_max_connections= true;);
92 
93   Connection_handler_manager *conn_manager=
94       Connection_handler_manager::get_instance();
95 
96   if (simulate_reach_max_connections ||
97       !conn_manager->check_and_incr_conn_count(false))
98   {
99     if (error_cb)
100       error_cb(plugin_ctx, ER_CON_COUNT_ERROR, ER_DEFAULT(ER_CON_COUNT_ERROR));
101     DBUG_RETURN(NULL);
102   }
103 
104   Srv_session* session= new (std::nothrow) class Srv_session(error_cb, plugin_ctx);
105 
106   if (!session)
107   {
108     DBUG_PRINT("error", ("Can't allocate a Srv_session object"));
109     connection_errors_internal++;
110     if (error_cb)
111       error_cb(plugin_ctx, ER_OUT_OF_RESOURCES, ER_DEFAULT(ER_OUT_OF_RESOURCES));
112   }
113   else
114   {
115     THD *current= current_thd;
116     THD *stack_thd= session->get_thd();
117 
118     session->get_thd()->thread_stack= reinterpret_cast<char *>(&stack_thd);
119     session->get_thd()->store_globals();
120 
121     bool result= session->open();
122 
123     session->get_thd()->restore_globals();
124 
125     if (result)
126     {
127       delete session;
128       session= NULL;
129     }
130 
131     if (current)
132       current->store_globals();
133   }
134   DBUG_RETURN(session);
135 }
136 
137 
138 /**
139   Detaches a session from current physical thread.
140 
141   @param session  Session handle to detach
142 
143   @returns
144     0  success
145     1  failure
146 */
srv_session_detach(Srv_session * session)147 int srv_session_detach(Srv_session* session)
148 {
149   DBUG_ENTER("srv_session_detach");
150 
151   if (!session || !Srv_session::is_valid(session))
152   {
153     DBUG_PRINT("error", ("Session is not valid"));
154     DBUG_RETURN(true);
155   }
156 
157   DBUG_RETURN(session->detach());
158 }
159 
160 
161 /**
162   Closes a session.
163 
164   @param session  Session handle to close
165 
166   @returns
167     0  Session successfully closed
168     1  Session wasn't found or key doesn't match
169 */
srv_session_close(Srv_session * session)170 int srv_session_close(Srv_session* session)
171 {
172   DBUG_ENTER("srv_session_close");
173 
174   if (!session || !Srv_session::is_valid(session))
175   {
176     DBUG_PRINT("error", ("Session is not valid"));
177     DBUG_RETURN(1);
178   }
179 
180   session->close();
181   delete session;
182 
183   /*
184     Here we don't need to reattach the previous session, as the next
185     function (run_command() for example) will attach to whatever is needed.
186   */
187   DBUG_RETURN(0);
188 }
189 
190 /**
191   Returns if the server is available (not booting or shutting down)
192 
193   @return
194     0  not available
195     1  available
196 */
srv_session_server_is_available()197 int srv_session_server_is_available()
198 {
199   return get_server_state() == SERVER_OPERATING;
200 }
201 
202 } /* extern "C" */
203