1 /*
2 Copyright (c) 2001, 2011, Oracle and/or its affiliates.
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-1335 USA */
16
17 /**
18 @file
19
20 All of the functions defined in this file which are not used (the ones to
21 handle failsafe) are not used; their code has not been updated for more
22 than one year now so should be considered as BADLY BROKEN. Do not enable
23 it. The used functions (to handle LOAD DATA FROM MASTER, plus some small
24 functions like register_slave()) are working.
25 */
26
27 #include "mariadb.h"
28 #include "sql_priv.h"
29 #include "sql_parse.h" // check_access
30 #ifdef HAVE_REPLICATION
31
32 #include "repl_failsafe.h"
33 #include "sql_acl.h" // REPL_SLAVE_ACL
34 #include "sql_repl.h"
35 #include "slave.h"
36 #include "rpl_mi.h"
37 #include "rpl_filter.h"
38 #include "log_event.h"
39 #include <mysql.h>
40
41
42 struct Slave_info
43 {
44 uint32 server_id;
45 uint32 master_id;
46 char host[HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1];
47 char user[USERNAME_LENGTH+1];
48 char password[MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1];
49 uint16 port;
50 };
51
52
53 Atomic_counter<uint32_t> binlog_dump_thread_count;
54 ulong rpl_status=RPL_NULL;
55 mysql_mutex_t LOCK_rpl_status;
56
57 const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
58 TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
59 rpl_role_type, NULL};
60
61 const char* rpl_status_type[]=
62 {
63 "AUTH_MASTER","IDLE_SLAVE","ACTIVE_SLAVE","LOST_SOLDIER","TROOP_SOLDIER",
64 "RECOVERY_CAPTAIN","NULL",NullS
65 };
66
67 /*
68 All of the functions defined in this file which are not used (the ones to
69 handle failsafe) are not used; their code has not been updated for more than
70 one year now so should be considered as BADLY BROKEN. Do not enable it.
71 The used functions (to handle LOAD DATA FROM MASTER, plus some small
72 functions like register_slave()) are working.
73 */
74
change_rpl_status(ulong from_status,ulong to_status)75 void change_rpl_status(ulong from_status, ulong to_status)
76 {
77 mysql_mutex_lock(&LOCK_rpl_status);
78 if (rpl_status == from_status || rpl_status == RPL_ANY)
79 rpl_status = to_status;
80 mysql_mutex_unlock(&LOCK_rpl_status);
81 }
82
83
84 #define get_object(p, obj, msg) \
85 {\
86 uint len = (uint)*p++; \
87 if (p + len > p_end || len >= sizeof(obj)) \
88 {\
89 errmsg= msg;\
90 goto err; \
91 }\
92 ::strmake(obj, (char*) p, len); \
93 p+= len; \
94 }\
95
96
unregister_slave()97 void THD::unregister_slave()
98 {
99 if (auto old_si= slave_info)
100 {
101 mysql_mutex_lock(&LOCK_thd_data);
102 slave_info= 0;
103 mysql_mutex_unlock(&LOCK_thd_data);
104 my_free(old_si);
105 binlog_dump_thread_count--;
106 }
107 }
108
109
110 /**
111 Register slave
112
113 @return
114 0 ok
115 @return
116 1 Error. Error message sent to client
117 */
118
register_slave(uchar * packet,size_t packet_length)119 int THD::register_slave(uchar *packet, size_t packet_length)
120 {
121 Slave_info *si;
122 uchar *p= packet, *p_end= packet + packet_length;
123 const char *errmsg= "Wrong parameters to function register_slave";
124
125 if (check_access(this, PRIV_COM_REGISTER_SLAVE, any_db, NULL, NULL, 0, 0))
126 return 1;
127 if (!(si= (Slave_info*)my_malloc(key_memory_SLAVE_INFO, sizeof(Slave_info),
128 MYF(MY_WME))))
129 return 1;
130
131 variables.server_id= si->server_id= uint4korr(p);
132 p+= 4;
133 get_object(p,si->host, "Failed to register slave: too long 'report-host'");
134 get_object(p,si->user, "Failed to register slave: too long 'report-user'");
135 get_object(p,si->password, "Failed to register slave; too long 'report-password'");
136 if (p+10 > p_end)
137 goto err;
138 si->port= uint2korr(p);
139 p += 2;
140 /*
141 We need to by pass the bytes used in the fake rpl_recovery_rank
142 variable. It was removed in patch for BUG#13963. But this would
143 make a server with that patch unable to connect to an old master.
144 See: BUG#49259
145 */
146 // si->rpl_recovery_rank= uint4korr(p);
147 p += 4;
148 if (!(si->master_id= uint4korr(p)))
149 si->master_id= global_system_variables.server_id;
150
151 if (!*si->host)
152 ::strmake(si->host, main_security_ctx.host_or_ip, sizeof(si->host));
153
154 unregister_slave();
155 mysql_mutex_lock(&LOCK_thd_data);
156 slave_info= si;
157 mysql_mutex_unlock(&LOCK_thd_data);
158 binlog_dump_thread_count++;
159 return 0;
160
161 err:
162 delete si;
163 my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
164 return 1;
165 }
166
167
is_binlog_dump_thread()168 bool THD::is_binlog_dump_thread()
169 {
170 mysql_mutex_lock(&LOCK_thd_data);
171 bool res= slave_info != NULL;
172 mysql_mutex_unlock(&LOCK_thd_data);
173
174 return res;
175 }
176
177
show_slave_hosts_callback(THD * thd,Protocol * protocol)178 static my_bool show_slave_hosts_callback(THD *thd, Protocol *protocol)
179 {
180 my_bool res= FALSE;
181 mysql_mutex_lock(&thd->LOCK_thd_data);
182 if (auto si= thd->slave_info)
183 {
184 protocol->prepare_for_resend();
185 protocol->store(si->server_id);
186 protocol->store(si->host, &my_charset_bin);
187 if (opt_show_slave_auth_info)
188 {
189 protocol->store(si->user, &my_charset_bin);
190 protocol->store(si->password, &my_charset_bin);
191 }
192 protocol->store((uint32) si->port);
193 protocol->store(si->master_id);
194 res= protocol->write();
195 }
196 mysql_mutex_unlock(&thd->LOCK_thd_data);
197 return res;
198 }
199
200
201 /**
202 Execute a SHOW SLAVE HOSTS statement.
203
204 @param thd Pointer to THD object for the client thread executing the
205 statement.
206
207 @retval FALSE success
208 @retval TRUE failure
209 */
show_slave_hosts(THD * thd)210 bool show_slave_hosts(THD* thd)
211 {
212 List<Item> field_list;
213 Protocol *protocol= thd->protocol;
214 MEM_ROOT *mem_root= thd->mem_root;
215 DBUG_ENTER("show_slave_hosts");
216
217 field_list.push_back(new (mem_root)
218 Item_return_int(thd, "Server_id", 10,
219 MYSQL_TYPE_LONG),
220 thd->mem_root);
221 field_list.push_back(new (mem_root)
222 Item_empty_string(thd, "Host", 20),
223 thd->mem_root);
224 if (opt_show_slave_auth_info)
225 {
226 field_list.push_back(new (mem_root) Item_empty_string(thd, "User", 20),
227 thd->mem_root);
228 field_list.push_back(new (mem_root) Item_empty_string(thd, "Password", 20),
229 thd->mem_root);
230 }
231 field_list.push_back(new (mem_root)
232 Item_return_int(thd, "Port", 7, MYSQL_TYPE_LONG),
233 thd->mem_root);
234 field_list.push_back(new (mem_root)
235 Item_return_int(thd, "Master_id", 10, MYSQL_TYPE_LONG),
236 thd->mem_root);
237
238 if (protocol->send_result_set_metadata(&field_list,
239 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
240 DBUG_RETURN(TRUE);
241
242 if (server_threads.iterate(show_slave_hosts_callback, protocol))
243 DBUG_RETURN(true);
244
245 my_eof(thd);
246 DBUG_RETURN(FALSE);
247 }
248
249 #endif /* HAVE_REPLICATION */
250
251