~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_connect.cc

  • Committer: Mats Kindahl
  • Date: 2008-08-26 07:32:59 UTC
  • mto: (489.1.2 codestyle)
  • mto: This revision was merged to the branch mainline in revision 491.
  • Revision ID: mats@mysql.com-20080826073259-9k4evtajgldgolli
Replaced use of thd_proc_info() macro with calls to
set_proc_info() and get_proc_info() internally.  Introduced
functions set_thd_proc_info() and get_thd_proc_info() for
external users, i.e., plug-ins.

The set_thd_proc_info() accepted callers info that can be used to
print debug output, but the information was not used. The return
value was changed to void and the old value is not fetched any
more. To be able to get the value of proc_info for external
users, the function get_thd_proc_info() was introduced.

The thd_proc_info() macro called set_thd_proc_info() but almost
never used the return value of set_thd_proc_info() so the macro
was replaced with a call of THD::set_proc_info().

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2007 MySQL AB
 
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 as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/*
 
18
  Functions to autenticate and handle reqests for a connection
 
19
*/
 
20
#include <drizzled/server_includes.h>
 
21
#include <drizzled/authentication.h>
 
22
#include <drizzled/drizzled_error_messages.h>
 
23
 
 
24
#define MIN_HANDSHAKE_SIZE      6
 
25
 
 
26
/*
 
27
  Get structure for logging connection data for the current user
 
28
*/
 
29
 
 
30
char *ip_to_hostname(struct sockaddr_storage *in, int addrLen)
 
31
{
 
32
  char *name;
 
33
 
 
34
  int gxi_error;
 
35
  char hostname_buff[NI_MAXHOST];
 
36
 
 
37
  /* Historical comparison for 127.0.0.1 */
 
38
  gxi_error= getnameinfo((struct sockaddr *)in, addrLen,
 
39
                         hostname_buff, NI_MAXHOST,
 
40
                         NULL, 0, NI_NUMERICHOST);
 
41
  if (gxi_error)
 
42
  {
 
43
    return NULL;
 
44
  }
 
45
 
 
46
  if (!(name= my_strdup(hostname_buff, MYF(0))))
 
47
  {
 
48
    return NULL;
 
49
  }
 
50
 
 
51
  return NULL;
 
52
}
 
53
 
 
54
/**
 
55
  Check if user exist and password supplied is correct.
 
56
 
 
57
  @param  thd         thread handle, thd->security_ctx->{host,user,ip} are used
 
58
  @param  command     originator of the check: now check_user is called
 
59
                      during connect and change user procedures; used for
 
60
                      logging.
 
61
  @param  passwd      scrambled password received from client
 
62
  @param  passwd_len  length of scrambled password
 
63
  @param  db          database name to connect to, may be NULL
 
64
  @param  check_count true if establishing a new connection. In this case
 
65
                      check that we have not exceeded the global
 
66
                      max_connections limist
 
67
 
 
68
  @note Host, user and passwd may point to communication buffer.
 
69
  Current implementation does not depend on that, but future changes
 
70
  should be done with this in mind; 'thd' is INOUT, all other params
 
71
  are 'IN'.
 
72
 
 
73
  @retval  0  OK
 
74
  @retval  1  error, e.g. access denied or handshake error, not sent to
 
75
              the client. A message is pushed into the error stack.
 
76
*/
 
77
 
 
78
int
 
79
check_user(THD *thd, enum enum_server_command command,
 
80
           const char *passwd,
 
81
           uint passwd_len, const char *db,
 
82
           bool check_count)
 
83
{
 
84
  LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
 
85
  bool is_authenticated;
 
86
 
 
87
  /*
 
88
    Clear thd->db as it points to something, that will be freed when
 
89
    connection is closed. We don't want to accidentally free a wrong
 
90
    pointer if connect failed. Also in case of 'CHANGE USER' failure,
 
91
    current database will be switched to 'no database selected'.
 
92
  */
 
93
  thd->reset_db(NULL, 0);
 
94
 
 
95
  if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
 
96
  {
 
97
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.ip);
 
98
    return(1);
 
99
  }
 
100
 
 
101
  is_authenticated= authenticate_user(thd, passwd);
 
102
 
 
103
  if (is_authenticated != true)
 
104
  {
 
105
    my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
 
106
             thd->main_security_ctx.user,
 
107
             thd->main_security_ctx.ip,
 
108
             passwd_len ? ER(ER_YES) : ER(ER_NO));
 
109
 
 
110
    return 1;
 
111
  }
 
112
 
 
113
 
 
114
  USER_RESOURCES ur;
 
