/* * Copyright (c) 2000 * SWsoft company * * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * Permission to use or copy this software for any purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * */ #include "my_global.h" #include "mysql_embed.h" #include "my_pthread.h" #include "sys/types.h" #include "../regex/regex.h" #include "my_sys.h" /* The following is needed to not cause conflicts when we include mysqld.cc */ #define main main1 #define mysql_unix_port mysql_inix_port1 #define mysql_port mysql_port1 #define net_read_timeout net_read_timeout1 #define net_write_timeout net_write_timeout1 #define changeable_vars changeable_vars1 extern "C" { #include "mysql_com.h" #include "lib_vio.c" } class THD; static int check_connections1(THD * thd); static int check_connections2(THD * thd); static bool check_user(THD *thd, enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count); void free_defaults_internal(char ** argv) {if (argv) free_defaults(argv);} #define free_defaults free_defaults_internal char mysql_data_home[FN_REFLEN]; char * get_mysql_data_home() { return mysql_data_home; } #define mysql_data_home mysql_data_home_internal #include "../sql/mysqld.cc" #define SCRAMBLE_LENGTH 8 extern "C" { char * get_mysql_home(){ return mysql_home;}; char * get_mysql_real_data_home(){ return mysql_real_data_home;}; bool lib_dispatch_command(enum enum_server_command command, NET *net, const char *arg, ulong length) { THD *thd=(THD *) net->vio->dest_thd; thd->store_globals(); // Fix if more than one connect thd->net.last_error[0]=0; // Clear error message thd->net.last_errno=0; net_new_transaction(&thd->net); return dispatch_command(command, thd, (char *) arg, length + 1); } void lib_connection_phase(NET * net, int phase) { THD * thd; thd = (THD *)(net->vio->dest_thd); if (thd) { switch (phase) { case 2: check_connections2(thd); break; } } } } /* extern "C" */ void start_embedded_conn1(NET * net) { THD * thd = new THD; my_net_init(&thd->net,NULL); /* if (protocol_version>9) */ thd->net.return_errno=1; thd->thread_id = thread_id++; Vio * v = net->vio; if (!v) { v = vio_new(0,VIO_CLOSED,0); net->vio = v; } if (v) { v -> dest_thd = thd; /* v -> dest_net = &thd->net; XXX: Probably not needed? */ } thd->net.vio = v; if (thd->store_globals()) { fprintf(stderr,"store_globals failed.\n"); return; } thd->mysys_var=my_thread_var; thd->dbug_thread_id=my_thread_id(); thd->thread_stack= (char*) &thd; if (thd->max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; if (thd->options & OPTION_ANSI_MODE) thd->client_capabilities|=CLIENT_IGNORE_SPACE; thd->proc_info=0; // Remove 'login' thd->command=COM_SLEEP; thd->version=refresh_version; thd->set_time(); init_sql_alloc(&thd->mem_root,8192,8192); check_connections1(thd); } static int check_connections1(THD *thd) { uint connect_errors=0; NET *net= &thd->net; /* ** store the connection details */ DBUG_PRINT("info", (("check_connections called by thread %d"), thd->thread_id)); DBUG_PRINT("general",("New connection received on %s", vio_description(net->vio))); if (!thd->host) // If TCP/IP connection { thd->host=(char*) localhost; } else /* Hostname given means that the connection was on a socket */ { DBUG_PRINT("general",("Host: %s",thd->host)); thd->ip=0; bzero((char*) &thd->remote,sizeof(struct sockaddr)); } //vio_keepalive(net->vio, TRUE); /* nasty, but any other way? */ uint pkt_len = 0; char buff[80],*end; int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_TRANSACTIONS; LINT_INIT(pkt_len); end=strmov(buff,server_version)+1; int4store((uchar*) end,thd->thread_id); end+=4; memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1); end+=SCRAMBLE_LENGTH +1; int2store(end,client_flags); end[2]=MY_CHARSET_CURRENT; #define MIN_HANDSHAKE_SIZE 6 int2store(end+3,thd->server_status); bzero(end+5,13); end+=18; if (net_write_command(net,protocol_version, buff, (uint) (end-buff))) { inc_host_errors(&thd->remote.sin_addr); return(ER_HANDSHAKE_ERROR); } return 0; } static int check_connections2(THD * thd) { uint connect_errors=0; uint pkt_len = 0; NET * net = &thd -> net; if (protocol_version>9) net -> return_errno=1; if ( (pkt_len=my_net_read(net)) == packet_error || pkt_len < MIN_HANDSHAKE_SIZE) { inc_host_errors(&thd->remote.sin_addr); return(ER_HANDSHAKE_ERROR); } #ifdef _CUSTOMCONFIG_ #include "_cust_sql_parse.h" #endif if (connect_errors) reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(net_buffer_length)) return(ER_OUT_OF_RESOURCES); thd->client_capabilities=uint2korr(net->read_pos); thd->max_packet_length=uint3korr(net->read_pos+2); char *user= (char*) net->read_pos+5; char *passwd= strend(user)+1; char *db=0; if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH) return ER_HANDSHAKE_ERROR; if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) db=strend(passwd)+1; if (thd->client_capabilities & CLIENT_INTERACTIVE) thd->inactive_timeout=net_interactive_timeout; if (thd->client_capabilities & CLIENT_TRANSACTIONS) thd->net.return_status= &thd->server_status; net->timeout=net_read_timeout; if (check_user(thd,COM_CONNECT, user, passwd, db, 1)) return (-1); thd->password=test(passwd[0]); return 0; } static bool check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count) { NET *net= &thd->net; thd->db=0; if (!(thd->user = my_strdup(user, MYF(0)))) { send_error(net,ER_OUT_OF_RESOURCES); return 1; } thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, passwd, thd->scramble, &thd->priv_user, protocol_version == 9 || !(thd->client_capabilities & CLIENT_LONG_PASSWORD)); DBUG_PRINT("general", ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", thd->client_capabilities, thd->max_packet_length, thd->host ? thd->host : thd->ip, thd->priv_user, passwd[0] ? "yes": "no", thd->master_access, thd->db ? thd->db : "*none*")); if (thd->master_access & NO_ACCESS) { net_printf(net, ER_ACCESS_DENIED_ERROR, thd->user, thd->host ? thd->host : thd->ip, passwd[0] ? ER(ER_YES) : ER(ER_NO)); mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), thd->user, thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip", passwd[0] ? ER(ER_YES) : ER(ER_NO)); return(1); // Error already given } if (check_count) { VOID(pthread_mutex_lock(&LOCK_thread_count)); bool tmp=(thread_count - delayed_insert_threads >= max_connections && !(thd->master_access & PROCESS_ACL)); VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (tmp) { // Too many connections send_error(net, ER_CON_COUNT_ERROR); return(1); } } mysql_log.write(thd,command, (thd->priv_user == thd->user ? (char*) "%s@%s on %s" : (char*) "%s@%s as anonymous on %s"), user, thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip", db ? db : (char*) ""); thd->db_access=0; if (db && db[0]) return test(mysql_change_db(thd,db)); else send_ok(net); // Ready to handle questions return 0; // ok } extern "C"{ void mysql_server_init(int argc, const char **argv, const char **groups) { char hostname[FN_REFLEN]; /* This mess is to allow people to call the init function without * having to mess with a fake argv */ int *argcp; char ***argvp; int fake_argc = 1; char *fake_argv[] = { (char *)"", 0 }; const char *fake_groups[] = { "server", 0 }; if (argc) { argcp = &argc; argvp = (char***) &argv; } else { argcp = &fake_argc; argvp = (char ***) &fake_argv; } if (!groups) groups = fake_groups; my_umask=0660; // Default umask for new files my_umask_dir=0700; // Default umask for new directories MY_INIT((char *)"mysqld_server"); // init my_sys library & pthreads tzset(); // Set tzname start_time=time((time_t*) 0); #ifdef HAVE_TZNAME #if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) { struct tm tm_tmp; localtime_r(&start_time,&tm_tmp); strmov(time_zone,tzname[tm_tmp.tm_isdst == 1 ? 1 : 0]); } #else { struct tm *start_tm; start_tm=localtime(&start_time); strmov(time_zone=tzname[start_tm->tm_isdst == 1 ? 1 : 0]); } #endif #endif if (gethostname(hostname,sizeof(hostname)-4) < 0) strmov(hostname,"mysql"); strmov(pidfile_name,hostname); strmov(strcend(pidfile_name,'.'),".pid"); // Add extension #ifdef DEMO_VERSION strcat(server_version,"-demo"); #endif #ifdef SHAREWARE_VERSION strcat(server_version,"-shareware"); #endif #ifndef DBUG_OFF strcat(server_version,"-debug"); #endif strcat(server_version,"-library-ver"); #ifdef _CUSTOMSTARTUPCONFIG_ if (_cust_check_startup()) { /* _cust_check_startup will report startup failure error */ exit( 1 ); } #endif load_defaults("my", groups, argcp, argvp); defaults_argv=*argvp; mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */ #ifdef __WIN__ if (!mysql_tmpdir) mysql_tmpdir=getenv("TEMP"); if (!mysql_tmpdir) mysql_tmpdir=getenv("TMP"); #endif if (!mysql_tmpdir || !mysql_tmpdir[0]) mysql_tmpdir=strdup((char*) P_tmpdir); set_options(); get_options(*argcp, *argvp); if (opt_log || opt_update_log || opt_slow_log || opt_bin_log) strcat(server_version,"-log"); DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, server_version, SYSTEM_TYPE,MACHINE_TYPE)); /* These must be set early */ (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_binlog_update, MY_MUTEX_INIT_FAST); // QQ NOT USED (void) pthread_mutex_init(&LOCK_slave, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_server_id, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_refresh,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); (void) pthread_cond_init(&COND_flush_thread_cache,NULL); (void) pthread_cond_init(&COND_manager,NULL); (void) pthread_cond_init(&COND_binlog_update, NULL); (void) pthread_cond_init(&COND_slave_stopped, NULL); (void) pthread_cond_init(&COND_slave_start, NULL); if (set_default_charset_by_name(default_charset, MYF(MY_WME))) unireg_abort(1); charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS)); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),CONNECT_PRIOR); /* Parameter for threads created for connections */ (void) pthread_attr_init(&connection_attrib); (void) pthread_attr_setdetachstate(&connection_attrib, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&connection_attrib,thread_stack); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR); pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM); #ifdef SET_RLIMIT_NOFILE /* connections and databases neads lots of files */ { uint wanted_files=10+(uint) max(max_connections*5, max_connections+table_cache_size*2); uint files=set_maximum_open_files(wanted_files); if (files && files < wanted_files) // Some systems return 0 { max_connections= (ulong) min((files-10),max_connections); table_cache_size= (ulong) max((files-10-max_connections)/2,64); DBUG_PRINT("warning", ("Changed limits: max_connections: %ld table_cache: %ld", max_connections,table_cache_size)); sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size); } } #endif unireg_init(opt_specialflag); /* Set up extern variabels */ init_errmessage(); /* Read error messages from file */ lex_init(); item_init(); mysys_uses_curses=0; #ifdef USE_REGEX regex_init(); #endif select_thread=pthread_self(); select_thread_in_use=1; /* ** We have enough space for fiddling with the argv, continue */ umask(((~my_umask) & 0666)); // strcpy(mysql_real_data_home, "/usr/local"); //if (my_setwd(mysql_real_data_home,MYF(MY_WME))) //{ // unireg_abort(1); /* purecov: inspected */ //} //mysql_data_home[0]=FN_CURLIB; // all paths are relative from here //mysql_data_home[1]=0; strcpy(get_mysql_data_home(), mysql_real_data_home); //server_init(); table_cache_init(); hostname_cache_init(); sql_cache_init(); randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); reset_floating_point_exceptions(); init_thr_lock(); /* Setup log files */ if (opt_log) open_log(&mysql_log, hostname, opt_logname, ".log", LOG_NORMAL); if (opt_update_log) open_log(&mysql_update_log, hostname, opt_update_logname, "", LOG_NEW); if (opt_bin_log) { if(server_id) { if (!opt_bin_logname) { char tmp[FN_REFLEN]; strnmov(tmp,hostname,FN_REFLEN-5); strmov(strcend(tmp,'.'),"-bin"); opt_bin_logname=my_strdup(tmp,MYF(MY_WME)); } mysql_bin_log.set_index_file_name(opt_binlog_index_name); open_log(&mysql_bin_log, hostname, opt_bin_logname, "-bin", LOG_BIN); } else sql_print_error("Server id is not set - binary logging disabled"); } if (opt_slow_log) open_log(&mysql_slow_log, hostname, opt_slow_logname, "-slow.log", LOG_NORMAL); if (ha_init()) { sql_print_error("Can't init databases"); exit(1); } #ifdef HAVE_MLOCKALL if (locked_in_memory && !geteuid()) { ha_key_cache(); if (mlockall(MCL_CURRENT)) { sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno); } else locked_in_memory=1; } #else locked_in_memory=0; #endif if (opt_myisam_log) (void) mi_log( 1 ); ft_init_stopwords(ft_precompiled_stopwords); /* SerG */ /* init signals & alarm After this we can't quit by a simple unireg_abort */ error_handler_hook = my_message_sql; if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) || pthread_key_create(&THR_MALLOC,NULL)) { sql_print_error("Can't create thread-keys"); exit(1); } //init_signals(); opt_noacl = 1; if (acl_init(opt_noacl)) { select_thread_in_use=0; (void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL); exit(1); } if (!opt_noacl) (void) grant_init(); #ifdef HAVE_DLOPEN if (!opt_noacl) udf_init(); #endif if (opt_bootstrap) { int error=bootstrap(stdin); end_thr_alarm(); // Don't allow alarms unireg_abort(error ? 1 : 0); } if (opt_init_file) { if (read_init_file(opt_init_file)) { end_thr_alarm(); // Don't allow alarms unireg_abort(1); } } (void) thr_setconcurrency(concurrency); // 10 by default if (flush_time && flush_time != ~(ulong) 0L) { pthread_t hThread; if (pthread_create(&hThread,&connection_attrib,handle_manager,0)) sql_print_error("Warning: Can't create thread to manage maintenance"); } // slave thread if(master_host) { if(server_id) { pthread_t hThread; if(!opt_skip_slave_start && pthread_create(&hThread, &connection_attrib, handle_slave, 0)) sql_print_error("Warning: Can't create thread to handle slave"); } else sql_print_error("Server id is not set, slave thread will not be started"); } //printf(ER(ER_READY),my_progname,server_version,""); //printf("%s initialized.\n", server_version); fflush(stdout); } void mysql_server_end() { /* (void) pthread_attr_destroy(&connection_attrib); */ DBUG_PRINT("quit",("Exiting main thread")); #ifdef EXTRA_DEBUG sql_print_error("Before Lock_thread_count"); #endif (void) pthread_mutex_lock(&LOCK_thread_count); select_thread_in_use=0; // For close_connections (void) pthread_cond_broadcast(&COND_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count); #ifdef EXTRA_DEBUG sql_print_error("After lock_thread_count"); #endif // /* Wait until cleanup is done */ // (void) pthread_mutex_lock(&LOCK_thread_count); // while (!ready_to_exit) // { // pthread_cond_wait(&COND_thread_count,&LOCK_thread_count); // } // (void) pthread_mutex_unlock(&LOCK_thread_count); unireg_end(0); my_thread_end(); } my_bool mysql_thread_init() { #ifdef THREAD return my_thread_init(); #else return 0; #endif } void mysql_thread_end() { #ifdef THREAD my_thread_end(); #endif } void start_embedded_connection(NET * net) { start_embedded_conn1(net); } } /* extern "C" */ int embedded_do_command(NET * net) { THD * thd = (THD *) net ->vio; do_command(thd); return 0; }