MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sql_connect.cc
1 /*
2  Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 /*
19  Functions to authenticate and handle requests for a connection
20 */
21 
22 #include "my_global.h"
23 #include "sql_priv.h"
24 #include "sql_audit.h"
25 #include "sql_connect.h"
26 #include "my_global.h"
27 #include "probes_mysql.h"
28 #include "unireg.h" // REQUIRED: for other includes
29 #include "sql_parse.h" // sql_command_flags,
30  // execute_init_command,
31  // do_command
32 #include "sql_db.h" // mysql_change_db
33 #include "hostname.h" // inc_host_errors, ip_to_hostname,
34  // reset_host_errors
35 #include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL
36 #include "sql_callback.h"
37 
38 #include <algorithm>
39 
40 using std::min;
41 using std::max;
42 
43 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
44 /*
45  Without SSL the handshake consists of one packet. This packet
46  has both client capabilites and scrambled password.
47  With SSL the handshake might consist of two packets. If the first
48  packet (client capabilities) has CLIENT_SSL flag set, we have to
49  switch to SSL and read the second packet. The scrambled password
50  is in the second packet and client_capabilites field will be ignored.
51  Maybe it is better to accept flags other than CLIENT_SSL from the
52  second packet?
53 */
54 #define SSL_HANDSHAKE_SIZE 2
55 #define NORMAL_HANDSHAKE_SIZE 6
56 #define MIN_HANDSHAKE_SIZE 2
57 #else
58 #define MIN_HANDSHAKE_SIZE 6
59 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
60 
61 /*
62  Get structure for logging connection data for the current user
63 */
64 
65 #ifndef NO_EMBEDDED_ACCESS_CHECKS
66 static HASH hash_user_connections;
67 
68 int get_or_create_user_conn(THD *thd, const char *user,
69  const char *host,
70  const USER_RESOURCES *mqh)
71 {
72  int return_val= 0;
73  size_t temp_len, user_len;
74  char temp_user[USER_HOST_BUFF_SIZE];
75  struct user_conn *uc;
76 
77  DBUG_ASSERT(user != 0);
78  DBUG_ASSERT(host != 0);
79 
80  user_len= strlen(user);
81  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
82  mysql_mutex_lock(&LOCK_user_conn);
83  if (!(uc = (struct user_conn *) my_hash_search(&hash_user_connections,
84  (uchar*) temp_user, temp_len)))
85  {
86  /* First connection for user; Create a user connection object */
87  if (!(uc= ((struct user_conn*)
88  my_malloc(sizeof(struct user_conn) + temp_len+1,
89  MYF(MY_WME)))))
90  {
91  /* MY_WME ensures an error is set in THD. */
92  return_val= 1;
93  goto end;
94  }
95  uc->user=(char*) (uc+1);
96  memcpy(uc->user,temp_user,temp_len+1);
97  uc->host= uc->user + user_len + 1;
98  uc->len= temp_len;
99  uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
100  uc->user_resources= *mqh;
101  uc->reset_utime= thd->thr_create_utime;
102  if (my_hash_insert(&hash_user_connections, (uchar*) uc))
103  {
104  /* The only possible error is out of memory, MY_WME sets an error. */
105  my_free(uc);
106  return_val= 1;
107  goto end;
108  }
109  }
110  thd->set_user_connect(uc);
111  thd->increment_user_connections_counter();
112 end:
113  mysql_mutex_unlock(&LOCK_user_conn);
114  return return_val;
115 
116 }
117 
118 
119 /*
120  check if user has already too many connections
121 
122  SYNOPSIS
123  check_for_max_user_connections()
124  thd Thread handle
125  uc User connect object
126 
127  NOTES
128  If check fails, we decrease user connection count, which means one
129  shouldn't call decrease_user_connections() after this function.
130 
131  RETURN
132  0 ok
133  1 error
134 */
135 
136 int check_for_max_user_connections(THD *thd, const USER_CONN *uc)
137 {
138  int error=0;
140  DBUG_ENTER("check_for_max_user_connections");
141 
142  mysql_mutex_lock(&LOCK_user_conn);
143  if (global_system_variables.max_user_connections &&
144  !uc->user_resources.user_conn &&
145  global_system_variables.max_user_connections < (uint) uc->connections)
146  {
147  my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user);
148  error=1;
149  errors.m_max_user_connection= 1;
150  goto end;
151  }
152  thd->time_out_user_resource_limits();
153  if (uc->user_resources.user_conn &&
154  uc->user_resources.user_conn < uc->connections)
155  {
156  my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user,
157  "max_user_connections",
158  (long) uc->user_resources.user_conn);
159  error= 1;
160  errors.m_max_user_connection= 1;
161  goto end;
162  }
163  if (uc->user_resources.conn_per_hour &&
164  uc->user_resources.conn_per_hour <= uc->conn_per_hour)
165  {
166  my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user,
167  "max_connections_per_hour",
168  (long) uc->user_resources.conn_per_hour);
169  error=1;
171  goto end;
172  }
173  thd->increment_con_per_hour_counter();
174 
175 end:
176  if (error)
177  {
178  thd->decrement_user_connections_counter();
179  /*
180  The thread may returned back to the pool and assigned to a user
181  that doesn't have a limit. Ensure the user is not using resources
182  of someone else.
183  */
184  thd->set_user_connect(NULL);
185  }
186  mysql_mutex_unlock(&LOCK_user_conn);
187  if (error)
188  {
189  inc_host_errors(thd->main_security_ctx.get_ip()->ptr(), &errors);
190  }
191  DBUG_RETURN(error);
192 }
193 
194 
195 /*
196  Decrease user connection count
197 
198  SYNOPSIS
199  decrease_user_connections()
200  uc User connection object
201 
202  NOTES
203  If there is a n user connection object for a connection
204  (which only happens if 'max_user_connections' is defined or
205  if someone has created a resource grant for a user), then
206  the connection count is always incremented on connect.
207 
208  The user connect object is not freed if some users has
209  'max connections per hour' defined as we need to be able to hold
210  count over the lifetime of the connection.
211 */
212 
213 void decrease_user_connections(USER_CONN *uc)
214 {
215  DBUG_ENTER("decrease_user_connections");
216  mysql_mutex_lock(&LOCK_user_conn);
217  DBUG_ASSERT(uc->connections);
218  if (!--uc->connections && !mqh_used)
219  {
220  /* Last connection for user; Delete it */
221  (void) my_hash_delete(&hash_user_connections,(uchar*) uc);
222  }
223  mysql_mutex_unlock(&LOCK_user_conn);
224  DBUG_VOID_RETURN;
225 }
226 
227 /*
228  Decrements user connections count from the USER_CONN held by THD
229  And removes USER_CONN from the hash if no body else is using it.
230 
231  SYNOPSIS
232  release_user_connection()
233  THD Thread context object.
234  */
235 void release_user_connection(THD *thd)
236 {
237  const USER_CONN *uc= thd->get_user_connect();
238  DBUG_ENTER("release_user_connection");
239 
240  if (uc)
241  {
242  mysql_mutex_lock(&LOCK_user_conn);
243  DBUG_ASSERT(uc->connections > 0);
244  thd->decrement_user_connections_counter();
245  if (!uc->connections && !mqh_used)
246  {
247  /* Last connection for user; Delete it */
248  (void) my_hash_delete(&hash_user_connections,(uchar*) uc);
249  }
250  mysql_mutex_unlock(&LOCK_user_conn);
251  thd->set_user_connect(NULL);
252  }
253 
254  DBUG_VOID_RETURN;
255 }
256 
257 
258 
259 /*
260  Check if maximum queries per hour limit has been reached
261  returns 0 if OK.
262 */
263 
264 bool check_mqh(THD *thd, uint check_command)
265 {
266  bool error= 0;
267  const USER_CONN *uc=thd->get_user_connect();
268  DBUG_ENTER("check_mqh");
269  DBUG_ASSERT(uc != 0);
270 
271  mysql_mutex_lock(&LOCK_user_conn);
272 
273  thd->time_out_user_resource_limits();
274 
275  /* Check that we have not done too many questions / hour */
276  if (uc->user_resources.questions)
277  {
278  thd->increment_questions_counter();
279  if ((uc->questions - 1) >= uc->user_resources.questions)
280  {
281  my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions",
282  (long) uc->user_resources.questions);
283  error=1;
284  goto end;
285  }
286  }
287  if (check_command < (uint) SQLCOM_END)
288  {
289  /* Check that we have not done too many updates / hour */
290  if (uc->user_resources.updates &&
291  (sql_command_flags[check_command] & CF_CHANGES_DATA))
292  {
293  thd->increment_updates_counter();
294  if ((uc->updates - 1) >= uc->user_resources.updates)
295  {
296  my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates",
297  (long) uc->user_resources.updates);
298  error=1;
299  goto end;
300  }
301  }
302  }
303 end:
304  mysql_mutex_unlock(&LOCK_user_conn);
305  DBUG_RETURN(error);
306 }
307 #else
308 
309 int check_for_max_user_connections(THD *thd, const USER_CONN *uc)
310 {
311  return 0;
312 }
313 
314 void decrease_user_connections(USER_CONN *uc)
315 {
316  return;
317 }
318 
319 void release_user_connection(THD *thd)
320 {
321  const USER_CONN *uc= thd->get_user_connect();
322  DBUG_ENTER("release_user_connection");
323 
324  if (uc)
325  {
326  thd->set_user_connect(NULL);
327  }
328 
329  DBUG_VOID_RETURN;
330 }
331 
332 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
333 
334 /*
335  Check for maximum allowable user connections, if the mysqld server is
336  started with corresponding variable that is greater then 0.
337 */
338 
339 extern "C" uchar *get_key_conn(user_conn *buff, size_t *length,
340  my_bool not_used __attribute__((unused)))
341 {
342  *length= buff->len;
343  return (uchar*) buff->user;
344 }
345 
346 
347 extern "C" void free_user(struct user_conn *uc)
348 {
349  my_free(uc);
350 }
351 
352 
353 void init_max_user_conn(void)
354 {
355 #ifndef NO_EMBEDDED_ACCESS_CHECKS
356  (void)
357  my_hash_init(&hash_user_connections,system_charset_info,max_connections,
358  0,0, (my_hash_get_key) get_key_conn,
359  (my_hash_free_key) free_user, 0);
360 #endif
361 }
362 
363 
364 void free_max_user_conn(void)
365 {
366 #ifndef NO_EMBEDDED_ACCESS_CHECKS
367  my_hash_free(&hash_user_connections);
368 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
369 }
370 
371 
372 void reset_mqh(LEX_USER *lu, bool get_them= 0)
373 {
374 #ifndef NO_EMBEDDED_ACCESS_CHECKS
375  mysql_mutex_lock(&LOCK_user_conn);
376  if (lu) // for GRANT
377  {
378  USER_CONN *uc;
379  uint temp_len=lu->user.length+lu->host.length+2;
380  char temp_user[USER_HOST_BUFF_SIZE];
381 
382  memcpy(temp_user,lu->user.str,lu->user.length);
383  memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
384  temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
385  if ((uc = (struct user_conn *) my_hash_search(&hash_user_connections,
386  (uchar*) temp_user,
387  temp_len)))
388  {
389  uc->questions=0;
390  get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
391  uc->updates=0;
392  uc->conn_per_hour=0;
393  }
394  }
395  else
396  {
397  /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
398  for (uint idx=0;idx < hash_user_connections.records; idx++)
399  {
400  USER_CONN *uc=(struct user_conn *)
401  my_hash_element(&hash_user_connections, idx);
402  if (get_them)
403  get_mqh(uc->user,uc->host,uc);
404  uc->questions=0;
405  uc->updates=0;
406  uc->conn_per_hour=0;
407  }
408  }
409  mysql_mutex_unlock(&LOCK_user_conn);
410 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
411 }
412 
413 
428 bool thd_init_client_charset(THD *thd, uint cs_number)
429 {
430  CHARSET_INFO *cs;
431  /*
432  Use server character set and collation if
433  - opt_character_set_client_handshake is not set
434  - client has not specified a character set
435  - client character set is the same as the servers
436  - client character set doesn't exists in server
437  */
438  if (!opt_character_set_client_handshake ||
439  !(cs= get_charset(cs_number, MYF(0))) ||
440  !my_strcasecmp(&my_charset_latin1,
441  global_system_variables.character_set_client->name,
442  cs->name))
443  {
444  if (!is_supported_parser_charset(
445  global_system_variables.character_set_client))
446  {
447  /* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */
448  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
449  global_system_variables.character_set_client->csname);
450  return true;
451  }
452  thd->variables.character_set_client=
453  global_system_variables.character_set_client;
454  thd->variables.collation_connection=
455  global_system_variables.collation_connection;
456  thd->variables.character_set_results=
457  global_system_variables.character_set_results;
458  }
459  else
460  {
461  if (!is_supported_parser_charset(cs))
462  {
463  /* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */
464  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
465  cs->csname);
466  return true;
467  }
468  thd->variables.character_set_results=
469  thd->variables.collation_connection=
470  thd->variables.character_set_client= cs;
471  }
472  return false;
473 }
474 
475 
476 /*
477  Initialize connection threads
478 */
479 
480 bool init_new_connection_handler_thread()
481 {
482  pthread_detach_this_thread();
483  if (my_thread_init())
484  {
485  statistic_increment(connection_errors_internal, &LOCK_status);
486  return 1;
487  }
488  return 0;
489 }
490 
491 #ifndef EMBEDDED_LIBRARY
492 /*
493  Perform handshake, authorize client and update thd ACL variables.
494 
495  SYNOPSIS
496  check_connection()
497  thd thread handle
498 
499  RETURN
500  0 success, thd is updated.
501  1 error
502 */
503 
504 static int check_connection(THD *thd)
505 {
506  uint connect_errors= 0;
507  int auth_rc;
508  NET *net= &thd->net;
509 
510  DBUG_PRINT("info",
511  ("New connection received on %s", vio_description(net->vio)));
512 #ifdef SIGNAL_WITH_VIO_SHUTDOWN
513  thd->set_active_vio(net->vio);
514 #endif
515 
516  if (!thd->main_security_ctx.get_host()->length()) // If TCP/IP connection
517  {
518  my_bool peer_rc;
519  char ip[NI_MAXHOST];
520 
521  peer_rc= vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST);
522 
523  /*
524  ===========================================================================
525  DEBUG code only (begin)
526  Simulate various output from vio_peer_addr().
527  ===========================================================================
528  */
529 
530  DBUG_EXECUTE_IF("vio_peer_addr_error",
531  {
532  peer_rc= 1;
533  }
534  );
535  DBUG_EXECUTE_IF("vio_peer_addr_fake_ipv4",
536  {
537  struct sockaddr *sa= (sockaddr *) &net->vio->remote;
538  sa->sa_family= AF_INET;
539  struct in_addr *ip4= &((struct sockaddr_in *) sa)->sin_addr;
540  /* See RFC 5737, 192.0.2.0/24 is reserved. */
541  const char* fake= "192.0.2.4";
542  ip4->s_addr= inet_addr(fake);
543  strcpy(ip, fake);
544  peer_rc= 0;
545  }
546  );
547 
548 #ifdef HAVE_IPV6
549  DBUG_EXECUTE_IF("vio_peer_addr_fake_ipv6",
550  {
551  struct sockaddr_in6 *sa= (sockaddr_in6 *) &net->vio->remote;
552  sa->sin6_family= AF_INET6;
553  struct in6_addr *ip6= & sa->sin6_addr;
554  /* See RFC 3849, ipv6 2001:DB8::/32 is reserved. */
555  const char* fake= "2001:db8::6:6";
556  /* inet_pton(AF_INET6, fake, ip6); not available on Windows XP. */
557  ip6->s6_addr[ 0] = 0x20;
558  ip6->s6_addr[ 1] = 0x01;
559  ip6->s6_addr[ 2] = 0x0d;
560  ip6->s6_addr[ 3] = 0xb8;
561  ip6->s6_addr[ 4] = 0x00;
562  ip6->s6_addr[ 5] = 0x00;
563  ip6->s6_addr[ 6] = 0x00;
564  ip6->s6_addr[ 7] = 0x00;
565  ip6->s6_addr[ 8] = 0x00;
566  ip6->s6_addr[ 9] = 0x00;
567  ip6->s6_addr[10] = 0x00;
568  ip6->s6_addr[11] = 0x00;
569  ip6->s6_addr[12] = 0x00;
570  ip6->s6_addr[13] = 0x06;
571  ip6->s6_addr[14] = 0x00;
572  ip6->s6_addr[15] = 0x06;
573  strcpy(ip, fake);
574  peer_rc= 0;
575  }
576  );
577 #endif /* HAVE_IPV6 */
578 
579  /*
580  ===========================================================================
581  DEBUG code only (end)
582  ===========================================================================
583  */
584 
585  if (peer_rc)
586  {
587  /*
588  Since we can not even get the peer IP address,
589  there is nothing to show in the host_cache,
590  so increment the global status variable for peer address errors.
591  */
592  statistic_increment(connection_errors_peer_addr, &LOCK_status);
593  my_error(ER_BAD_HOST_ERROR, MYF(0));
594  return 1;
595  }
596  thd->main_security_ctx.set_ip(my_strdup(ip, MYF(MY_WME)));
597  if (!(thd->main_security_ctx.get_ip()->length()))
598  {
599  /*
600  No error accounting per IP in host_cache,
601  this is treated as a global server OOM error.
602  TODO: remove the need for my_strdup.
603  */
604  statistic_increment(connection_errors_internal, &LOCK_status);
605  return 1; /* The error is set by my_strdup(). */
606  }
607  thd->main_security_ctx.host_or_ip= thd->main_security_ctx.get_ip()->ptr();
608  if (!(specialflag & SPECIAL_NO_RESOLVE))
609  {
610  int rc;
611  char *host= (char *) thd->main_security_ctx.get_host()->ptr();
612 
613  rc= ip_to_hostname(&net->vio->remote,
614  thd->main_security_ctx.get_ip()->ptr(),
615  &host, &connect_errors);
616 
617  thd->main_security_ctx.set_host(host);
618  /* Cut very long hostnames to avoid possible overflows */
619  if (thd->main_security_ctx.get_host()->length())
620  {
621  if (thd->main_security_ctx.get_host()->ptr() != my_localhost)
622  thd->main_security_ctx.set_host(thd->main_security_ctx.get_host()->ptr(),
623  min<size_t>(thd->main_security_ctx.get_host()->length(),
624  HOSTNAME_LENGTH));
625  thd->main_security_ctx.host_or_ip=
626  thd->main_security_ctx.get_host()->ptr();
627  }
628 
629  if (rc == RC_BLOCKED_HOST)
630  {
631  /* HOST_CACHE stats updated by ip_to_hostname(). */
632  my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip);
633  return 1;
634  }
635  }
636  DBUG_PRINT("info",("Host: %s ip: %s",
637  (thd->main_security_ctx.get_host()->length() ?
638  thd->main_security_ctx.get_host()->ptr() : "unknown host"),
639  (thd->main_security_ctx.get_ip()->length() ?
640  thd->main_security_ctx.get_ip()->ptr() : "unknown ip")));
641  if (acl_check_host(thd->main_security_ctx.get_host()->ptr(),
642  thd->main_security_ctx.get_ip()->ptr()))
643  {
644  /* HOST_CACHE stats updated by acl_check_host(). */
645  my_error(ER_HOST_NOT_PRIVILEGED, MYF(0),
646  thd->main_security_ctx.host_or_ip);
647  return 1;
648  }
649  }
650  else /* Hostname given means that the connection was on a socket */
651  {
652  DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.get_host()->ptr()));
653  thd->main_security_ctx.host_or_ip= thd->main_security_ctx.get_host()->ptr();
654  thd->main_security_ctx.set_ip("");
655  /* Reset sin_addr */
656  memset(&net->vio->remote, 0, sizeof(net->vio->remote));
657  }
658  vio_keepalive(net->vio, TRUE);
659 
660  if (thd->packet.alloc(thd->variables.net_buffer_length))
661  {
662  /*
663  Important note:
664  net_buffer_length is a SESSION variable,
665  so it may be tempting to account OOM conditions per IP in the HOST_CACHE,
666  in case some clients are more demanding than others ...
667  However, this session variable is *not* initialized with a per client
668  value during the initial connection, it is initialized from the
669  GLOBAL net_buffer_length variable from the server.
670  Hence, there is no reason to account on OOM conditions per client IP,
671  we count failures in the global server status instead.
672  */
673  statistic_increment(connection_errors_internal, &LOCK_status);
674  return 1; /* The error is set by alloc(). */
675  }
676 
677  auth_rc= acl_authenticate(thd, 0);
678  if (auth_rc == 0 && connect_errors != 0)
679  {
680  /*
681  A client connection from this IP was successful,
682  after some previous failures.
683  Reset the connection error counter.
684  */
685  reset_host_connect_errors(thd->main_security_ctx.get_ip()->ptr());
686  }
687 
688  return auth_rc;
689 }
690 
691 
692 /*
693  Setup thread to be used with the current thread
694 
695  SYNOPSIS
696  bool setup_connection_thread_globals()
697  thd Thread/connection handler
698 
699  RETURN
700  0 ok
701  1 Error (out of memory)
702  In this case we will close the connection and increment status
703 */
704 
705 bool setup_connection_thread_globals(THD *thd)
706 {
707  if (thd->store_globals())
708  {
709  close_connection(thd, ER_OUT_OF_RESOURCES);
710  statistic_increment(aborted_connects,&LOCK_status);
711  MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
712  return 1; // Error
713  }
714  return 0;
715 }
716 
717 
718 /*
719  Autenticate user, with error reporting
720 
721  SYNOPSIS
722  login_connection()
723  thd Thread handler
724 
725  NOTES
726  Connection is not closed in case of errors
727 
728  RETURN
729  0 ok
730  1 error
731 */
732 
733 
734 bool login_connection(THD *thd)
735 {
736  NET *net= &thd->net;
737  int error;
738  DBUG_ENTER("login_connection");
739  DBUG_PRINT("info", ("login_connection called by thread %lu",
740  thd->thread_id));
741 
742  /* Use "connect_timeout" value during connection phase */
743  my_net_set_read_timeout(net, connect_timeout);
744  my_net_set_write_timeout(net, connect_timeout);
745 
746  error= check_connection(thd);
747  thd->protocol->end_statement();
748 
749  if (error)
750  { // Wrong permissions
751 #ifdef _WIN32
752  if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
753  my_sleep(1000); /* must wait after eof() */
754 #endif
755  statistic_increment(aborted_connects,&LOCK_status);
756  DBUG_RETURN(1);
757  }
758  /* Connect completed, set read/write timeouts back to default */
759  my_net_set_read_timeout(net, thd->variables.net_read_timeout);
760  my_net_set_write_timeout(net, thd->variables.net_write_timeout);
761  DBUG_RETURN(0);
762 }
763 
764 
765 /*
766  Close an established connection
767 
768  NOTES
769  This mainly updates status variables
770 */
771 
772 void end_connection(THD *thd)
773 {
774  NET *net= &thd->net;
775  plugin_thdvar_cleanup(thd);
776 
777  /*
778  The thread may returned back to the pool and assigned to a user
779  that doesn't have a limit. Ensure the user is not using resources
780  of someone else.
781  */
782  release_user_connection(thd);
783 
784  if (thd->killed || (net->error && net->vio != 0))
785  {
786  statistic_increment(aborted_threads,&LOCK_status);
787  }
788 
789  if (net->error && net->vio != 0)
790  {
791  if (!thd->killed && log_warnings > 1)
792  {
793  Security_context *sctx= thd->security_ctx;
794 
795  sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
796  thd->thread_id,(thd->db ? thd->db : "unconnected"),
797  sctx->user ? sctx->user : "unauthenticated",
798  sctx->host_or_ip,
799  (thd->get_stmt_da()->is_error() ?
800  thd->get_stmt_da()->message() :
801  ER(ER_UNKNOWN_ERROR)));
802  }
803  }
804 }
805 
806 
807 /*
808  Initialize THD to handle queries
809 */
810 
811 void prepare_new_connection_state(THD* thd)
812 {
813  Security_context *sctx= thd->security_ctx;
814 
815  if (thd->client_capabilities & CLIENT_COMPRESS)
816  thd->net.compress=1; // Use compression
817 
818  /*
819  Much of this is duplicated in create_embedded_thd() for the
820  embedded server library.
821  TODO: refactor this to avoid code duplication there
822  */
823  thd->proc_info= 0;
824  thd->set_command(COM_SLEEP);
825  thd->set_time();
826  thd->init_for_queries();
827 
828  if (opt_init_connect.length && !(sctx->master_access & SUPER_ACL))
829  {
830  execute_init_command(thd, &opt_init_connect, &LOCK_sys_init_connect);
831  if (thd->is_error())
832  {
833  Host_errors errors;
834  ulong packet_length;
835  NET *net= &thd->net;
836 
837  sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
838  thd->thread_id,
839  thd->db ? thd->db : "unconnected",
840  sctx->user ? sctx->user : "unauthenticated",
841  sctx->host_or_ip, "init_connect command failed");
842  sql_print_warning("%s", thd->get_stmt_da()->message());
843 
844  thd->lex->current_select= 0;
845  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
846  thd->clear_error();
847  net_new_transaction(net);
848  packet_length= my_net_read(net);
849  /*
850  If my_net_read() failed, my_error() has been already called,
851  and the main Diagnostics Area contains an error condition.
852  */
853  if (packet_length != packet_error)
854  my_error(ER_NEW_ABORTING_CONNECTION, MYF(0),
855  thd->thread_id,
856  thd->db ? thd->db : "unconnected",
857  sctx->user ? sctx->user : "unauthenticated",
858  sctx->host_or_ip, "init_connect command failed");
859 
860  thd->server_status&= ~SERVER_STATUS_CLEAR_SET;
861  thd->protocol->end_statement();
862  thd->killed = THD::KILL_CONNECTION;
863  errors.m_init_connect= 1;
864  inc_host_errors(thd->main_security_ctx.get_ip()->ptr(), &errors);
865  return;
866  }
867 
868  thd->proc_info=0;
869  thd->set_time();
870  thd->init_for_queries();
871  }
872 }
873 
874 
875 /*
876  Thread handler for a connection
877 
878  SYNOPSIS
879  handle_one_connection()
880  arg Connection object (THD)
881 
882  IMPLEMENTATION
883  This function (normally) does the following:
884  - Initialize thread
885  - Initialize THD to be used with this thread
886  - Authenticate user
887  - Execute all queries sent on the connection
888  - Take connection down
889  - End thread / Handle next connection using thread from thread cache
890 */
891 
892 pthread_handler_t handle_one_connection(void *arg)
893 {
894  THD *thd= (THD*) arg;
895 
896  mysql_thread_set_psi_id(thd->thread_id);
897 
898  do_handle_one_connection(thd);
899  return 0;
900 }
901 
902 bool thd_prepare_connection(THD *thd)
903 {
904  bool rc;
905  lex_start(thd);
906  rc= login_connection(thd);
907  MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
908  if (rc)
909  return rc;
910 
911  MYSQL_CONNECTION_START(thd->thread_id, &thd->security_ctx->priv_user[0],
912  (char *) thd->security_ctx->host_or_ip);
913 
914  prepare_new_connection_state(thd);
915  return FALSE;
916 }
917 
918 bool thd_is_connection_alive(THD *thd)
919 {
920  NET *net= &thd->net;
921  if (!net->error &&
922  net->vio != 0 &&
923  !(thd->killed == THD::KILL_CONNECTION))
924  return TRUE;
925  return FALSE;
926 }
927 
928 void do_handle_one_connection(THD *thd_arg)
929 {
930  THD *thd= thd_arg;
931 
932  thd->thr_create_utime= my_micro_time();
933 
934  if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
935  {
936  close_connection(thd, ER_OUT_OF_RESOURCES);
937  statistic_increment(aborted_connects,&LOCK_status);
938  MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
939  return;
940  }
941 
942  /*
943  If a thread was created to handle this connection:
944  increment slow_launch_threads counter if it took more than
945  slow_launch_time seconds to create the thread.
946  */
947  if (thd->prior_thr_create_utime)
948  {
949  ulong launch_time= (ulong) (thd->thr_create_utime -
950  thd->prior_thr_create_utime);
951  if (launch_time >= slow_launch_time*1000000L)
952  statistic_increment(slow_launch_threads, &LOCK_status);
953  thd->prior_thr_create_utime= 0;
954  }
955 
956  /*
957  handle_one_connection() is normally the only way a thread would
958  start and would always be on the very high end of the stack ,
959  therefore, the thread stack always starts at the address of the
960  first local variable of handle_one_connection, which is thd. We
961  need to know the start of the stack so that we could check for
962  stack overruns.
963  */
964  thd->thread_stack= (char*) &thd;
965  if (setup_connection_thread_globals(thd))
966  return;
967 
968  for (;;)
969  {
970  bool rc;
971 
972  NET *net= &thd->net;
973  mysql_socket_set_thread_owner(net->vio->mysql_socket);
974 
975  rc= thd_prepare_connection(thd);
976  if (rc)
977  goto end_thread;
978 
979  while (thd_is_connection_alive(thd))
980  {
981  mysql_audit_release(thd);
982  if (do_command(thd))
983  break;
984  }
985  end_connection(thd);
986 
987 end_thread:
988  close_connection(thd);
989  if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0))
990  return; // Probably no-threads
991 
992  /*
993  If end_thread() returns, we are either running with
994  thread-handler=no-threads or this thread has been schedule to
995  handle the next connection.
996  */
997  thd= current_thd;
998  thd->thread_stack= (char*) &thd;
999  }
1000 }
1001 #endif /* EMBEDDED_LIBRARY */