115
  thd->security_ctx->skip_grants();
 
116
  memset(&ur, 0, sizeof(USER_RESOURCES));
 
117
 
 
118
  if (check_count)
 
119
  {
 
120
    pthread_mutex_lock(&LOCK_connection_count);
 
121
    bool count_ok= connection_count <= max_connections;
 
122
    VOID(pthread_mutex_unlock(&LOCK_connection_count));
 
123
 
 
124
    if (!count_ok)
 
125
    {                                         // too many connections
 
126
      my_error(ER_CON_COUNT_ERROR, MYF(0));
 
127
      return(1);
 
128
    }
 
129
  }
 
130
 
 
131
  /*
 
132
    Log the command before authentication checks, so that the user can
 
133
    check the log for the tried login tried and also to detect
 
134
    break-in attempts.
 
135
  */
 
136
  general_log_print(thd, command,
 
137
                    ((char*) "%s@%s on %s"),
 
138
                    thd->main_security_ctx.user,
 
139
                    thd->main_security_ctx.ip,
 
140
                    db ? db : (char*) "");
 
141
 
 
142
  /* Change database if necessary */
 
143
  if (db && db[0])
 
144
  {
 
145
    if (mysql_change_db(thd, &db_str, false))
 
146
    {
 
147
      /* mysql_change_db() has pushed the error message. */
 
148
      return(1);
 
149
    }
 
150
  }
 
151
  my_ok(thd);
 
152
  thd->password= test(passwd_len);          // remember for error messages 
 
153
  /* Ready to handle queries */
 
154
  return(0);
 
155
}
 
156
 
 
157
 
 
158
/*
 
159
  Check for maximum allowable user connections, if the mysqld server is
 
160
  started with corresponding variable that is greater then 0.
 
161
*/
 
162
 
 
163
extern "C" uchar *get_key_conn(user_conn *buff, size_t *length,
 
164
                               bool not_used __attribute__((unused)))
 
165
{
 
166
  *length= buff->len;
 
167
  return (uchar*) buff->user;
 
168
}
 
169
 
 
170
 
 
171
extern "C" void free_user(struct user_conn *uc)
 
172
{
 
173
  my_free((char*) uc,MYF(0));
 
174
}
 
175
 
 
176
void thd_init_client_charset(THD *thd, uint cs_number)
 
177
{
 
178
  /*
 
179
   Use server character set and collation if
 
180
   - opt_character_set_client_handshake is not set
 
181
   - client has not specified a character set
 
182
   - client character set is the same as the servers
 
183
   - client character set doesn't exists in server
 
184
  */
 
185
  if (!opt_character_set_client_handshake ||
 
186
      !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
 
187
      !my_strcasecmp(&my_charset_latin1,
 
188
                     global_system_variables.character_set_client->name,
 
189
                     thd->variables.character_set_client->name))
 
190
  {
 
191
    thd->variables.character_set_client=
 
192
      global_system_variables.character_set_client;
 
193
    thd->variables.collation_connection=
 
194
      global_system_variables.collation_connection;
 
195
    thd->variables.character_set_results=
 
196
      global_system_variables.character_set_results;
 
197
  }
 
198
  else
 
199
  {
 
200
    thd->variables.character_set_results=
 
201
      thd->variables.collation_connection= 
 
202
      thd->variables.character_set_client;
 
203
  }
 
204
}
 
205
 
 
206
 
 
207
/*
 
208
  Initialize connection threads
 
209
*/
 
210
 
 
211
bool init_new_connection_handler_thread()
 
212
{
 
213
  pthread_detach_this_thread();
 
214
  /* Win32 calls this in pthread_create */
 
215
  if (my_thread_init())
 
216
    return 1;
 
217
  return 0;
 
218
}
 
219
 
 
220
/*
 
221
  Perform handshake, authorize client and update thd ACL variables.
 
222
 
 
223
  SYNOPSIS
 
224
    check_connection()
 
225
    thd  thread handle
 
226
 
 
227
  RETURN
 
228
     0  success, OK is sent to user, thd is updated.
 
229
    -1  error, which is sent to user
 
230
   > 0  error code (not sent to user)
 
231
*/
 
232
 
 
233
static int check_connection(THD *thd)
 
234
{
 
235
  NET *net= &thd->net;
 
236
  uint32_t pkt_len= 0;
 
237
  char *end;
 
238
 
 
239
#ifdef SIGNAL_WITH_VIO_CLOSE
 
240
  thd->set_active_vio(net->vio);
 
241
#endif
 
242
 
 
243
  // TCP/IP connection
 
244
  {
 
245
    char ip[NI_MAXHOST];
 
246
 
 
247
    if (vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST))
 
248
    {
 
249
      my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.ip);
 
250
      return 1;
 
251
    }
 
