MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LocalConfig.cpp
1 /*
2  Copyright (c) 2003, 2010, 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 #include "LocalConfig.hpp"
19 #include <NdbEnv.h>
20 #include <NdbConfig.h>
21 #include <NdbAutoPtr.hpp>
22 #include <util/NdbOut.hpp>
23 
24 #define _STR_VALUE(x) #x
25 #define STR_VALUE(x) _STR_VALUE(x)
26 
27 LocalConfig::LocalConfig(){
28  error_line = 0; error_msg[0] = 0;
29  _ownNodeId= 0;
30  bind_address_port= 0;
31 }
32 
33 bool
34 LocalConfig::init(const char *connectString,
35  const char *fileName)
36 {
47  _ownNodeId= 0;
48 
49  //1. Check connectString
50  if(connectString != 0 && connectString[0] != 0){
51  if(readConnectString(connectString, "connect string")){
52  if (ids.size())
53  return true;
54  // only nodeid given, continue to find hosts
55  } else
56  return false;
57  }
58 
59  //2. Check given filename
60  if (fileName && strlen(fileName) > 0) {
61  bool fopenError;
62  if(readFile(fileName, fopenError)){
63  return true;
64  }
65  return false;
66  }
67 
68  //3. Check environment variable
69  char buf[255];
70  if(NdbEnv_GetEnv("NDB_CONNECTSTRING", buf, sizeof(buf)) &&
71  strlen(buf) != 0){
72  if(readConnectString(buf, "NDB_CONNECTSTRING")){
73  return true;
74  }
75  return false;
76  }
77 
78  //4. Check Ndb.cfg in NDB_HOME
79  {
80  bool fopenError;
81  char *buf2= NdbConfig_NdbCfgName(1 /*true*/);
82  NdbAutoPtr<char> tmp_aptr(buf2);
83  if(readFile(buf2, fopenError))
84  return true;
85  if (!fopenError)
86  return false;
87  }
88 
89  //5. Check Ndb.cfg in cwd
90  {
91  bool fopenError;
92  char *buf2= NdbConfig_NdbCfgName(0 /*false*/);
93  NdbAutoPtr<char> tmp_aptr(buf2);
94  if(readFile(buf2, fopenError))
95  return true;
96  if (!fopenError)
97  return false;
98  }
99 
100  //7. Use default connect string
101  {
102  if(readConnectString("host=localhost:" STR_VALUE(NDB_PORT),
103  "default connect string"))
104  return true;
105  }
106 
107  setError(0, "");
108 
109  return false;
110 }
111 
112 LocalConfig::~LocalConfig(){
113 }
114 
115 void LocalConfig::setError(int lineNumber, const char * _msg) {
116  error_line = lineNumber;
117  strncpy(error_msg, _msg, sizeof(error_msg));
118 }
119 
120 void LocalConfig::printError() const {
121  ndbout << "Configuration error" << endl;
122  if (error_line)
123  ndbout << "Line: "<< error_line << ", ";
124  ndbout << error_msg << endl << endl;
125 }
126 
127 void LocalConfig::printUsage() const {
128  ndbout << "This node needs information on how to connect"<<endl
129  << "to the NDB Management Server."<<endl
130  << "The information can be supplied in one of the following ways:"
131  << endl;
132 
133  ndbout << "1. Put a Ndb.cfg file in the directory where you start"<<endl
134  << " the node. "<< endl
135  << " Ex: Ndb.cfg" << endl
136  << " | host=localhost:"<<NDB_PORT<<endl;
137 
138  ndbout << "2. Use the environment variable NDB_CONNECTSTRING to "<<endl
139  << " provide this information." <<endl
140  << " Ex: " << endl
141  << " >export NDB_CONNECTSTRING=\"host=localhost:"<<NDB_PORT<<"\""
142  <<endl<<endl;
143 }
144 
145 const char *nodeIdTokens[] = {
146  "OwnProcessId %i",
147  "nodeid=%i",
148  0
149 };
150 
151 const char *hostNameTokens[] = {
152  "host://%[^:]:%i",
153  "host=%[^:]:%i",
154  "mgmd=%[^:]:%i",
155  "%[^:^=^ ]:%i",
156  "%s %i",
157  0
158 };
159 
160 const char *bindAddressTokens[] = {
161  "bind-address=%[^:]:%i",
162  0
163 };
164 
165 const char *fileNameTokens[] = {
166  "file://%s",
167  "file=%s",
168  0
169 };
170 
171 bool
172 LocalConfig::parseNodeId(const char * buf){
173  for(int i = 0; nodeIdTokens[i] != 0; i++)
174  if (sscanf(buf, nodeIdTokens[i], &_ownNodeId) == 1)
175  return true;
176  return false;
177 }
178 
179 bool
180 LocalConfig::parseHostName(const char * buf){
181  char tempString[1024];
182  char tempString2[1024];
183  int port;
184  do {
185  for(int i = 0; hostNameTokens[i] != 0; i++) {
186  if (sscanf(buf, hostNameTokens[i], tempString, &port) == 2) {
187  MgmtSrvrId mgmtSrvrId;
188  mgmtSrvrId.type = MgmId_TCP;
189  mgmtSrvrId.name.assign(tempString);
190  mgmtSrvrId.port = port;
191  /* assign default bind_address if available */
192  if (bind_address.length())
193  mgmtSrvrId.bind_address.assign(bind_address);
194  mgmtSrvrId.bind_address_port = bind_address_port;
195  ids.push_back(mgmtSrvrId);
196  return true;
197  }
198  }
199  if (buf == tempString2)
200  break;
201  // try to add default port to see if it works
202  BaseString::snprintf(tempString2, sizeof(tempString2),
203  "%s:%d", buf, NDB_PORT);
204  buf= tempString2;
205  } while(1);
206  return false;
207 }
208 
209 bool
210 LocalConfig::parseBindAddress(const char * buf)
211 {
212  char tempString[1024];
213  char tempString2[1024];
214  int port;
215  do
216  {
217  for(int i = 0; bindAddressTokens[i] != 0; i++)
218  {
219  if (sscanf(buf, bindAddressTokens[i], tempString, &port) == 2)
220  {
221  if (ids.size() == 0)
222  {
223  /* assign default bind_address */
224  bind_address.assign(tempString);
225  bind_address_port = port;
226  return true;
227  }
228  /* override bind_address on latest mgmd */
229  MgmtSrvrId &mgmtSrvrId= ids[ids.size()-1];
230  mgmtSrvrId.bind_address.assign(tempString);
231  mgmtSrvrId.bind_address_port = port;
232  return true;
233  }
234  }
235  if (buf == tempString2)
236  break;
237  // try to add port 0 to see if it works
238  BaseString::snprintf(tempString2, sizeof(tempString2),"%s:0", buf);
239  buf= tempString2;
240  } while(1);
241  return false;
242 }
243 
244 bool
245 LocalConfig::parseFileName(const char * buf){
246  char tempString[1024];
247  for(int i = 0; fileNameTokens[i] != 0; i++) {
248  if (sscanf(buf, fileNameTokens[i], tempString) == 1) {
249  MgmtSrvrId mgmtSrvrId;
250  mgmtSrvrId.type = MgmId_File;
251  mgmtSrvrId.name.assign(tempString);
252  ids.push_back(mgmtSrvrId);
253  return true;
254  }
255  }
256  return false;
257 }
258 
259 bool
260 LocalConfig::parseString(const char * connectString, BaseString &err){
261  char * for_strtok;
262  char * copy = strdup(connectString);
263  NdbAutoPtr<char> tmp_aptr(copy);
264 
265  for (char *tok = strtok_r(copy,";,",&for_strtok); tok != 0;
266  tok = strtok_r(NULL, ";,", &for_strtok)) {
267  if (tok[0] == '#') continue;
268 
269  if (!_ownNodeId) // only one nodeid definition allowed
270  if (parseNodeId(tok))
271  continue;
272  if (parseHostName(tok))
273  continue;
274  if (parseBindAddress(tok))
275  continue;
276  if (parseFileName(tok))
277  continue;
278 
279  err.assfmt("Unexpected entry: \"%s\"", tok);
280  return false;
281  }
282  bind_address_port= 0;
283  bind_address.assign("");
284  return true;
285 }
286 
287 bool LocalConfig::readFile(const char * filename, bool &fopenError)
288 {
289  char line[1024];
290 
291  fopenError = false;
292 
293  FILE * file = fopen(filename, "r");
294  if(file == 0){
295  BaseString::snprintf(line, sizeof(line),
296  "Unable to open local config file: %s", filename);
297  setError(0, line);
298  fopenError = true;
299  return false;
300  }
301 
302  BaseString theString;
303 
304  while(fgets(line, sizeof(line), file)){
305  BaseString tmp(line);
306  tmp.trim(" \t\n\r");
307  if(tmp.length() > 0 && tmp.c_str()[0] != '#'){
308  theString.append(tmp);
309  break;
310  }
311  }
312  while (fgets(line, sizeof(line), file)) {
313  BaseString tmp(line);
314  tmp.trim(" \t\n\r");
315  if(tmp.length() > 0 && tmp.c_str()[0] != '#'){
316  theString.append(";");
317  theString.append(tmp);
318  }
319  }
320 
321  BaseString err;
322  bool return_value = parseString(theString.c_str(), err);
323 
324  if (!return_value) {
325  BaseString tmp;
326  tmp.assfmt("Reading %s: %s", filename, err.c_str());
327  setError(0, tmp.c_str());
328  }
329 
330  fclose(file);
331  return return_value;
332 }
333 
334 bool
335 LocalConfig::readConnectString(const char * connectString,
336  const char * info){
337  BaseString err;
338  bool return_value = parseString(connectString, err);
339  if (!return_value) {
340  BaseString err2;
341  err2.assfmt("Reading %s \"%s\": %s", info, connectString, err.c_str());
342  setError(0,err2.c_str());
343  }
344  return return_value;
345 }
346 
347 char *
348 LocalConfig::makeConnectString(char *buf, int sz)
349 {
350  int p= BaseString::snprintf(buf,sz,"nodeid=%d", _ownNodeId);
351  if (p < sz && bind_address.length())
352  {
353  int new_p= p+BaseString::snprintf(buf+p,sz-p,",bind-address=%s:%d",
354  bind_address.c_str(), bind_address_port);
355  if (new_p < sz)
356  p= new_p;
357  else
358  buf[p]= 0;
359  }
360  if (p < sz)
361  for (unsigned i = 0; i < ids.size(); i++)
362  {
363  if (ids[i].type != MgmId_TCP)
364  continue;
365  int new_p= p+BaseString::snprintf(buf+p,sz-p,",%s:%d",
366  ids[i].name.c_str(), ids[i].port);
367  if (new_p < sz)
368  p= new_p;
369  else
370  {
371  buf[p]= 0;
372  break;
373  }
374  if (!bind_address.length() && ids[i].bind_address.length())
375  {
376  new_p= p+BaseString::snprintf(buf+p,sz-p,",bind-address=%s:%d",
377  ids[i].bind_address.c_str(), ids[i].bind_address_port);
378  if (new_p < sz)
379  p= new_p;
380  else
381  {
382  buf[p]= 0;
383  break;
384  }
385  }
386  }
387  buf[sz-1]=0;
388  return buf;
389 }
390 
391 template class Vector<MgmtSrvrId>;