Commit 70a627a1 authored by monty@donna.mysql.com's avatar monty@donna.mysql.com
Browse files

Added max_user_connections

parent 96a86081
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -11,7 +11,8 @@ extra_configs="$pentium_configs $debug_configs"
# Use the debug version if it exists
if test -d /usr/local/BerkeleyDB-dbug/
then
 extra_configs="$extra_configs --with-berkeley-db=/usr/local/BerkeleyDB-dbug/ --with-innobase"
 extra_configs="$extra_configs --with-berkeley-db=/usr/local/BerkeleyDB-dbug/"
fi
extra_configs="$extra_configs --with-innobase"

. "$path/FINISH.sh"
+11 −0
Original line number Diff line number Diff line
@@ -9579,6 +9579,7 @@ uses:
@findex command-line options
@cindex options, command-line
@cindex mysqld options
@node Command-line options, Option files, Automatic start, Post-installation
@subsection Command-line Options
@@ -11522,6 +11523,11 @@ in the grant tables. In principle, the @code{--secure} option to
@code{mysqld} should make hostnames safe.  In any case, you should be very
careful about creating grant table entries using hostname values that
contain wild cards!
@item
If you want to restrict the number of connections for a single user, you
can do this by setting the @code{max_user_connections} variable in
@code{mysqld}.
@end itemize
@node Privileges options, What Privileges, Security, Privilege system
@@ -21048,6 +21054,9 @@ The number of bytes to use when sorting @code{BLOB} or @code{TEXT}
values (only the first @code{max_sort_length} bytes of each value
are used; the rest are ignored).
@item @code{max_user_connections}
The maximum number of active connections for a single user (0 = no limit).
@item @code{max_tmp_tables}
(This option doesn't yet do anything.)
Maximum number of temporary tables a client can keep open at the same time.
@@ -41585,6 +41594,8 @@ not yet 100 % confident in this code.
@appendixsubsec Changes in release 3.23.34
@itemize @bullet
@item
Added option @code{max_user_connections} to @code{mysqld}.
@item
Limit query length for replication by max_allowed_packet, not the arbitrary
limit of 4 MB
@item
+33 −20
Original line number Diff line number Diff line
@@ -60,9 +60,9 @@ os_event_create(
	event = ut_malloc(sizeof(struct os_event_struct));

	os_fast_mutex_init(&(event->os_mutex));
	os_fast_mutex_init(&(event->wait_mutex));
	pthread_cond_init(&(event->cond_var), NULL);

	event->is_set = TRUE;
	event->is_set = FALSE;

	return(event);
#endif
@@ -119,8 +119,8 @@ os_event_set(
	if (event->is_set) {
		/* Do nothing */
	} else {
		os_fast_mutex_unlock(&(event->wait_mutex));
		event->is_set = TRUE;
		pthread_cond_broadcast(&(event->cond_var));
	}

	os_fast_mutex_unlock(&(event->os_mutex));
@@ -148,7 +148,6 @@ os_event_reset(
	if (!event->is_set) {
		/* Do nothing */
	} else {
		os_fast_mutex_lock(&(event->wait_mutex));
		event->is_set = FALSE;
	}

@@ -173,7 +172,7 @@ os_event_free(
	ut_a(event);

	os_fast_mutex_free(&(event->os_mutex));
	os_fast_mutex_free(&(event->wait_mutex));
	pthread_cond_destroy(&(event->cond_var));

	ut_free(event);
#endif
@@ -197,8 +196,22 @@ os_event_wait(

	ut_a(err == WAIT_OBJECT_0);
#else
	os_fast_mutex_lock(&(event->wait_mutex));
	os_fast_mutex_unlock(&(event->wait_mutex));
	os_fast_mutex_lock(&(event->os_mutex));
loop:
	if (event->is_set == TRUE) {
		os_fast_mutex_unlock(&(event->os_mutex));

		/* Ok, we may return */

		return;
	}

	pthread_cond_wait(&(event->cond_var), &(event->os_mutex));

	/* Solaris manual said that spurious wakeups may occur: we have
	to check the 'is_set' variable again */

	goto loop;
#endif
}

+1 −1
Original line number Diff line number Diff line
@@ -521,7 +521,7 @@ extern uint protocol_version,dropping_tables;
extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
	     max_join_size,join_buff_size,tmp_table_size,
	     max_connections,max_connect_errors,long_query_time,
	     max_insert_delayed_threads,
	     max_insert_delayed_threads, max_user_connections,
	     long_query_count,net_wait_timeout,net_interactive_timeout,
	     net_read_timeout,net_write_timeout,
	     what_to_log,flush_time,
+131 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <thr_alarm.h>
#include <myisam.h>
#include <my_dir.h>
#include <assert.h>

#define SCRAMBLE_LENGTH 8

@@ -32,6 +33,9 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
extern "C" int gethostname(char *name, int namelen);
#endif

static int check_for_max_user_connections(const char *user, int u_length,
					  const char *host);
static void decrease_user_connections(const char *user, const char *host);
static bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
@@ -145,13 +149,134 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
		  thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
		  db ? db : (char*) "");
  thd->db_access=0;
  if (max_user_connections &&
      check_for_max_user_connections(user, strlen(user), thd->host))
    return -1;
  if (db && db[0])
    return test(mysql_change_db(thd,db));
  {
    bool error=test(mysql_change_db(thd,db));
    if (error)
      decrease_user_connections(user,thd->host);
    return error;
  }
  else
    send_ok(net);				// Ready to handle questions
  return 0;					// ok
}

/*
** check for maximum allowable user connections
** if mysql server is started with corresponding
** variable that is greater then 0
*/

static HASH hash_user_connections;
static DYNAMIC_ARRAY  user_conn_array;
extern  pthread_mutex_t LOCK_user_conn;

struct  user_conn {
  char user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  int connections, len;
};

static byte* get_key_conn(user_conn *buff, uint *length,
			  my_bool not_used __attribute__((unused)))
{
  *length=buff->len;
  return (byte*) buff->user;
}

#define DEF_USER_COUNT 50

void init_max_user_conn(void) 
{
  (void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
		   (hash_get_key) get_key_conn,0, 0);
  (void) init_dynamic_array(&user_conn_array,sizeof(user_conn),
			    DEF_USER_COUNT, DEF_USER_COUNT);
}


static int check_for_max_user_connections(const char *user, int u_length,
					  const char *host) 
{
  uint temp_len;
  char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  struct  user_conn *uc;
  if (!user)
    user="";
  if (!host)
    host="";
  temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
			     NullS) - temp_user);
  (void) pthread_mutex_lock(&LOCK_user_conn);
  uc = (struct  user_conn *) hash_search(&hash_user_connections,
					 (byte*) temp_user, temp_len);
  if (uc) /* user found ; check for no. of connections */
  {
    if (max_user_connections ==  uc->connections) 
    {
      net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, temp_user);
      pthread_mutex_unlock(&LOCK_user_conn);
      return 1;
    }
    uc->connections++; 
  }
  else
  {
    /* the user is not found in the cache; Insert it */
    struct user_conn uc;
    memcpy(uc.user,temp_user,temp_len+1);
    uc.len = temp_len;
    uc.connections = 1;
    if (!insert_dynamic(&user_conn_array, (char *) &uc))
    {
      hash_insert(&hash_user_connections,
		  (byte *) dynamic_array_ptr(&user_conn_array,
					     user_conn_array.elements - 1));
    }
  }
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return 0;
}