252
    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
 
253
      return 1; /* The error is set by my_strdup(). */
 
254
  }
 
255
  vio_keepalive(net->vio, true);
 
256
  
 
257
  uint32_t server_capabilites;
 
258
  {
 
259
    /* buff[] needs to big enough to hold the server_version variable */
 
260
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
 
261
    server_capabilites= CLIENT_BASIC_FLAGS;
 
262
 
 
263
    if (opt_using_transactions)
 
264
      server_capabilites|= CLIENT_TRANSACTIONS;
 
265
#ifdef HAVE_COMPRESS
 
266
    server_capabilites|= CLIENT_COMPRESS;
 
267
#endif /* HAVE_COMPRESS */
 
268
 
 
269
    end= stpncpy(buff, server_version, SERVER_VERSION_LENGTH) + 1;
 
270
    int4store((uchar*) end, thd->thread_id);
 
271
    end+= 4;
 
272
    /*
 
273
      So as check_connection is the only entry point to authorization
 
274
      procedure, scramble is set here. This gives us new scramble for
 
275
      each handshake.
 
276
    */
 
277
    create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
 
278
    /*
 
279
      Old clients does not understand long scrambles, but can ignore packet
 
280
      tail: that's why first part of the scramble is placed here, and second
 
281
      part at the end of packet.
 
282
    */
 
283
    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
 
284
   
 
285
    int2store(end, server_capabilites);
 
286
    /* write server characteristics: up to 16 bytes allowed */
 
287
    end[2]=(char) default_charset_info->number;
 
288
    int2store(end+3, thd->server_status);
 
289
    memset(end+5, 0, 13);
 
290
    end+= 18;
 
291
    /* write scramble tail */
 
292
    end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, 
 
293
                 SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
 
294
 
 
295
    /* At this point we write connection message and read reply */
 
296
    if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0,
 
297
                          (uchar*) buff, (size_t) (end-buff)) ||
 
298
        (pkt_len= my_net_read(net)) == packet_error ||
 
299
        pkt_len < MIN_HANDSHAKE_SIZE)
 
300
    {
 
301
      my_error(ER_HANDSHAKE_ERROR, MYF(0),
 
302
               thd->main_security_ctx.ip);
 
303
      return 1;
 
304
    }
 
305
  }
 
306
  if (thd->packet.alloc(thd->variables.net_buffer_length))
 
307
    return 1; /* The error is set by alloc(). */
 
308
 
 
309
  thd->client_capabilities= uint2korr(net->read_pos);
 
310
 
 
311
 
 
312
  thd->client_capabilities|= ((uint32_t) uint2korr(net->read_pos+2)) << 16;
 
313
  thd->max_client_packet_length= uint4korr(net->read_pos+4);
 
314
  thd_init_client_charset(thd, (uint) net->read_pos[8]);
 
315
  thd->update_charset();
 
316
  end= (char*) net->read_pos+32;
 
317
 
 
318
  /*
 
319
    Disable those bits which are not supported by the server.
 
320
    This is a precautionary measure, if the client lies. See Bug#27944.
 
321
  */
 
322
  thd->client_capabilities&= server_capabilites;
 
323
 
 
324
  if (end >= (char*) net->read_pos+ pkt_len +2)
 
325
  {
 
326
 
 
327
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.ip);
 
328
    return 1;
 
329
  }
 
330
 
 
331
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
 
332
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
 
333
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
 
334
      opt_using_transactions)
 
335
    net->return_status= &thd->server_status;
 
336
 
 
337
  char *user= end;
 
338
  char *passwd= strend(user)+1;
 
339
  uint user_len= passwd - user - 1;
 
340
  char *db= passwd;
 
341
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
 
342
  char user_buff[USERNAME_LENGTH + 1];  // buffer to store user in utf8
 
343
  uint dummy_errors;
 
344
 
 
345
  /*
 
346
    Old clients send null-terminated string as password; new clients send
 
347
    the size (1 byte) + string (not null-terminated). Hence in case of empty
 
348
    password both send '\0'.
 
349
 
 
350
    This strlen() can't be easily deleted without changing protocol.
 
351
 
 
352
    Cast *passwd to an unsigned char, so that it doesn't extend the sign for
 
353
    *passwd > 127 and become 2**32-127+ after casting to uint.
 
354
  */
 
355
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
 
356
    (uchar)(*passwd++) : strlen(passwd);
 
357
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
 
358
    db + passwd_len + 1 : 0;
 
359
  /* strlen() can't be easily deleted without changing protocol */
 
360
  uint db_len= db ? strlen(db) : 0;
 
361
 
 
362
  if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
 
363
  {
 
364
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.ip);
 
365
    return 1;
 
366
  }
 
367
 
 
368
  /* Since 4.1 all database names are stored in utf8 */
 
369
  if (db)
 
370
  {
 
371
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
 
372
                             system_charset_info,
 
373
                             db, db_len,
 
374
                             thd->charset(), &dummy_errors)]= 0;
 
375
    db= db_buff;
 
376
  }
 
377
 
 
378
  user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
 
379
                                       system_charset_info, user, user_len,
 
380
                                       thd->charset(), &dummy_errors)]= '\0';
 
381
  user= user_buff;
 
382
 
 
383
  /* If username starts and ends in "'", chop them off */
 
384
  if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
 
385
  {
 
386
    user[user_len-1]= 0;
 
387
    user++;
 
388
    user_len-= 2;
 
389
  }
 
390
 
 
391
  if (thd->main_security_ctx.user)
 
392
    x_free(thd->main_security_ctx.user);
 
393
  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
 
394
    return 1; /* The error is set by my_strdup(). */
 
395
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
 
396
}
 
397
 
 
398
 
 
399
/*
 
400
  Setup thread to be used with the current thread
 
401
 
 
402
  SYNOPSIS
 
403
    bool setup_connection_thread_globals()
 
404
    thd    Thread/connection handler
 
405
 
 
406
  RETURN
 
407
    0   ok
 
408
    1   Error (out of memory)
 
409
        In this case we will close the connection and increment status
 
410
*/
 
411
 
 
412
bool setup_connection_thread_globals(THD *thd)
 
413
{
 
414
  if (thd->store_globals())
 
415
  {
 
416
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
 
417
    statistic_increment(aborted_connects,&LOCK_status);
 
418
    thread_scheduler.end_thread(thd, 0);
 
419
    return 1;                                   // Error
 
420
  }
 
421
  return 0;
 
422
}
 
423
 
 
424
 
 
425
/*
 
426
  Autenticate user, with error reporting
 
427
 
 
428
  SYNOPSIS
 
429
   login_connection()
 
430
   thd        Thread handler
 
431
 
 
432
  NOTES
 
433
    Connection is not closed in case of errors
 
434
 
 
435
  RETURN
 
436
    0    ok
 
437
    1    error
 
438
*/
 
439
 
 
440
 
 
441
bool login_connection(THD *thd)
 
442
{
 
443
  NET *net= &thd->net;
 
444
  int error;
 
445
 
 
446
  /* Use "connect_timeout" value during connection phase */
 
447
  my_net_set_read_timeout(net, connect_timeout);
 
448
  my_net_set_write_timeout(net, connect_timeout);
 
449
  
 
450
  lex_start(thd);
 
451
 
 
452
  error= check_connection(thd);
 
453
  net_end_statement(thd);
 
454
 
 
455
  if (error)
 
456
  {                                             // Wrong permissions
 
457
    statistic_increment(aborted_connects,&LOCK_status);
 
458
    return(1);
 
459
  }
 
460
  /* Connect completed, set read/write timeouts back to default */
 
461
  my_net_set_read_timeout(net, thd->variables.net_read_timeout);
 
462
  my_net_set_write_timeout(net, thd->variables.net_write_timeout);
 
463
  return(0);
 
464
}
 
465
 
 
466
 
 
467
/*
 
468
  Close an established connection
 
469
 
 
470
  NOTES
 
471
    This mainly updates status variables
 
472
*/
 
473
 
 
474
void end_connection(THD *thd)
 
475
{
 
476
  NET *net= &thd->net;
 
477
  plugin_thdvar_cleanup(thd);
 
478
 
 
479
  if (thd->killed || (net->error && net->vio != 0))
 
480
  {
 
481
    statistic_increment(aborted_threads,&LOCK_status);
 
482
  }
 
483
 
 
484
  if (net->error && net->vio != 0)
 
485
  {
 
486
    if (!thd->killed && thd->variables.log_warnings > 1)
 
487
    {
 
488
      Security_context *sctx= thd->security_ctx;
 
489
 
 
490
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
 
491
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
 
492
                        sctx->user ? sctx->user : "unauthenticated",
 
493
                        sctx->ip,
 
494
                        (thd->main_da.is_error() ? thd->main_da.message() :
 
495
                         ER(ER_UNKNOWN_ERROR)));
 
496
    }
 
497
  }
 