static void decrease_user_connections(const char *user, const char *host)
{
  char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  int temp_len;
  struct user_conn uucc, *uc;
  if (!user)
    user="";
  if (!host)
    host="";
  temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
			     NullS) - temp_user);
  (void) pthread_mutex_lock(&LOCK_user_conn);

  uc = (struct  user_conn *) hash_search(&hash_user_connections,
					 (byte*) temp_user, temp_len);
  dbug_assert(uc != 0);			// We should always find the user
  if (!uc)
    goto end;				// Safety; Something went wrong
  if (! --uc->connections)
  {
    /* Last connection for user; Delete it */
    (void) hash_delete(&hash_user_connections,(char *) uc);
    uint element= ((uint) ((byte*) uc - (byte*) user_conn_array.buffer) /
		   user_conn_array.size_of_element);
    delete_dynamic_element(&user_conn_array,element);
  }
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
}

void free_max_user_conn(void)
{
  delete_dynamic(&user_conn_array);
  hash_free(&hash_user_connections);
}


/*
** check connnetion and get priviliges
@@ -417,6 +542,8 @@ pthread_handler_decl(handle_one_connection,arg)
      thread_safe_increment(aborted_threads,&LOCK_thread_count);
    }

    if (max_user_connections)
      decrease_user_connections(thd->user,thd->host);
end_thread:
    close_connection(net);
    end_thread(thd,1);
@@ -652,6 +779,7 @@ bool do_command(THD *thd)
      thd->priv_user=save_priv_user;
      break;
    }
    decrease_user_connections (save_user, thd->host);
    x_free((gptr) save_db);
    x_free((gptr) save_user);
    thd->password=test(passwd[0]);