498
}
 
499
 
 
500
 
 
501
/*
 
502
  Initialize THD to handle queries
 
503
*/
 
504
 
 
505
void prepare_new_connection_state(THD* thd)
 
506
{
 
507
  Security_context *sctx= thd->security_ctx;
 
508
 
 
509
  if (thd->variables.max_join_size == HA_POS_ERROR)
 
510
    thd->options |= OPTION_BIG_SELECTS;
 
511
  if (thd->client_capabilities & CLIENT_COMPRESS)
 
512
    thd->net.compress=1;                                // Use compression
 
513
 
 
514
  /*
 
515
    Much of this is duplicated in create_embedded_thd() for the
 
516
    embedded server library.
 
517
    TODO: refactor this to avoid code duplication there
 
518
  */
 
519
  thd->version= refresh_version;
 
520
  thd->set_proc_info(0);
 
521
  thd->command= COM_SLEEP;
 
522
  thd->set_time();
 
523
  thd->init_for_queries();
 
524
 
 
525
  /* In the past this would only run of the user did not have SUPER_ACL */
 
526
  if (sys_init_connect.value_length)
 
527
  {
 
528
    execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
 
529
    if (thd->is_error())
 
530
    {
 
531
      thd->killed= THD::KILL_CONNECTION;
 
532
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
 
533
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
 
534
                        sctx->user ? sctx->user : "unauthenticated",
 
535
                        sctx->ip, "init_connect command failed");
 
536
      sql_print_warning("%s", thd->main_da.message());
 
537
    }
 
538
    thd->set_proc_info(0);
 
539
    thd->set_time();
 
540
    thd->init_for_queries();
 
541
  }
 
542
}
 
543
 
 
544
 
 
545
/*
 
546
  Thread handler for a connection
 
547
 
 
548
  SYNOPSIS
 
549
    handle_one_connection()
 
550
    arg         Connection object (THD)
 
551
 
 
552
  IMPLEMENTATION
 
553
    This function (normally) does the following:
 
554
    - Initialize thread
 
555
    - Initialize THD to be used with this thread
 
556
    - Authenticate user
 
557
    - Execute all queries sent on the connection
 
558
    - Take connection down
 
559
    - End thread  / Handle next connection using thread from thread cache
 
560
*/
 
561
 
 
562
pthread_handler_t handle_one_connection(void *arg)
 
563
{
 
564
  THD *thd= (THD*) arg;
 
565
  uint32_t launch_time= (uint32_t) ((thd->thr_create_utime= my_micro_time()) -
 
566
                              thd->connect_utime);
 
567
 
 
568
  if (thread_scheduler.init_new_connection_thread())
 
569
  {
 
570
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
 
571
    statistic_increment(aborted_connects,&LOCK_status);
 
572
    thread_scheduler.end_thread(thd,0);
 
573
    return 0;
 
574
  }
 
575
  if (launch_time >= slow_launch_time*1000000L)
 
576
    statistic_increment(slow_launch_threads,&LOCK_status);
 
577
 
 
578
  /*
 
579
    handle_one_connection() is normally the only way a thread would
 
580
    start and would always be on the very high end of the stack ,
 
581
    therefore, the thread stack always starts at the address of the
 
582
    first local variable of handle_one_connection, which is thd. We
 
583
    need to know the start of the stack so that we could check for
 
584
    stack overruns.
 
585
  */
 
586
  thd->thread_stack= (char*) &thd;
 
587
  if (setup_connection_thread_globals(thd))
 
588
    return 0;
 
589
 
 
590
  for (;;)
 
591
  {
 
592
    NET *net= &thd->net;
 
593
 
 
594
    if (login_connection(thd))
 
595
      goto end_thread;
 
596
 
 
597
    prepare_new_connection_state(thd);
 
598
 
 
599
    while (!net->error && net->vio != 0 &&
 
600
           !(thd->killed == THD::KILL_CONNECTION))
 
601
    {
 
602
      if (do_command(thd))
 
603
        break;
 
604
    }
 
605
    end_connection(thd);
 
606
   
 
607
end_thread:
 
608
    close_connection(thd, 0, 1);
 
609
    if (thread_scheduler.end_thread(thd,1))
 
610
      return 0;                                 // Probably no-threads
 
611
 
 
612
    /*
 
613
      If end_thread() returns, we are either running with
 
614
      thread-handler=no-threads or this thread has been schedule to
 
615
      handle the next connection.
 
616
    */
 
617
    thd= current_thd;
 
618
    thd->thread_stack= (char*) &thd;
 
619
  }
 
620
}